==============================================================================
+helpers/external_acl/kerberos_ldap_group/support_ldap.cc
+
+/* get_attributes is partly from OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2009 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
- ... and a great many testing improvements
- ... and many documentation updates
+Changes to squid-3.1.7 (23 Aug 2010):
+
+ - Regression Bug 3021: Large DNS reply causes crash
+ - Regression Bug 3011: ICAP, HTTPS, cache_peer probe IPv4-only port fixes
+ - Regression Bug 2997: visible_hostname directive no longer matches docs
+ - Bug 3012: deprecate sslBump and support ssl-bump spelling in http_port
+ - Bug 3006: handle IPV6_V6ONLY definition missing
+ - Bug 3004: Solaris 9 SunStudio 12 build failure
+ - Bug 3003: inconsistent concepts in documentation of cache_dir
+ - Bug 3001: dnsserver link issues
+ - HTTP/1.1: default keep-alive for 1.1 clients (bug 3016)
+ - HTTP/1.1: Improved Range header field validation
+ - HTTP/1.1: Forward multiple unknown Cache-Control directives
+ - HTTP/1.1: Stop sending Proxy-Connection header
+ - Fix 32-bit wrap in refresh_pattern min/max values
+ - ... and several documentation corrections.
+
Changes to squid-3.1.6 (02 Aug 2010):
- Bug 2994, 2995: IPv4-only regressions
# options
# They are (with their GCC equivalent):
# squid_cv_cc_option_werror (-Werror)
+# squid_cv_cxx_option_werror (-Werror)
# squid_cv_cc_option_wall (-Wall)
# squid_cv_cc_option_optimize (-O3)
#
case "$squid_cv_compiler" in
gcc)
squid_cv_cc_option_werror="-Werror"
+ squid_cv_cxx_option_werror="-Werror"
squid_cv_cc_option_wall="-Wall"
squid_cv_cc_option_optimize="-O3"
squid_cv_cc_arg_pipe="-pipe"
;;
sunstudio)
- squid_cv_cc_option_werror="-errwarn=%all"
+ squid_cv_cc_option_werror="-errwarn=%all -errtags"
+ squid_cv_cxx_option_werror="-errwarn=%all,no%badargtype2w,no%wbadinit,no%wbadasg -errtags"
squid_cv_cc_option_wall="+w"
squid_cv_cc_option_optimize="-fast"
squid_cv_cc_arg_pipe=""
;;
*)
+ squid_cv_cxx_option_werror=""
squid_cv_cc_option_werror=""
squid_cv_cc_option_wall=""
squid_cv_cc_option_optimize="-O"
AC_DEFUN([SQUID_CHECK_WORKING_GSSAPI], [
AC_CACHE_CHECK([for working gssapi], squid_cv_working_gssapi, [
AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#ifdef HAVE_HEIMDAL_KERBEROS
#ifdef HAVE_GSSAPI_GSSAPI_H
#include <gssapi/gssapi.h>
-#elif HAVE_GSSAPI_H
+#elif defined(HAVE_GSSAPI_H)
#include <gssapi.h>
#endif
-
-#ifdef HAVE_GSSAPI_GSSAPI_EXT_H
-#include <gssapi/gssapi_ext.h>
+#else
+#ifdef HAVE_GSSAPI_GSSAPI_H
+#include <gssapi/gssapi.h>
+#elif defined(HAVE_GSSAPI_H)
+#include <gssapi.h>
#endif
-
#ifdef HAVE_GSSAPI_GSSAPI_KRB5_H
#include <gssapi/gssapi_krb5.h>
#endif
-
#ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H
#include <gssapi/gssapi_generic.h>
#endif
+#endif
int
main(void)
{
## Special Universal .h dependency test script
## aborts if error encountered
testHeaders: $(srcdir)/*.h $(srcdir)/os/*.h
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(srcdir)" || exit 1
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(srcdir)/os" || exit 1
+ $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" $^ || exit 1
CLEANFILES += testHeaders
#include "compat/osdetect.h"
/* ugly hack. But we need to set this REALLY soon in the header */
-#if _SQUID_SOLARIS_
+#if _SQUID_SOLARIS_ && !defined(__GNUC__) && !defined(__GNUG__)
+#ifndef __EXTENSIONS__
+#define __EXTENSIONS__ 1
+#endif
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 1
#endif
#endif /* wcsstr */
#define wcsstr wcswcs
-/*
- * we need some standard-based extensions
- */
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 1
-#endif
-#ifndef _XOPEN_SOURCE_EXTENDED
-#define _XOPEN_SOURCE_EXTENDED 1
-#endif
-
-
/*
* On Solaris 9 x86, gcc may includes a "fixed" set of old system
* include files that is incompatible with the updated Solaris
#endif
#endif
+#ifndef PRIX64
+#ifdef _SQUID_MSWIN_ /* Windows native port using MSVCRT */
+#define PRIX64 "I64X"
+#elif SIZEOF_INT64_T > SIZEOF_LONG
+#define PRIX64 "llX"
+#else
+#define PRIX64 "lX"
+#endif
+#endif
+
#ifndef HAVE_MODE_T
typedef unsigned short mode_t;
#endif
# this needs to be before any test is run, to have more standard
# functions available on some Unix sysems (e.g. Solaris)
-AC_USE_SYSTEM_EXTENSIONS
+if test "x$squid_host_os" = "solaris" -a "x$GCC" != "x" ; then
+ AC_USE_SYSTEM_EXTENSIONS
+fi
AC_ARG_ENABLE(strict-error-checking,
AS_HELP_STRING([--disable-strict-error-checking],[By default squid is compiled
)
AC_SUBST(DEFAULT_LOG_DIR)
-DEFAULT_PIDFILE="$localstatedir/run/squid.pid"
+DEFAULT_PID_FILE="$localstatedir/run/squid.pid"
AC_ARG_WITH(pidfile,
AS_HELP_STRING([--with-pidfile=PATH],
[Default location for squid pid file. Default: PREFIX/var/run/squid.pid]), [
AC_MSG_ERROR( --with-pidfile requires a file PATH. --with-pidfile=PATH )
;;
*)
- DEFAULT_PIDFILE="$withval"
+ DEFAULT_PID_FILE="$withval"
;;
esac
])
-AC_SUBST(DEFAULT_PIDFILE)
+AC_SUBST(DEFAULT_PID_FILE)
if test "x$GCC" = "xyes"; then
GCCVER=`$CC -v 2>&1 | awk '$2 == "version" {print $3}'`
if test "x$enable_strict_error_checking" != "xno"; then
SQUID_CFLAGS="$SQUID_CFLAGS $squid_cv_cc_option_werror"
- SQUID_CXXFLAGS="$SQUID_CXXFLAGS $squid_cv_cc_option_werror"
+ SQUID_CXXFLAGS="$SQUID_CXXFLAGS $squid_cv_cxx_option_werror"
fi
AC_SUBST(SQUID_CFLAGS)
SQUID_CXXFLAGS="$SQUID_CXXFLAGS $squid_cv_cc_arg_pipe"
SQUID_CFLAGS="$SQUID_CFLAGS $squid_cv_cc_arg_pipe"
-enable_inline="yes"
AC_ARG_ENABLE(optimizations,
AS_HELP_STRING([--disable-optimizations],
[Do not compile Squid with compiler optimizations enabled.
SQUID_YESNO([$enableval],
[Unrecognized argument to --disable-inline: $enableval])
])
-AC_MSG_NOTICE([inlining optimizations enabled: $enable_inline])
+AC_MSG_NOTICE([inlining optimizations enabled: ${enable_inline:=yes}])
SQUID_DEFINE_BOOL(_USE_INLINE_,$enable_inline,
[Include inline methods into header file])
# to be used by sub-commands
CXXFLAGS="`getconf ${buildmodel}_CFLAGS` $CXXFLAGS"
LIBS="`getconf ${buildmodel}_LIBS` $LIBS"
LDFLAGS="`getconf ${buildmodel}_LDFLAGS` $LDFLAGS"
- if "$squid_host_os" = "solaris" ; then
+ if test "x$squid_host_os" = "xsolaris" ; then
# On Solaris getconf returns for CFLAGS -xarch=generic64, -Xa and -Usun options, and
# for LDFLAGS -xarch=generic64, but:
AC_ARG_ENABLE(default-hostsfile,
AS_HELP_STRING([--enable-default-hostsfile=path],
[Select default location for hosts file.
- See hosts_file directive in squid.conf for details]),
-[
- if test "x$enableval" != "xnone" -a "x$enableval" != "xno" ; then
- if test -f "$enableval"; then
- OPT_DEFAULT_HOSTS=$enableval
- else
- AC_MSG_WARN([Unable to find $enableval])
- fi
- else
- OPT_DEFAULT_HOSTS="none"
+ See hosts_file directive in squid.conf for details]), [
+if test "x$enableval" != "xnone" -a "x$enableval" != "xno" ; then
+ if test \! -f "$enableval"; then
+ AC_MSG_WARN([Unable to find file $enableval. I hope you know what you are doing.])
fi
- AC_MSG_NOTICE([Default hosts file set to: $enableval])
-],[OPT_DEFAULT_HOSTS="/etc/hosts"])
-AC_SUBST(OPT_DEFAULT_HOSTS)
+ squid_opt_default_hosts=$enableval
+else
+ squid_opt_default_hosts="none"
+fi
+])
+AC_MSG_NOTICE([Default hosts file set to: ${squid_opt_default_hosts:=/etc/hosts}])
+DEFAULT_HOSTS=$squid_opt_default_hosts
+AC_SUBST(DEFAULT_HOSTS)
# Select auth schemes modules to build
AC_ARG_ENABLE(auth,
AC_CHECK_HEADERS(gssapi/gssapi_generic.h)
AC_CHECK_HEADERS(profile.h)
fi
- AC_CHECK_HEADERS(krb5.h com_err.h et/com_err.h)
SQUID_CHECK_KRB5_SOLARIS_BROKEN_KRB5_H
if test "x$squid_cv_broken_krb5_h" = "xyes"; then
- AC_DEFINE(HAVE_BROKEN_SOLARIS_KRB5_H, 1, [Define to 1 if krb5.h is broken for C++])
+ AC_DEFINE(HAVE_BROKEN_SOLARIS_KRB5_H, 1, [Define to 1 if krb5.h is broken for C++])
+ AC_MSG_WARN([You have a broken Solaris <krb5.h> system include.])
+ AC_MSG_WARN([Please see http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6837512])
+ AC_MSG_WARN([If you need Kerberos support you'll have to patch])
+ AC_MSG_WARN([your system. See contrib/solaris/solaris-krb5-include.patch])
fi
+ AC_CHECK_HEADERS(krb5.h com_err.h et/com_err.h)
ac_com_error_message=no
if test "x$ac_cv_header_com_err_h" == "xyes" ; then
AC_CHECK_LIB(krb5,krb5_get_error_message,
AC_DEFINE(HAVE_KRB5_GET_ERROR_MESSAGE,1,
[Define to 1 if you have krb5_get_error_message]),)
+ AC_CHECK_DECLS(krb5_kt_free_entry,,,[#include <krb5.h>])
AC_CHECK_LIB(krb5,krb5_kt_free_entry,
AC_DEFINE(HAVE_KRB5_KT_FREE_ENTRY,1,
[Define to 1 if you have krb5_kt_free_entry]),)
dir="$srcdir/helpers/external_acl/$helper"
if test -f "$dir/config.test" && sh "$dir/config.test" "$@"; then
EXTERNAL_ACL_HELPERS="$EXTERNAL_ACL_HELPERS $helper"
+ # special case
+ if test "x$helper" = "xkerberos_ldap_group" ; then
+ squid_require_sasl=yes
+ fi
else
AC_MSG_NOTICE([external acl helper $helper ... found but cannot be built])
fi
AC_MSG_ERROR(Neither SASL nor SASL2 found)
])
])
+ case "$host_os" in
+ Darwin)
+ if test "$ac_cv_lib_sasl2_sasl_errstring" = "yes" ; then
+ AC_DEFINE(HAVE_SASL_DARWIN,1,[Define to 1 if Mac Darwin without sasl.h])
+ echo "checking for MAC Darwin without sasl.h ... yes"
+ else
+ echo "checking for MAC Darwin without sasl.h ... no"
+ fi
+ ;;
+ esac
AC_SUBST(LIBSASL)
fi
regex.h \
sched.h \
security/pam_appl.h \
+ siginfo.h \
signal.h \
sstream \
stdarg.h \
sys/md5.h \
sys/msg.h \
sys/resource.h \
- sys/select.h\
+ sys/select.h \
sys/socket.h \
sys/stat.h \
sys/statvfs.h \
AC_TYPE_SSIZE_T
AC_TYPE_OFF_T
AC_TYPE_UID_T
+AC_CHECK_TYPE([bool])
#need the defines for PRId64
AC_CHECK_SIZEOF(int64_t)
AC_CHECK_SIZEOF(long)
dnl On MinGW OpenLDAP is not available, so LDAP helpers can be linked
dnl only with Windows LDAP libraries using -lwldap32
case "$host_os" in
-mingw|mingw32)
- LDAPLIB="-lwldap32"
- LBERLIB=""
- ;;
-*)
- LDAPLIB="-lldap"
- dnl LDAP helpers need to know if -llber is needed or not
- AC_CHECK_LIB(lber, main, [LBERLIB="-llber"])
- ;;
+ mingw|mingw32)
+ LDAPLIB="-lwldap32"
+ LBERLIB=""
+ ;;
+ *)
+ AC_CHECK_LIB(ldap, ldap_init, [LDAPLIB="-lldap"])
+ dnl LDAP helpers need to know if -llber is needed or not
+ AC_CHECK_LIB(lber, ber_init, [LBERLIB="-llber"])
+ dnl if no ldap lib found check for mozilla version
+ if test "x$ac_cv_lib_ldap_ldap_init" != x""yes; then
+ oLIBS=$LIBS
+ LIBS="$LIBPTHREADS"
+ AC_CHECK_LIB(ldap60, ldap_init, [LDAPLIB="-lldap60"])
+ LIBS="$LDAPLIB $LIBPTHREADS"
+ AC_CHECK_LIB(prldap60, prldap_init, [LDAPLIB="-lprldap60 $LDAPLIB"])
+ LIBS="$LDAPLIB $LIBPTHREADS"
+ AC_CHECK_LIB(ssldap60, ldapssl_init, [LDAPLIB="-lssldap60 $LDAPLIB"])
+ LIBS=$oLIBS
+ fi
+
+ AC_CHECK_HEADERS(ldap.h lber.h)
+ AC_CHECK_HEADERS(mozldap/ldap.h)
+
+ dnl
+ dnl Check for LDAP_OPT_DEBUG_LEVEL
+ dnl
+ AC_MSG_CHECKING([for LDAP_OPT_DEBUG_LEVEL])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+# include <ldap.h>
+ ]],[[
+ int i=LDAP_OPT_DEBUG_LEVEL
+ ]])],
+ [ AC_MSG_RESULT(yes) ],
+ [ AC_MSG_RESULT(no) ])
+
+ dnl
+ dnl Check for working ldap
+ dnl
+ oLIBS=$LIBS
+ LIBS="$LDAPLIB $LBERLIB $LIBPTHREADS"
+ AC_MSG_CHECKING([for working ldap])
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+# define LDAP_DEPRECATED 1
+# if HAVE_LDAP_H
+# include <ldap.h>
+# elif HAVE_MOZLDAP_LDAP_H
+# include <mozldap/ldap.h>
+# endif
+ int
+ main(void)
+ {
+ char host[]="";
+ int port;
+
+ ldap_init((const char *)&host, port);
+
+ return 0;
+ }
+ ]])],
+ [ AC_DEFINE(HAVE_LDAP, 1, [LDAP support])
+ AC_MSG_RESULT(yes) ],
+ [ AC_MSG_RESULT(no) ])
+ LIBS=$oLIBS
+
+ dnl
+ dnl Check for ldap vendor
+ dnl
+ AC_MSG_CHECKING([for OpenLDAP])
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+# if HAVE_LDAP_H
+# include <ldap.h>
+# endif
+# include <string.h>
+ int
+ main(void)
+ {
+ return strcmp(LDAP_VENDOR_NAME,"OpenLDAP");
+ }
+ ]])],
+ [ AC_DEFINE(HAVE_OPENLDAP, 1, [OpenLDAP support])
+ AC_MSG_RESULT(yes) ],
+ [ AC_MSG_RESULT(no) ])
+
+ AC_MSG_CHECKING([for Sun LDAP SDK])
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+# if HAVE_LDAP_H
+# include <ldap.h>
+# endif
+# include <string.h>
+ int
+ main(void)
+ {
+ return strcmp(LDAP_VENDOR_NAME,"Sun Microsystems Inc.");
+ }
+ ]])],
+ [ AC_DEFINE(HAVE_SUN_LDAP_SDK, 1, [Sun LDAP SDK support])
+ AC_MSG_RESULT(yes) ],
+ [ AC_MSG_RESULT(no) ])
+
+ AC_MSG_CHECKING([for Mozilla LDAP SDK])
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+# if HAVE_LDAP_H
+# include <ldap.h>
+# elif HAVE_MOZLDAP_LDAP_H
+# include <mozldap/ldap.h>
+# endif
+# include <string.h>
+ int
+ main(void)
+ {
+ return strcmp(LDAP_VENDOR_NAME,"mozilla.org");
+ }
+ ]])],
+ [ AC_DEFINE(HAVE_MOZILLA_LDAP_SDK, 1, [Mozilla LDAP SDK support])
+ AC_MSG_RESULT(yes) ],
+ [ AC_MSG_RESULT(no)])
+
+ dnl
+ dnl Check for LDAP_REBINDPROC_CALLBACK
+ dnl
+ AC_MSG_CHECKING([for LDAP_REBINDPROC_CALLBACK])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+# if HAVE_LDAP_H
+# include <ldap.h>
+# elif HAVE_MOZLDAP_LDAP_H
+# include <mozldap/ldap.h>
+# endif
+ ]],[[
+ LDAP_REBINDPROC_CALLBACK ldap_rebind;
+ ]])],
+ [ AC_DEFINE(HAVE_LDAP_REBINDPROC_CALLBACK,1,[Define to 1 if you have LDAP_REBINDPROC_CALLBACK])
+ AC_MSG_RESULT(yes) ],
+ [ AC_MSG_RESULT(no) ])
+
+ dnl
+ dnl Check for LDAP_REBIND_PROC
+ dnl
+ AC_MSG_CHECKING([for LDAP_REBIND_PROC])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+# if HAVE_LDAP_H
+# include <ldap.h>
+# elif HAVE_MOZLDAP_LDAP_H
+# include <mozldap/ldap.h>
+# endif
+ ]],[[
+ LDAP_REBIND_PROC ldap_rebind;
+ ]])],
+ [ AC_DEFINE(HAVE_LDAP_REBIND_PROC,1,[Define to 1 if you have LDAP_REBIND_PROC])
+ AC_MSG_RESULT(yes) ],
+ [ AC_MSG_RESULT(no) ])
+
+ dnl
+ dnl Check for LDAP_REBIND_FUNCTION
+ dnl
+ AC_MSG_CHECKING([for LDAP_REBIND_FUNCTION])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+# define LDAP_REFERRALS
+# if HAVE_LDAP_H
+# include <ldap.h>
+# elif HAVE_MOZLDAP_LDAP_H
+# include <mozldap/ldap.h>
+# endif
+ ]],[[
+ LDAP_REBIND_FUNCTION ldap_rebind;
+ ]])],
+ [ AC_DEFINE(HAVE_LDAP_REBIND_FUNCTION,1,[Define to 1 if you have LDAP_REBIND_FUNCTION])
+ AC_MSG_RESULT(yes) ],
+ [ AC_MSG_RESULT(no) ])
+
+ dnl
+ dnl Check for LDAP_SCOPE_DEFAULT
+ dnl
+ AC_MSG_CHECKING([for LDAP_SCOPE_DEFAULT])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+# if HAVE_LDAP_H
+# include <ldap.h>
+# elif HAVE_MOZLDAP_LDAP_H
+# include <mozldap/ldap.h>
+# endif
+ ]],[[
+ int i=LDAP_SCOPE_DEFAULT;
+ ]])],
+ [ AC_DEFINE(HAVE_LDAP_SCOPE_DEFAULT,1,[Define to 1 if you have LDAP_SCOPE_DEFAULT])
+ AC_MSG_RESULT(yes) ],
+ [ AC_MSG_RESULT(no) ])
+
+ dnl
+ dnl Check for ldap_url_desc.lud_scheme
+ dnl
+ AC_CHECK_MEMBER(struct ldap_url_desc.lud_scheme,
+ AC_DEFINE(HAVE_LDAP_URL_LUD_SCHEME,1,
+ [Define to 1 if you have LDAPURLDesc.lud_scheme]),,[#include <ldap.h>])
+
+ dnl
+ dnl Check for ldapssl_client_init
+ dnl
+ AC_CHECK_LIB(ldap,ldapssl_client_init,
+ AC_DEFINE(HAVE_LDAPSSL_CLIENT_INIT,1,[Define to 1 if you have ldapssl_client_init]),)
+
+ dnl
+ dnl Check for ldap_url_desc2str
+ dnl
+ AC_CHECK_LIB(ldap,ldap_url_desc2str,
+ AC_DEFINE(HAVE_LDAP_URL_DESC2STR,1,[Define to 1 if you have ldap_url_desc2str]),)
+
+ dnl
+ dnl Check for ldap_url_parse
+ dnl
+ AC_CHECK_LIB(ldap,ldap_url_parse,
+ AC_DEFINE(HAVE_LDAP_URL_PARSE,1,[Define to 1 if you have ldap_url_parse]),)
+ ;;
esac
+
AC_SUBST(LDAPLIB)
AC_SUBST(LBERLIB)
initgroups \
getaddrinfo \
getnameinfo \
+ psignal \
strerror \
strsep \
strtoll \
helpers/negotiate_auth/SSPI/Makefile \
helpers/external_acl/Makefile \
helpers/external_acl/AD_group/Makefile \
+ helpers/external_acl/eDirectory_userip/Makefile \
helpers/external_acl/file_userip/Makefile \
+ helpers/external_acl/kerberos_ldap_group/Makefile \
helpers/external_acl/LDAP_group/Makefile \
helpers/external_acl/LM_group/Makefile \
helpers/external_acl/session/Makefile \
helpers/url_rewrite/Makefile \
helpers/url_rewrite/fake/Makefile \
tools/Makefile
+ tools/purge/Makefile
])
AC_CONFIG_SUBDIRS(lib/libTrie)
--- /dev/null
+--- /usr/include/kerberosv5/krb5.h.orig Mon Aug 23 04:09:23 2010
++++ /usr/include/kerberosv5/krb5.h Mon Aug 23 04:10:53 2010
+@@ -171,6 +171,7 @@
+ #define KRB5INT_END_DECLS
+ #endif
+ #endif
++KRB5INT_BEGIN_DECLS
+
+ #if TARGET_OS_MAC
+ # pragma options align=mac68k
+@@ -3246,8 +3247,4 @@
+ /* for compatibility with older versions... */
+ #define asn1_err_base ERROR_TABLE_BASE_asn1
+
+-#ifdef __cplusplus
+-}
+-#endif
+-
+ #endif /* _KRB5_H */
#~ msgid "12 August 2002"
#~ msgstr ""
-#. type: TH
-#. type: Plain text
-#: helpers/external_acl/unix_group/squid_unix_group.8:1
-#: helpers/external_acl/unix_group/squid_unix_group.8:7
#, no-wrap
-msgid "Squid UNIX Group helper"
-msgstr "Módulo de grupo UNIX de Squid"
+#~ msgid "Squid UNIX Group helper"
+#~ msgstr "Módulo de grupo UNIX de Squid"
#~ msgid "squid_unix_group - Squid UNIX Group external_acl helper"
#~ msgstr ""
"no cumple estos criterios o si desea filtrar a los usuarios válidos "
"necesita filtrar por los DN de usuario."
-#. type: Plain text
-#: helpers/external_acl/ldap_group/squid_ldap_group.8:87
-msgid ""
-"The DN and password to bind as while performing searches. Required if the "
-"directory does not allow anonymous searches."
-msgstr ""
-"El DN y clave para enlazar al directorio mientras se realizan las búsquedas. "
-"Requerido si el directorio no permite búsquedas anónimas."
+#~ msgid ""
+#~ "The DN and password to bind as while performing searches. Required if the "
+#~ "directory does not allow anonymous searches."
+#~ msgstr ""
+#~ "El DN y clave para enlazar al directorio mientras se realizan las búsquedas. "
+#~ "Requerido si el directorio no permite búsquedas anónimas."
#. type: Plain text
#: helpers/external_acl/ldap_group/squid_ldap_group.8:141
msgid "A simple HTTP web client tool"
msgstr "Una herramienta web cliente HTTP sencilla"
-#. type: Plain text
-#: helpers/external_acl/unix_group/squid_unix_group.8:18
-msgid ""
-"B<squid_unix_group> allows Squid to base access controls on users "
-"memberships in UNIX groups."
-msgstr ""
-"B<squid_unix_group> permite a Squid realizar controles de acceso basado en "
-"la membresía de grupos UNIX de los usuarios"
+#~ msgid ""
+#~ "B<squid_unix_group> allows Squid to base access controls on users "
+#~ "memberships in UNIX groups."
+#~ msgstr ""
+#~ "B<squid_unix_group> permite a Squid realizar controles de acceso basado en "
+#~ "la membresía de grupos UNIX de los usuarios"
#. type: Plain text
#: helpers/basic_auth/RADIUS/basic_radius_auth.8:60
"El nombre de servicio es B<squid> , y el programa hace uso de B<auth> y "
"B<account> para administración. Verifique la clave y la validez de la cuenta."
-#. type: Plain text
-#: helpers/external_acl/ldap_group/squid_ldap_group.8:33
-msgid ""
-"B<squid_ldap_group> allows Squid to connect to a LDAP directory to authorize "
-"users via LDAP groups. LDAP options are specified as parameters on the "
-"command line, while the username(s) and group(s) to be checked against the "
-"LDAP directory are specified on subsequent lines of input to the helper, one "
-"username/group pair per line separated by a space."
-msgstr ""
-"B<squid_ldap_group> permite a Squid conectar a un directorio LDAP para "
-"autorizar grupos de usuarios LDAP. Las opciones LDAP son especificadas como "
-"parámetros en la línea de comandos, mientras, los nombres de usuario y "
-"grupos a ser autenticados contra el servidor LDAP son especificados en las "
-"líneas de entrada subsecuentes del módulo, un par nombre de usuario/grupo "
-"por línea separado por espacios"
+#~ msgid ""
+#~ "B<squid_ldap_group> allows Squid to connect to a LDAP directory to authorize "
+#~ "users via LDAP groups. LDAP options are specified as parameters on the "
+#~ "command line, while the username(s) and group(s) to be checked against the "
+#~ "LDAP directory are specified on subsequent lines of input to the helper, one "
+#~ "username/group pair per line separated by a space."
+#~ msgstr ""
+#~ "B<squid_ldap_group> permite a Squid conectar a un directorio LDAP para "
+#~ "autorizar grupos de usuarios LDAP. Las opciones LDAP son especificadas como "
+#~ "parámetros en la línea de comandos, mientras, los nombres de usuario y "
+#~ "grupos a ser autenticados contra el servidor LDAP son especificados en las "
+#~ "líneas de entrada subsecuentes del módulo, un par nombre de usuario/grupo "
+#~ "por línea separado por espacios"
#. type: Plain text
#: src/squid.8.in:166
msgid "Host header"
msgstr "cabecera de host"
-#. type: Plain text
-#: helpers/external_acl/ldap_group/squid_ldap_group.8:158
-msgid ""
-"Specify an alternate TCP port where the ldap server is listening if other "
-"than the default LDAP port 389."
-msgstr ""
-"Especificar puerto TCP alternativo si el servidor LDAP está escuchando en un "
-"puerto diferente al puerto por defecto 389"
+#~ msgid ""
+#~ "Specify an alternate TCP port where the ldap server is listening if other "
+#~ "than the default LDAP port 389."
+#~ msgstr ""
+#~ "Especificar puerto TCP alternativo si el servidor LDAP está escuchando en un "
+#~ "puerto diferente al puerto por defecto 389"
#. type: Plain text
#: helpers/basic_auth/LDAP/basic_ldap_auth.8:16 helpers/basic_auth/LDAP/basic_ldap_auth.8:31 helpers/external_acl/ldap_group/squid_ldap_group.8:18
"Especifica el servidor LDAP a conectar por un URI LDAP (requiere las "
"librerías OpenLDAP)"
-#. type: Plain text
-#: helpers/external_acl/session/squid_session.8:23
-msgid ""
-"B<squid_session> maintains a concept of sessions by monitoring requests and "
-"timing out sessions if no requests have been seen for the idle timeout timer."
-msgstr ""
-"B<squid_session> mantiene un \"concepto\" de sesiones por monitoreo de "
-"solicitudes y expiración de sesiones HTTP si las solicitudes han sido vistas "
-"por el temporizador."
+#~ msgid ""
+#~ "B<squid_session> maintains a concept of sessions by monitoring requests and "
+#~ "timing out sessions if no requests have been seen for the idle timeout timer."
+#~ msgstr ""
+#~ "B<squid_session> mantiene un \"concepto\" de sesiones por monitoreo de "
+#~ "solicitudes y expiración de sesiones HTTP si las solicitudes han sido vistas "
+#~ "por el temporizador."
#. type: Plain text
#: helpers/basic_auth/PAM/basic_pam_auth.8:46
"este archivo; si no, escriba a la Free Software Foundation, Inc., 59 Temple "
"Place, Suite 330, Boston, MA 02111-1307 USA"
-#. type: Plain text
-#: helpers/external_acl/ldap_group/squid_ldap_group.8:231
-msgid ""
-"B<NOTE:> When constructing search filters it is recommended to first test "
-"the filter using B<ldapsearch> to verify that the filter matches what you "
-"expect before you attempt to use B<squid_ldap_group>"
-msgstr ""
-"B<NOTE:> Cuando se construyen filtros de búsqueda es recomendable primer "
-"hacer pruebas del filtro usando B<ldapsearch> para verificar que el filtro "
-"devuelve los resultados esperados antes de usar B<squid_ldap_group>"
+#~ msgid ""
+#~ "B<NOTE:> When constructing search filters it is recommended to first test "
+#~ "the filter using B<ldapsearch> to verify that the filter matches what you "
+#~ "expect before you attempt to use B<squid_ldap_group>"
+#~ msgstr ""
+#~ "B<NOTE:> Cuando se construyen filtros de búsqueda es recomendable primer "
+#~ "hacer pruebas del filtro usando B<ldapsearch> para verificar que el filtro "
+#~ "devuelve los resultados esperados antes de usar B<squid_ldap_group>"
#. type: Plain text
#: helpers/basic_auth/getpwnam/basic_getpwnam_auth.8:71 helpers/basic_auth/NCSA/basic_ncsa_auth.8:32 helpers/basic_auth/RADIUS/basic_radius_auth.8:93 helpers/external_acl/ldap_group/squid_ldap_group.8:243 helpers/external_acl/unix_group/squid_unix_group.8:67
"cache.org/SquidFaq/BugReporting para detalles de lo que necesita incluir en "
"el reporte de errores"
-#. type: Plain text
-#: helpers/external_acl/ldap_group/squid_ldap_group.8:20
-msgid "ldap_server_name"
-msgstr "ldap_server_name"
+#~ msgid "ldap_server_name"
+#~ msgstr "ldap_server_name"
#. type: Plain text
#: src/squid.8.in:36
"El archivo de configuración principal para las herramientas web "
"B<cachemgr.cgi>"
-#. type: Plain text
-#: helpers/basic_auth/LDAP/basic_ldap_auth.8:216 helpers/external_acl/ldap_group/squid_ldap_group.8:204
-msgid "LDAP protocol version. Defaults to 2 if not specified."
-msgstr ""
-"Versión del protocolo LDAP. Se usará la versión 2 si no se especifica."
+#~ msgid "LDAP protocol version. Defaults to 2 if not specified."
+#~ msgstr ""
+#~ "Versión del protocolo LDAP. Se usará la versión 2 si no se especifica."
#. type: Plain text
#: helpers/basic_auth/PAM/basic_pam_auth.8:7
"solicitudes, en adición a cualquier B<http_port> especificado en "
"B<squid.conf>"
-#. type: Plain text
-#: helpers/external_acl/session/squid_session.8:7
-msgid "Squid session tracking external acl group helper."
-msgstr "Módulo externo de seguimiento de sesiones para ACLs de grupo"
+#~ msgid "Squid session tracking external acl group helper."
+#~ msgstr "Módulo externo de seguimiento de sesiones para ACLs de grupo"
#. type: Plain text
#: tools/squidclient.1:18
"is not permitted then the authenticator will typically fail with \"-1, "
"generic error\"."
msgstr ""
+"Típicamente las bases de datos de autenticación (B</etc/sasldb> "
+",B</etc/shadow> ,B<PAM> ) no pueden ser accedidas por un usuario normal. "
+"Debería usar setuid/setgid y un usuario/grupo apropiado sobre el ejecutable "
+"para permitir al autenticador acceder a la base de datos de contraseñas "
+"apropiada. Si el acceso a la base de datos no es permitido entonces el "
+"autenticador fallará típicamente con \"-1, generic error\"."
#. type: Plain text
#: helpers/digest_auth/file/digest_file_auth.8:19
#: helpers/digest_auth/file/digest_file_auth.8:34
#, no-wrap
msgid "- plaintext entry format is username:password"
-msgstr ""
+msgstr "Entrada en formato de texto plano es nombre de usuario: contraseña"
#. type: Plain text
#: helpers/digest_auth/file/digest_file_auth.8:50
msgid ""
" - use traditional \n"
"B</etc/passwd>\n"
-msgstr ""
+msgstr " uso tradicional\n"
#. type: Plain text
#: helpers/basic_auth/SASL/basic_sasl_auth.8:36
#. type: Plain text
#: helpers/digest_auth/file/digest_file_auth.8:64
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:108
msgid "Based on prior work by"
-msgstr ""
+msgstr "Basado en trabajo previo por"
#. type: Plain text
#: helpers/basic_auth/SASL/basic_sasl_auth.8:38
#, no-wrap
msgid " - use PAM authentication database\n"
-msgstr ""
+msgstr " - usar base de datos de autenticación PAM\n"
#. type: Plain text
#: helpers/digest_auth/file/digest_file_auth.8:28
#: helpers/digest_auth/file/digest_file_auth.8:31
#, no-wrap
msgid "- empty or blank lines are possible;"
-msgstr ""
+msgstr "- son posibles líneas vacías o en blanco;"
#. type: Plain text
#: helpers/basic_auth/SASL/basic_sasl_auth.8:74
"service name if B<pwcheck_method:pam> is chosen. And example PAM "
"configuration file B<basic_sasl_auth.pam> is also included."
msgstr ""
+
+#. type: Plain text
+#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:43
+msgid ""
+"Users that are allowed to access the web proxy must have the Windows NT User "
+"Rights \"logon from the network\"."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/file_userip/ext_file_userip_acl.8:49
+msgid "ip_addr[/netmask]\t\tusername|@group|ALL|NONE"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:128 helpers/external_acl/LM_group/ext_lm_group_acl.8:90
+msgid ""
+"Native WIN32 NTLM and Basic Helpers must be used without the B<-A> and B<-D> "
+"switches."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LM_group/ext_lm_group_acl.8:37
+msgid "Start helper in Domain Global Group mode."
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:75
+msgid ""
+"You will need to specify the absolute path to B<basic_sspi_auth> in the "
+"B<auth_param basic program> directive."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:51
+msgid "Use case insensitive compare (local mode only)."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/session/ext_session_acl.8:7
+msgid "Squid session tracking external acl helper."
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:14 helpers/basic_auth/SSPI/basic_sspi_auth.8:16 helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:15 helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:17
+msgid "Group Name"
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:97
+msgid ""
+"Note that if NT guest user access is allowed on the PDC, an OK message may "
+"be returned instead of ERR."
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:99
+msgid ""
+"Test that entering an valid username and password results in an OK message."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LM_group/ext_lm_group_acl.8:19
+msgid ""
+"B<ext_lm_group_acl> is an installed binary in Squid for Windows builds."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LM_group/ext_lm_group_acl.8:22
+msgid ""
+"This helper must be used in with an authentication scheme (typically Basic "
+"or NTLM) based on Windows NT/2000 domain users (LM mode)."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:19
+msgid ""
+"B<ext_ad_group_acl> is an installed binary in Squid for Windows builds."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:59 helpers/external_acl/file_userip/ext_file_userip_acl.8:31 helpers/external_acl/LM_group/ext_lm_group_acl.8:39 helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:31
+msgid "Display the binary help and command line syntax info using stderr."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:57
+msgid "Start helper in Active Directory Global mode."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:130 helpers/external_acl/LM_group/ext_lm_group_acl.8:92
+msgid "Refer to Squid documentation for the more details on squid.conf."
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:38
+msgid "A Windows Local Group name allowed to authenticate."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LM_group/ext_lm_group_acl.8:139
+msgid "with contributions by"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:46
+msgid ""
+"B<- Domain Global> B<- Domain Local from user's domain> B<- Universal> and "
+"Active Directory group nesting is fully supported."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:28
+msgid "Two running mode are available:"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LM_group/ext_lm_group_acl.8:83
+msgid ""
+"The standard group name comparison is case sensitive, so group name must be "
+"specified with same case as in the NT/2000 Domain. It's possible to enable "
+"case insensitive group name comparison ( B<-c> ), but on some not-english "
+"locales, the results can be unexpected."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/file_userip/ext_file_userip_acl.8:45
+msgid ""
+"If the helper program finds a matching username/ip in the configuration "
+"file, it returns B<OK> , otherwise it returns B<ERR .>"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:55 helpers/external_acl/LM_group/ext_lm_group_acl.8:35
+msgid "Specify the default user's domain."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:95
+msgid ""
+"In the previous example all validated AD users member of I<MYDOMAIN\\"
+"GProxyUsers> domain group or member of I<LProxyUsers> machine local group "
+"are allowed to use the cache."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:14 helpers/external_acl/LM_group/ext_lm_group_acl.8:14
+msgid "domain"
+msgstr ""
+
+#. type: Plain text
+#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:54
+msgid ""
+"Better group checking is available with External Acl, see mswin_check_group "
+"documentation."
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:56
+msgid ""
+"You will need to set the following line in B<squid.conf> to enable the "
+"authenticator:"
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:18
+msgid "Default Domain"
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:92
+msgid ""
+"Test that entering no details does not result in an OK or ERR message."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:137 helpers/external_acl/LM_group/ext_lm_group_acl.8:99
+msgid ""
+"I strongly recommend that B<ext_lm_group_acl> is tested prior to being used "
+"in a production environment. It may behave differently on different "
+"platforms."
+msgstr ""
+
+#. type: SH
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:43
+#, no-wrap
+msgid "CONFGURATION"
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/LDAP/basic_ldap_auth.8:216 helpers/external_acl/LDAP_group/ext_ldap_group_acl.8:204
+msgid "LDAP protocol version. Defaults to 3 if not specified."
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:9 helpers/external_acl/AD_group/ext_ad_group_acl.8:9
+msgid "Version 2.0"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:187 helpers/external_acl/LM_group/ext_lm_group_acl.8:134
+msgid ""
+"Test that entering an valid username and group results in an B<OK> message."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/unix_group/ext_unix_group_acl.8:7
+msgid "Squid UNIX Group ACL helper"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/file_userip/ext_file_userip_acl.8:7
+msgid "Restrict users to cetain IP addresses, using a text file backend."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:117
+msgid ""
+"When running in local mode, the standard group name comparison is case "
+"sensitive, so group name must be specified with same case as in the local "
+"SAM database."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LM_group/ext_lm_group_acl.8:59
+msgid ""
+"In the previous example all validated NT users member of GProxyUsers Global "
+"domain group or member of LProxyUsers machine local group are allowed to use "
+"the cache."
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:24
+msgid ""
+"B<basic_sspi_auth> is a simple authentication module for the Squid proxy "
+"server running on Windows NT to authenticate users on an NT domain in native "
+"WIN32 mode."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:38
+msgid ""
+"The minimal Windows version needed to run ext_ad_group_acl is a Windows 2000 "
+"SP4 member of an Active Directory Domain."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/file_userip/ext_file_userip_acl.8:61
+msgid ""
+"When the second parameter is prefixed with an B<@> , the program will lookup "
+"the B</etc/group> file entry for the specified username."
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:31
+msgid ""
+"Usage is simple. It accepts a username and password on standard input and "
+"will return OK if the username/password is valid for the domain/machine, or "
+"ERR if there was some problem. It's possible to authenticate against NT "
+"trusted domains specifyng the username in the domain\\eusername Microsoft "
+"notation."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:41
+msgid ""
+"When running in Active Directory Global mode, all types of Active Directory "
+"security groups are supported:"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LM_group/ext_lm_group_acl.8:67
+msgid ""
+"Groups with spaces in name, for example B<Domain Users> , must be quoted and "
+"the acl data ( B<Domain Users> ) must be placed into a separate file "
+"included by specifying B</path/to/file>"
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:51
+msgid ""
+"This can be accomplished creating a local user group on the NT machine, "
+"grant the privilege, and adding users to it."
+msgstr ""
+
+#. type: Plain text
+#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:57
+msgid "B<squid.conf> typical minimal required changes:"
+msgstr ""
+
+#. type: Plain text
+#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:85
+msgid "Based on prior work in by"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:164 helpers/external_acl/AD_group/ext_ad_group_acl.8:179 helpers/external_acl/LM_group/ext_lm_group_acl.8:126
+msgid ""
+"Test that entering no details does not result in an B<OK> or B<ERR> message."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:35
+msgid ""
+"B<- Local mode:> membership is checked against machine's local groups, "
+"cannot be used when running on a Domain Controller. B<- Active Directory "
+"Global mode:> membership is checked against the whole Active Directory "
+"Forest of the machine where Squid is running."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:113
+msgid ""
+"When running in Active Directory Global mode, for better performance, all "
+"Domain Controllers of the Active Directory forest should be configured as "
+"Global Catalog."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:22
+msgid ""
+"This helper must be used in with an authentication scheme (typically Basic, "
+"NTLM or Negotiate) based on Windows Active Directory domain users."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/file_userip/ext_file_userip_acl.8:37
+msgid "The B<squid.conf> configuration for the external ACL should be:"
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:36 helpers/external_acl/AD_group/ext_ad_group_acl.8:53 helpers/external_acl/file_userip/ext_file_userip_acl.8:27 helpers/external_acl/LM_group/ext_lm_group_acl.8:33 helpers/external_acl/unix_group/ext_unix_group_acl.8:23 helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:29
+msgid "Write debug info to stderr."
+msgstr ""
+
+#. type: Plain text
+#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:35
+msgid "Specify a Windows Local Group name allowed to authenticate."
+msgstr ""
+
+#. type: Plain text
+#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:75
+msgid ""
+"Internet Explorer has some problems with B<ftp://> URLs when handling "
+"internal Squid FTP icons. The following B<squid.conf> ACL works around this "
+"when placed before the authentication ACL:"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/file_userip/ext_file_userip_acl.8:47
+msgid "The configuration file format is as follows:"
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:48
+msgid ""
+"Users that are allowed to access the web proxy must have the Windows NT User "
+"Rights \"logon from the network\" and must be included in the NT LOCAL User "
+"Groups specified in the Authenticator's command line."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LM_group/ext_lm_group_acl.8:69
+msgid "The previous example will be:"
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:102
+msgid ""
+"Test that entering a guest username and password returns the correct "
+"response for the site's access policy."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LM_group/ext_lm_group_acl.8:144
+msgid "Based in part on prior work in B<check_group> by"
+msgstr ""
+
+#. type: Plain text
+#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:33
+msgid "Enables verbose NTLM packet debugging."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/file_userip/ext_file_userip_acl.8:29
+msgid "Configuration file to load."
+msgstr ""
+
+#. type: Plain text
+#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:24
+msgid ""
+"B<ntlm_sspi_auth.exe> is an installed binary built on Windows systems. It "
+"provides native access to the Security Service Provider Interface of Windows "
+"for authenticating with NTLM / NTLMv2. It has automatic support for NTLM "
+"NEGOTIATE packets."
+msgstr ""
+
+#. type: Plain text
+#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:8
+msgid ""
+"Native Windows NTLM/NTLMv2 authenticator for Squid with automatic support "
+"for NTLM NEGOTIATE packets."
+msgstr ""
+
+#. any user on this IP address may authenticate\" or \"no user on this ip address may authenticate\".
+#. type: Plain text
+#: helpers/external_acl/file_userip/ext_file_userip_acl.8:67
+msgid "There are other two directives, B<ALL> and B<NONE> , which mean"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:104
+msgid ""
+"Groups with spaces in name, for example B<Domain Users> , must be quoted and "
+"the acl data ( B<Domain Users> ) must be placed into a separate file "
+"included by specifying B</path/to/file .> The previous example will be:"
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:40
+msgid "A Windows Local Group name not allowed to authenticate."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LM_group/ext_lm_group_acl.8:9 helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:10
+msgid "Version 1.22"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LM_group/ext_lm_group_acl.8:76
+msgid ""
+"and the B<DomainUsers.txt> files will contain only the following line: "
+"B<Domain Users>"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/session/ext_session_acl.8:23
+msgid ""
+"B<ext_session_acl> maintains a concept of sessions by monitoring requests "
+"and timing out sessions if no requests have been seen for the idle timeout "
+"timer."
+msgstr ""
+
+#. type: Plain text
+#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:37
+msgid ""
+"Specify a Windows Local Group name which is to be denied authentication."
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:7
+msgid "Basic authentication protocol"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LDAP_group/ext_ldap_group_acl.8:158
+msgid ""
+"Specify an alternate TCP port where the LDAP server is listening if other "
+"than the default LDAP port 389."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:77
+msgid ""
+"When using Plain NT4 Group Name, the Group is searched in the user's domain."
+msgstr ""
+
+#. type: Plain text
+#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:47
+msgid ""
+"Optionally the authenticator can verify the NT LOCAL group membership of the "
+"user against the User Group specified in the Authenticator's command line."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:122
+msgid ""
+"It is possible to enable case insensitive group name comparison ( B<-c> ), "
+"but on some non-english locales, the results can be unexpected."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LDAP_group/ext_ldap_group_acl.8:82
+msgid ""
+"Debug mode where each step taken will get reported in detail. Useful for "
+"understanding what goes wrong if the result is not what was expected."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:109
+msgid ""
+"and the DomainUsers files will contain only the following line: \"Domain "
+"Users\""
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LM_group/ext_lm_group_acl.8:31
+msgid "Use case insensitive compare."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:157 helpers/external_acl/AD_group/ext_ad_group_acl.8:172 helpers/external_acl/LM_group/ext_lm_group_acl.8:119
+msgid "Make sure pressing B<CTRL+C> aborts the program."
+msgstr ""
+
+#. type: Plain text
+#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:51
+msgid ""
+"This can be accomplished creating a local user group on the NT machine, "
+"grant the privilege, and adding users to it, it works only with MACHINE "
+"Local Groups, not Domain Local Groups."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:7 helpers/external_acl/LM_group/ext_lm_group_acl.8:7
+msgid "Squid external ACL helper to check Windows users group membership."
+msgstr ""
+
+#. type: SH
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:76 helpers/external_acl/AD_group/ext_ad_group_acl.8:131 helpers/external_acl/LM_group/ext_lm_group_acl.8:93
+#, no-wrap
+msgid "TESTING"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LDAP_group/ext_ldap_group_acl.8:33
+msgid ""
+"B<ext_ldap_group_acl> allows Squid to connect to a LDAP directory to "
+"authorize users via LDAP groups. LDAP options are specified as parameters "
+"on the command line, while the username(s) and group(s) to be checked "
+"against the LDAP directory are specified on subsequent lines of input to the "
+"helper, one username/group pair per line separated by a space."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/file_userip/ext_file_userip_acl.8:22
+msgid ""
+"It works by reading a pair composed by an ip address and an username on "
+"STDIN and matching it against a configuration file."
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:90
+#, no-wrap
+msgid ""
+"I strongly urge that \n"
+"B<basic_sspi_auth>\n"
+"is tested prior to being used in a \n"
+"production environment. It may behave differently on different platforms.\n"
+"To test it, run it from the command line. Enter username and password\n"
+"pairs separated by a space. Press ENTER to get an OK or ERR message.\n"
+"Make sure pressing \n"
+"B<CTRL-D>\n"
+" behaves the same as a carriage return.\n"
+"Make sure pressing \n"
+"B<CTRL-C>\n"
+" aborts the program.\n"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:149 helpers/external_acl/LM_group/ext_lm_group_acl.8:111
+msgid ""
+"To test it, run it from the command line. Enter username and group pairs "
+"separated by a space (username must entered with URL-encoded "
+"I<domain%5Cusername> syntax). Press B<ENTER> to get an B<OK> or B<ERR> "
+"message."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:64
+msgid ""
+"When running in Active Directory Global mode, the AD Group can be specified "
+"using the following syntax:"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:153 helpers/external_acl/AD_group/ext_ad_group_acl.8:168 helpers/external_acl/LM_group/ext_lm_group_acl.8:115
+msgid "Make sure pressing B<CTRL+D> behaves the same as a carriage return."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:183 helpers/external_acl/LM_group/ext_lm_group_acl.8:130
+msgid ""
+"Test that entering an invalid username and group results in an B<ERR> "
+"message."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LDAP_group/ext_ldap_group_acl.8:87
+msgid ""
+"The DN and password to bind as while performing searches. Required if the "
+"LDAP directory does not allow anonymous searches."
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:42
+msgid "The default Domain against to authenticate."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LDAP_group/ext_ldap_group_acl.8:231
+msgid ""
+"B<NOTE:> When constructing search filters it is recommended to first test "
+"the filter using B<ldapsearch> to verify that the filter matches what you "
+"expect before you attempt to use B<ext_ldap_group_acl>"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/file_userip/ext_file_userip_acl.8:14
+msgid "file name"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/LM_group/ext_lm_group_acl.8:41
+msgid "Use ONLY PDCs for group validation."
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:64
+msgid ""
+"You will need to set the following lines in B<squid.conf> to enable "
+"authentication for your access list -"
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:26 helpers/external_acl/LM_group/ext_lm_group_acl.8:26
+msgid ""
+"It reads from the standard input the domain username and a list of groups "
+"and tries to match each against the groups membership of the specified "
+"username."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/file_userip/ext_file_userip_acl.8:55
+msgid ""
+"Where B<ip_addr> is a dotted quad format IP address, the B<netmask> must be "
+"in dotted quad format too."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/file_userip/ext_file_userip_acl.8:19
+msgid ""
+"B<ext_file_userip_acl> is an installed binary. An external helper for the "
+"Squid external acl scheme."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/unix_group/ext_unix_group_acl.8:18
+msgid ""
+"B<ext_unix_group_acl> allows Squid to base access controls on users "
+"memberships in UNIX groups."
+msgstr ""
+
+#. type: Plain text
+#: helpers/basic_auth/SSPI/basic_sspi_auth.8:94
+msgid ""
+"Test that entering an invalid username and password results in an ERR "
+"message."
+msgstr ""
+
+#. type: Plain text
+#: helpers/external_acl/AD_group/ext_ad_group_acl.8:194
+msgid "Based on prior work in B<mswin_check_lm_group (ext_lm_group_acl)>"
+msgstr ""
"recommended, but if you absolutely need to then make the program B<setuid> "
"B<root>"
msgstr ""
+"При использовании локальной базы UNIX паролей для аутентификации программа "
+"должна быть запущена с правами администратора, иначе она не будет обладать "
+"достаточными правами для доступа к базе данных паролей пользователей. Такое "
+"использование этой программы не рекомендуется, но если это вам абсолютно "
+"необходимо, то измените B<setuid> на B<root>"
#. type: Plain text
#: helpers/basic_auth/getpwnam/basic_getpwnam_auth.8:60
#: helpers/external_acl/unix_group/ext_unix_group_acl.8:108
#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:123 src/squid.8.in:274
msgid "The Squid Configuration Manual"
-msgstr ""
+msgstr "Руководство по настройке Squid"
#. type: Plain text
#: helpers/basic_auth/LDAP/basic_ldap_auth.8:7
#: helpers/basic_auth/LDAP/basic_ldap_auth.8:216
#: helpers/external_acl/LDAP_group/ext_ldap_group_acl.8:204
msgid "LDAP protocol version. Defaults to 3 if not specified."
-msgstr ""
+msgstr "Версия протокола LDAP. По умолчанию 3, если не указано."
#. type: Plain text
#: helpers/basic_auth/LDAP/basic_ldap_auth.8:220
#: helpers/external_acl/LDAP_group/ext_ldap_group_acl.8:208
msgid "Use TLS encryption"
-msgstr ""
+msgstr "Используйте TLS шифрование"
#. type: Plain text
#: helpers/basic_auth/LDAP/basic_ldap_auth.8:224
#: helpers/external_acl/LDAP_group/ext_ldap_group_acl.8:107
msgid "Enable LDAP over SSL (requires Netscape LDAP API libraries)"
-msgstr ""
+msgstr "Включить LDAP через SSL (требуются Netscape LDAP API библиотеки)"
#. type: Plain text
#: helpers/basic_auth/LDAP/basic_ldap_auth.8:231
#. type: Plain text
#: helpers/basic_auth/NCSA/basic_ncsa_auth.8:11
msgid "passwd file"
-msgstr ""
+msgstr "passwd файл"
#. type: Plain text
#: helpers/basic_auth/NCSA/basic_ncsa_auth.8:16
#: helpers/basic_auth/PAM/basic_pam_auth.8:59
#, no-wrap
msgid "NOTES"
-msgstr ""
+msgstr "ПРИМЕЧАНИЯ"
#. type: Plain text
#: helpers/basic_auth/PAM/basic_pam_auth.8:66
#. type: Plain text
#: helpers/basic_auth/RADIUS/basic_radius_auth.8:12
msgid "config file"
-msgstr ""
+msgstr "конфигурационный файл"
#. type: Plain text
#: helpers/basic_auth/RADIUS/basic_radius_auth.8:16
#: helpers/external_acl/file_userip/ext_file_userip_acl.8:9
#: helpers/external_acl/session/ext_session_acl.8:9
msgid "Version 1.0"
-msgstr ""
+msgstr "Версия 1.0"
#. type: Plain text
#: helpers/basic_auth/SASL/basic_sasl_auth.8:18
#. type: Plain text
#: helpers/basic_auth/SASL/basic_sasl_auth.8:33
msgid "Examples:"
-msgstr ""
+msgstr "Например:"
#. type: Plain text
#: helpers/basic_auth/SASL/basic_sasl_auth.8:36
#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:29
msgid "Write debug info to stderr."
msgstr ""
+"Записывать отладочную информацию в стандартный файл вывода сообщений об "
+"ошибках (stderr)."
#. type: Plain text
#: helpers/basic_auth/SSPI/basic_sspi_auth.8:38
#: helpers/basic_auth/SSPI/basic_sspi_auth.8:43
#, no-wrap
msgid "CONFGURATION"
-msgstr ""
+msgstr "КОНФИГУРИРОВАНИЕ"
#. type: Plain text
#: helpers/basic_auth/SSPI/basic_sspi_auth.8:48
#: helpers/basic_auth/SSPI/basic_sspi_auth.8:76
#: helpers/external_acl/AD_group/ext_ad_group_acl.8:131
#: helpers/external_acl/LM_group/ext_lm_group_acl.8:93
-#, fuzzy, no-wrap
+#, no-wrap
+#, no-wrap
#| msgid "QUESTIONS"
msgid "TESTING"
-msgstr "Ð\92Ð\9eÐ\9fÐ Ð\9eСЫ"
+msgstr "ТÐ\95СТÐ\98Ð Ð\9eÐ\92Ð\90Ð\9dÐ\98Ð\95"
#. type: Plain text
#: helpers/basic_auth/SSPI/basic_sspi_auth.8:90
#. type: Plain text
#: helpers/external_acl/file_userip/ext_file_userip_acl.8:14
msgid "file name"
-msgstr ""
+msgstr "имя файла"
#. type: Plain text
#: helpers/external_acl/file_userip/ext_file_userip_acl.8:19
#. type: Plain text
#: helpers/external_acl/file_userip/ext_file_userip_acl.8:47
msgid "The configuration file format is as follows:"
-msgstr ""
+msgstr "Формат конфигурационного файла выглядит следующим образом:"
#. type: Plain text
#: helpers/external_acl/file_userip/ext_file_userip_acl.8:49
#. type: Plain text
#: helpers/external_acl/LDAP_group/ext_ldap_group_acl.8:9
msgid "Version 2.17"
-msgstr ""
+msgstr "Версия 2.17"
#. type: Plain text
#: helpers/external_acl/LDAP_group/ext_ldap_group_acl.8:33
#. type: Plain text
#: helpers/external_acl/LDAP_group/ext_ldap_group_acl.8:145
msgid "Specify the LDAP server to connect to"
-msgstr ""
+msgstr "Укажите сервер LDAP для подключения к"
#. type: Plain text
#: helpers/external_acl/LDAP_group/ext_ldap_group_acl.8:149
#. type: Plain text
#: helpers/external_acl/LM_group/ext_lm_group_acl.8:139
msgid "with contributions by"
-msgstr ""
+msgstr "внесут свой вклад"
#. type: Plain text
#: helpers/external_acl/LM_group/ext_lm_group_acl.8:144
#. type: Plain text
#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:33
msgid "Enables verbose NTLM packet debugging."
-msgstr ""
+msgstr "Включить подробную отладку NTLM пакетов."
#. type: Plain text
#: helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8:35
#. type: Plain text
#: src/squid.8.in:21
msgid "service-name"
-msgstr ""
+msgstr "название службы"
#. type: Plain text
#: src/squid.8.in:23
msgid "command-line"
-msgstr ""
+msgstr "командная строка"
#. type: Plain text
#: src/squid.8.in:32
#. type: Plain text
#: src/squid.8.in:70
msgid "Do not catch fatal signals."
-msgstr ""
+msgstr "Не перехватывать сигналы отказов."
#. type: Plain text
#: src/squid.8.in:74
msgid "Write debugging to stderr also."
msgstr ""
+"Отладочную информацию тоже записывать в стандартный файл вывода сообщений об "
+"ошибках (stderr)."
#. type: Plain text
#: src/squid.8.in:86
#. type: Plain text
#: src/squid.8.in:100
msgid "Install as a Windows Service (see B<-n> option)."
-msgstr ""
+msgstr "установить как Службу Windows (see B<-n> option)."
#. type: Plain text
#: src/squid.8.in:107
#. type: Plain text
#: src/squid.8.in:121
msgid "No daemon mode."
-msgstr ""
+msgstr "Не в режиме демона."
#. type: Plain text
#: src/squid.8.in:125
#. type: Plain text
#: src/squid.8.in:131
msgid "Remove a Windows Service (see B<-n> option)."
-msgstr ""
+msgstr "Убрать из служб Windows (see B<-n> option)."
#. type: Plain text
#: src/squid.8.in:137
#. type: Plain text
#: src/squid.8.in:154
msgid "Print version and build details."
-msgstr ""
+msgstr "Показать версию и информацию о сборке."
#. type: Plain text
#: src/squid.8.in:158
#. type: Plain text
#: tools/squidclient.1:14
msgid "remote host"
-msgstr ""
+msgstr "удалённый хост"
#. type: Plain text
#: tools/squidclient.1:16
#. type: Plain text
#: tools/squidclient.1:24
msgid "local host"
-msgstr ""
+msgstr "локальный хост"
#. type: Plain text
#: tools/squidclient.1:26
#. type: Plain text
#: tools/squidclient.1:85
msgid "Ping interval in seconds (default 1 second)."
-msgstr ""
+msgstr "Интервал ping в секундах (по умолчанию 1 секунда)"
#. type: Plain text
#: tools/squidclient.1:89
#. type: Plain text
#: tools/squidclient.1:116
msgid "Port number of cache. Default is 3128."
-msgstr ""
+msgstr "Номер аорта кэширующего прокси-сервера. По умолчанию 3128."
#. type: Plain text
#: tools/squidclient.1:120
<!doctype linuxdoc system>
<article>
-<title>Squid 3.1.6 release notes</title>
+<title>Squid 3.1.7 release notes</title>
<author>Squid Developers</author>
<abstract>
<sect>Notice
<p>
-The Squid Team are pleased to announce the release of Squid-3.1.6
+The Squid Team are pleased to announce the release of Squid-3.1.7
This new release is available for download from <url url="http://www.squid-cache.org/Versions/v3/3.1/"> or the <url url="http://www.squid-cache.org/Mirrors/http-mirrors.html" name="mirrors">.
<item>permit IPv6-only snmp_incoming_address and snmp_outgoing_address to be configured.
<item>permit IPv6 server connection provided tcp_outgoing_address has been configured (see below).
</itemize>
-<p><em>NOTE:</em> SNMP, ICP and HTCP are not yet opening double ports so they will only run as IPv4-only or IPv6-only.
+<p><em>NOTE:</em> ICAP, SNMP, ICP and HTCP are not yet opening double ports so they will only run as IPv4-only or IPv6-only.
<p>Specify a specific tcp_outgoing_address and the clients who match its ACL are limited
to the IPv4 or IPv6 network that address belongs to. They are not permitted over the
<tag>ssl_bump</tag>
<p>New Access control for which CONNECT requests to an http_port
- marked with an sslBump flag are actually "bumped". Please
- see the sslBump flag of an http_port option for more details
+ marked with an ssl-bump flag are actually "bumped". Please
+ see the ssl-bump flag of an http_port option for more details
about decoding proxied SSL connections.
DEFAULT: No requests are bumped.
<verb>
X-Forwarded-For entries, and place itself as the sole entry.
</verb>
- <tag>http_port transparent intercept sslbump connection-auth[=on|off] ignore-cc</tag>
+ <tag>http_port transparent intercept ssl-bump connection-auth[=on|off] ignore-cc</tag>
<p>Option 'transparent' is being deprecated in favour of 'intercept' which more clearly identifies what the option does.
For now option 'tproxy' remains with old behaviour meaning fully-invisible proxy using TPROXY support.</p>
<p>New port options
Warning: This option violates HTTP specifications if
used in non-accelerator setups.
- sslBump Intercept each CONNECT request matching ssl_bump ACL,
+ ssl-bump Intercept each CONNECT request matching ssl_bump ACL,
establish secure connection with the client and with
the server, decrypt HTTP messages as they pass through
Squid, and treat them as unencrypted HTTP messages,
for more information on these options.
The ssl_bump option is required to fully enable
- the SslBump feature.
+ the SSL Bump feature.
</verb>
- <tag>https_port intercept sslbump connection-auth[=on|off]</tag>
+ <tag>https_port intercept ssl-bump connection-auth[=on|off]</tag>
<p>New port options. see http_port.
<tag>icap_service bypass=on|off|1|0 routing=on|off|1|0 ipv6=on|off</tag>
should have the same method and vectoring point as the current
ICAP transaction. Services violating these rules are ignored.
An empty X-Next-Services value results in an empty plan which
- ends the current adaptation.
+ ends the current adaptation.
Routing is not allowed by default: the ICAP X-Next-Services
response header is ignored.
<em>concurrency=N</em> previously called <em>auth_param ... concurrency</em> as a separate option.
<p>Removed Basic, Digest, NTLM, Negotiate <em>auth_param ... concurrency</em> setting option.
+ <tag>cache_peer</tag>
+ <p><em>htcp-*</em> options collapsed into <em>htcp=</em> taking an optional comma-separated list of flags.
+ The old form is deprecated but still accepted.
+
<tag>deny_info</tag>
<p>Support URL format tags. For dynamically generated URL in denial redirect.
lv.lang \
ms.lang \
nl.lang \
+ oc.lang \
pl.lang \
pt-br.lang \
pt.lang \
tr.lang \
uk.lang \
uz.lang \
+ vi.lang \
zh-cn.lang \
zh-tw.lang
fr fr-be fr-ca fr-ch fr-fr fr-lu fr-mc
he he-il
hu hu-hu
-hy hy-am
+hy hy-armn hy-am
id id-id
it it-ch it-it
ja ja-jp
"Project-Id-Version: Squid-3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-07-26 21:21+1300\n"
-"PO-Revision-Date: 2010-05-01 00:17+1300\n"
+"PO-Revision-Date: 2010-08-18 01:16+0200\n"
"Last-Translator: Amos <squid3@treenet.co.nz>\n"
"Language-Team: Squid Developers <squid-dev@squid-cache.org>\n"
"Language: en\n"
msgstr "ESI Processing failed."
#: templates/ERR_FTP_PUT_CREATED:1 templates/ERR_FTP_PUT_MODIFIED:1
-#, fuzzy
msgid "FTP PUT Successful."
-msgstr "FTP PUT Successful: File Created"
+msgstr "FTP PUT Successful."
#: templates/ERR_FTP_PUT_ERROR:3
-#, fuzzy
msgid "FTP PUT upload failed"
-msgstr "FTP PUT/upload failed"
+msgstr "FTP PUT upload failed"
#: templates/ERR_FTP_DISABLED:5
msgid "FTP is Disabled"
#: templates/ERR_AGENT_CONFIGURE:8 templates/ERR_AGENT_CONFIGURE:11
#: templates/ERR_AGENT_CONFIGURE:14
msgid "In the HTTP proxy box type the proxy name %h and port 3128."
-msgstr ""
+msgstr "In the HTTP proxy box type the proxy name %h and port 3128."
#: templates/ERR_INVALID_URL:5
msgid "Invalid URL"
msgstr "El procesado ESI falló"
#: templates/ERR_FTP_PUT_CREATED:1 templates/ERR_FTP_PUT_MODIFIED:1
-#, fuzzy
msgid "FTP PUT Successful."
-msgstr "FTP PUT Correcto: Archivo Creado"
+msgstr "PUT FTP realizado con éxito"
#: templates/ERR_FTP_PUT_ERROR:3
-#, fuzzy
msgid "FTP PUT upload failed"
-msgstr "FTP PUT/envio fallido"
+msgstr "FTP PUT fallido"
#: templates/ERR_FTP_DISABLED:5
msgid "FTP is Disabled"
"Project-Id-Version: Squid-3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-07-26 21:21+1300\n"
-"PO-Revision-Date: 2008-12-18 01:19+1300\n"
-"Last-Translator: Arthur Tumanyan <arthurtumanyan@yahoo.com>\n"
+"PO-Revision-Date: 2010-08-21 17:08+0200\n"
+"Last-Translator: Arthur <arthurtumanyan@yahoo.com>\n"
"Language-Team: Squid Developers <squid-dev@squid-cache.org>\n"
"Language: hy\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Pootle 1.2.0\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Pootle 2.0.1\n"
#: templates/ERR_DIR_LISTING:6
msgid "<a href=\"../\">Parent Directory</a> (<a href=\"/\">Root Directory</a>)"
msgstr ""
+"<a href=\"../\">Ծնողական դիրեկտորիա</a> (<a href=\"/\">Արմատական դիրեկտորիա</a>)"
#: templates/ERR_INVALID_REQ:4
msgid ""
"<b>Invalid Request</b> error was encountered while trying to process the "
"request:"
-msgstr ""
+msgstr "<b>Սխալ հարցում</b> հարցումն իրականացնելու ընթացքում տեղի ունեցավ սխալ:"
#: templates/ERR_INVALID_RESP:4
msgid ""
"<b>Invalid Response</b> error was encountered while trying to process the "
"request:"
msgstr ""
+"<b>Անթույլատրելի պատասխան</b> հարցումն իրականացնելու ընթացքում տեղի ունեցավ "
+"սխալ:"
#: templates/ERR_READ_TIMEOUT:7
-#, fuzzy
msgid ""
"A Timeout occurred while waiting to read data from the network. The network "
"or server may be down or congested. Please retry your request."
#: templates/ERR_URN_RESOLVE:3
msgid "A URL for the requested URN could not be retrieved"
-msgstr "Պահանջվող URN չի կարող առաքվել"
+msgstr "Պահանջվող URN-ի համար URL-ն հնարավոր չէ ստանալ"
#: templates/ERR_ACCESS_DENIED:5
msgid "Access Denied."
msgstr "Մուտքն արգելված է."
#: templates/ERR_ACCESS_DENIED:6
-#, fuzzy
msgid ""
"Access control configuration prevents your request from being allowed at "
"this time. Please contact your service provider if you feel this is "
"incorrect."
msgstr ""
-"Õ\84Õ¸Ö\82Õ¿Ö\84Õ« Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö\80Õ´Õ¡Õ¶ ÕºÕ¡Ö\80Õ¡Õ´Õ¥Õ¿Ö\80Õ¥Ö\80Õ¨ Õ©Õ¸Ö\82ÕµÕ¬ Õ¹Õ¥Õ¶ Õ¿Õ¡Õ¬Õ«Õ½ Õ¯Õ¡Õ¿Õ¡Ö\80ել Ձեր հարցումը տվյալ "
-"ÕºÕ¡Õ°Õ«Õ¶.ÔµÕ©Õ¥ Ô´Õ¸Ö\82Ö\84 Õ½Õ¡ Õ½ÕÕ¡Õ¬ Õ¥Ö\84 Õ°Õ¡Õ´Õ¡Ö\80Õ¸Ö\82Õ´,ÕÕ¶Õ¤Ö\80Õ¾Õ¸Ö\82Õ´ Õ§ Õ¤Õ«Õ´Õ¥Õ¬ Õ\81Õ¥Ö\80 Õ«Õ¶Õ¿Õ¥Ö\80Õ¶Õ¥Õ¿ ապահովողին․"
+"Õ\84Õ¸Ö\82Õ¿Ö\84Õ« Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö\80Õ´Õ¡Õ¶ ÕºÕ¡Ö\80Õ¡Õ´Õ¥Õ¿Ö\80Õ¥Ö\80Õ¨ Õ©Õ¸Ö\82ÕµÕ¬ Õ¹Õ¥Õ¶ Õ¿Õ¡Õ¬Õ«Õ½ Õ«Ö\80Õ¡Õ¯Õ¡Õ¶Õ¡Ö\81Õ¶ել Ձեր հարցումը տվյալ "
+"ÕºÕ¡Õ°Õ«Õ¶.ÔµÕ©Õ¥ Ô´Õ¸Ö\82Ö\84 Õ½Õ¡ Õ½ÕÕ¡Õ¬ Õ¥Ö\84 Õ°Õ¡Õ´Õ¡Ö\80Õ¸Ö\82Õ´,Õ¡ÕºÕ¡ Õ¤Õ«Õ´Õ¥Ö\84 Õ\81Õ¥Ö\80 Õ«Õ¶Õ¿Õ¥Ö\80Õ¶Õ¥Õ¿ Õ¯Õ¡Õº ապահովողին․"
#: templates/ERR_FTP_FORBIDDEN:4
msgid ""
"An FTP authentication failure occurred while trying to retrieve the URL: <a "
"href=\"%U\">%U</a>"
msgstr ""
-"URL ի առաքման ժամանակ տեղի ունեցավ FTP աութենտիֆիկացիայի սխալ: <a href=\"%U"
-"\">%U</a>"
+"URL -ի ստացման ընթացքում տեղի ունեցավ FTP աութենտիֆիկացիայի սխալ: <a href=\"%"
+"U\">%U</a>"
#: templates/ERR_FTP_FAILURE:4 templates/ERR_FTP_PUT_ERROR:4
msgid ""
"An FTP protocol error occurred while trying to retrieve the URL: <a href=\"%U"
"\">%U</a>"
msgstr ""
-"URL ի առաքման ժամանակ տեղի ունեցավ FTP արձանագրության սխալ: <a href=\"%U\">"
+"URL -ի ստացման ընթացքում տեղի ունեցավ FTP արձանագրության սխալ: <a href=\"%U\">"
"%U</a>"
#: templates/ERR_ICAP_FAILURE:10
msgstr ""
#: templates/ERR_READ_ERROR:7
-#, fuzzy
msgid ""
"An error condition occurred while reading data from the network. Please "
"retry your request."
msgstr ""
-"Ցանցից տվյալների ընթերցման ժամանակ առաջացավ սխալ.Խնդրվում է կրկնել հարցումը."
+"Ցանցից տվյալների ընթերցման ընթացքում առաջացավ սխալ.Խնդրվում է կրկնել "
+"հարցումը."
#: templates/ERR_WRITE_ERROR:7
-#, fuzzy
msgid ""
"An error condition occurred while writing to the network. Please retry your "
"request."
msgstr ""
-"Տվյալները ցանց ուղարկելու ժամանակ առաջացավ սխալ․ Խնդրվում է կրկնել հարցումը․"
+"Տվյալները ցանցում գրանցելու ընթացքում առաջացավ սխալ․ Խնդրվում է կրկնել "
+"հարցումը․"
#: templates/ERR_CACHE_ACCESS_DENIED:3 templates/ERR_CACHE_ACCESS_DENIED:5
msgid "Cache Access Denied."
msgstr "Քեշի կառավառման մուտքն արգելված է."
#: templates/ERR_URN_RESOLVE:5
+#, fuzzy
msgid "Cannot Resolve URN"
-msgstr ""
+msgstr "Cannot Resolve URN"
#: templates/ERR_LIFETIME_EXP:5
msgid "Connection Lifetime Expired"
-msgstr "Կապ հաստատման ժամանակը սպառվեց "
+msgstr "Կապի հաստատման ժամանակը սպառվեց"
#: templates/ERR_CONNECT_FAIL:5
msgid "Connection to %I failed."
#: templates/ERR_DIR_LISTING:3
msgid "Directory Content:"
-msgstr ""
+msgstr "Դիրեկտորիայի պարունակությունը:"
#: templates/ERR_DIR_LISTING:4
msgid "Directory Listing"
#: templates/ERR_DIR_LISTING:1
msgid "Directory: %U"
-msgstr ""
+msgstr "Դիրեկտորիա: %U"
#: templates/ERR_DIR_LISTING:2
msgid "Directory: <a href=\"%U\">%U</a>/"
-msgstr ""
+msgstr "Դիրեկտորիա: <a href=\"%U\">%U</a>/"
#: templates/ERR_ACCESS_DENIED:2 templates/ERR_AGENT_CONFIGURE:2
#: templates/ERR_AGENT_WPAD:2 templates/ERR_CACHE_ACCESS_DENIED:2
#: templates/ERR_CACHE_MGR_ACCESS_DENIED:1
msgid "ERROR: Cache Manager Access Denied"
-msgstr "Սխալ: Քեշի կառավառման մուտքն արգելված է"
+msgstr "ՍԽԱԼ: Քեշի կառավառման մուտքն արգելված է"
#: templates/ERR_FTP_PUT_ERROR:1
msgid "ERROR: FTP upload failed"
-msgstr "ՍԽԱԼ: FTP upload գործողությունը խափանվեց"
+msgstr "ՍԽԱԼ; FTP upload գործողությունը խափանվեց"
#: templates/ERR_ACCESS_DENIED:1 templates/ERR_CANNOT_FORWARD:1
#: templates/ERR_CONNECT_FAIL:1 templates/ERR_DNS_FAIL:1 templates/ERR_ESI:1
#: templates/ERR_UNSUP_REQ:1 templates/ERR_WRITE_ERROR:1
#: templates/ERR_ZERO_SIZE_OBJECT:1
msgid "ERROR: The requested URL could not be retrieved"
-msgstr "ՍԽԱԼ: Պահանջվող URL չի կարող առաքվել"
+msgstr "ՍԽԱԼ: Պահանջվող URL-ն հնարավոր չէ ստանալ"
#: templates/ERR_URN_RESOLVE:1
-#, fuzzy
msgid "ERROR: The requested URN could not be retrieved"
-msgstr "ՍԽԱԼ: Պահանջվող URL չի կարող առաքվել"
+msgstr "ՍԽԱԼ: Պահանջվող URL-ն հնարավոր չէ ստանալ"
#: templates/ERR_ESI:5
msgid "ESI Processing failed."
msgstr ""
#: templates/ERR_FTP_PUT_CREATED:1 templates/ERR_FTP_PUT_MODIFIED:1
-#, fuzzy
msgid "FTP PUT Successful."
msgstr "FTP PUT Գործողությունը հաջողվեց: Ֆայլը ստեղծված է"
#: templates/ERR_FTP_PUT_ERROR:3
-#, fuzzy
msgid "FTP PUT upload failed"
msgstr "FTP upload գործողությունը խափանվեց"
#: templates/ERR_SECURE_CONNECT_FAIL:5
msgid "Failed to establish a secure connection to %I"
-msgstr ""
+msgstr "Չհաջողվեց անվտանգ կապ հաստատել %I"
#: templates/ERR_FTP_PUT_CREATED:3
msgid "File created"
#: templates/ERR_AGENT_CONFIGURE:6 templates/ERR_AGENT_WPAD:6
msgid "For Firefox browsers go to: <ul>"
-msgstr ""
+msgstr "Firefox բրաուզերի համար այցելեք: <ul>"
#: templates/ERR_AGENT_CONFIGURE:9 templates/ERR_AGENT_WPAD:8
msgid "For Internet Explorer browsers go to: <ul>"
-msgstr ""
+msgstr "Internet Explorer բրաուզերի համար այցելեք: <ul>"
#: templates/ERR_AGENT_CONFIGURE:12 templates/ERR_AGENT_WPAD:11
msgid "For Opera browsers go to: <ul>"
-msgstr ""
+msgstr "Opera բրաուզերի համար այցելեք: <ul>"
#: templates/ERR_FORWARDING_DENIED:5
msgid "Forwarding Denied."
#: templates/ERR_URN_RESOLVE:8 templates/ERR_WRITE_ERROR:9
#: templates/ERR_ZERO_SIZE_OBJECT:8
msgid "Generated %T by %h (%s)"
-msgstr ""
+msgstr "Ստեղծված է %T by %h (%s)"
#: templates/ERR_INVALID_REQ:12
+#, fuzzy
msgid ""
"HTTP/1.1 <q>Expect:</q> feature is being asked from an HTTP/1.0 software."
msgstr ""
+"HTTP/1.1 <q>Expect:</q> հատկության համար հարցում է կատարվում HTTP/1.0 "
+"ծրագրային միջոցից"
#: templates/ERR_URN_RESOLVE:6
msgid "Hey, don't expect too much from URNs on %T :)"
#: templates/ERR_AGENT_CONFIGURE:5 templates/ERR_AGENT_WPAD:5
msgid "How to find these settings in your browser:"
-msgstr ""
+msgstr "Ինչպես փնտրել այս կարգաբերումները քո բրաուզերում:"
#: templates/ERR_ICAP_FAILURE:5
msgid "ICAP protocol error."
msgstr ""
#: templates/ERR_TOO_BIG:7
+#, fuzzy
msgid ""
"If you are making a GET request, then the item you are trying to download is "
"too large."
msgstr ""
+"Եթե Դուք GET հարցում եք ձևակերպում, ապա տարրը ,որը Դուք փորձում եք "
+"բեռնավորել, շատ մեծ ծավալ ունի."
#: templates/ERR_TOO_BIG:6
+#, fuzzy
msgid ""
"If you are making a POST or PUT request, then the item you are trying to "
"upload is too large."
msgstr ""
+"Եթե Դուք POST կամ PUT հարցում եք ձևակերպում, ապա տարրը ,որը Դուք փորձում եք "
+"բեռնավորել, շատ մեծ ծավալ ունի"
#: templates/ERR_INVALID_REQ:11 templates/ERR_INVALID_URL:11
msgid "Illegal character in hostname; underscores are not allowed."
-msgstr "Անթույլատրելի նիշ սերվերի անվան մեջ;ընդգծման նիշն անթույլատրելի է"
+msgstr "Անթույլատրելի նիշ սերվերի անվան մեջ; ընդգծման նիշն անթույլատրելի է"
#: templates/ERR_INVALID_URL:10
msgid "Illegal double-escape in the URL-Path"
-msgstr "Անթույլատրելի կրկնակի կառավարող նիշ URL ուղղում"
+msgstr "Անթույլատրելի կրկնակի կառավարող նիշ URL-ի ուղիում"
#: templates/ERR_AGENT_CONFIGURE:8 templates/ERR_AGENT_CONFIGURE:11
#: templates/ERR_AGENT_CONFIGURE:14
msgid "In the HTTP proxy box type the proxy name %h and port 3128."
-msgstr ""
+msgstr "HTTP proxy դաշտում նշիր proxy name %h և port 3128."
#: templates/ERR_INVALID_URL:5
msgid "Invalid URL"
-msgstr ""
+msgstr "Սխալ URL"
#: templates/ERR_INVALID_REQ:8
msgid "Missing HTTP Identifier (HTTP/1.0)."
#: templates/ERR_NO_RELAY:5
msgid "No Wais Relay"
-msgstr "Wais Relay որոշված չէ "
+msgstr "Wais Relay-ը որոշված չէ"
#: templates/ERR_FTP_PUT_CREATED:2 templates/ERR_FTP_PUT_MODIFIED:2
msgid "Operation successful"
#: templates/ERR_DIR_LISTING:5
msgid "Parent Directory"
-msgstr ""
+msgstr "Ծնողական դիրեկտորիա"
#: templates/ERR_CACHE_ACCESS_DENIED:7
msgid ""
#: templates/ERR_AGENT_WPAD:10
msgid "Select Automatically detect settings"
-msgstr ""
+msgstr "Ընտրեք Automatically detect settings"
#: templates/ERR_AGENT_WPAD:13
msgid "Select Use Automatic proxy configuration"
-msgstr ""
+msgstr "Ընտրեք Use Automatic proxy configuration"
#: templates/ERR_SOCKET_FAILURE:5
msgid "Socket Failure"
-msgstr "Socket ձախողում "
+msgstr "Socket ձախողում"
#: templates/ERR_INVALID_URL:6
-#, fuzzy
msgid "Some aspect of the requested URL is incorrect."
msgstr "URL-ի որոշ ասպեկտներ սխալ են."
#: templates/ERR_ICAP_FAILURE:8 templates/ERR_INVALID_REQ:5
#: templates/ERR_INVALID_URL:7
-#, fuzzy
msgid "Some possible problems are:"
msgstr "Հնարավոր պատճառներն են:"
#: templates/ERR_CACHE_MGR_ACCESS_DENIED:6
-#, fuzzy
msgid ""
"Sorry, you are not currently allowed to request %U from this cache manager "
"until you have authenticated yourself."
msgstr ""
-"Õ\86Õ¥Ö\80Õ¸Õ²Õ¸Ö\82Õ©ÕµÕ¸Ö\82Õ¶,Ô´Õ¸Ö\82Ö\84 Õ¹Õ¥Ö\84 Õ¯Õ¡Ö\80Õ¸Õ² Ö\84Õ¥Õ·Õ« Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö\80Õ´Õ¡Õ¶ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö\80Õ£Õ«Ö\81 Õ¯Õ¡Õ¿Õ¡Ö\80ել հետևյալ "
+"Õ\86Õ¥Ö\80Õ¸Õ²Õ¸Ö\82Õ©ÕµÕ¸Ö\82Õ¶,Ô´Õ¸Ö\82Ö\84 Õ¹Õ¥Ö\84 Õ¯Õ¡Ö\80Õ¸Õ² Ö\84Õ¥Õ·Õ« Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö\80Õ´Õ¡Õ¶ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö\80Õ£Õ«Ö\81 Õ«Ö\80Õ¡Õ¯Õ¡Õ¶Õ¡Ö\81Õ¶ել հետևյալ "
"հարցումը %U մինչև աութենտիֆիկացիան չանցնեք."
#: templates/ERR_CACHE_ACCESS_DENIED:6
-#, fuzzy
msgid ""
"Sorry, you are not currently allowed to request %U from this cache until you "
"have authenticated yourself."
msgstr ""
-"Õ\86Õ¥Ö\80Õ¸Õ²Õ¸Ö\82Õ©ÕµÕ¸Ö\82Õ¶,Ô´Õ¸Ö\82Ö\84 Õ¹Õ¥Ö\84 Õ¯Õ¡Ö\80Õ¸Õ² Õ¯Õ¡Õ¿Õ¡Ö\80ել հետևյալ հարցումը %U մինչև "
+"Õ\86Õ¥Ö\80Õ¸Õ²Õ¸Ö\82Õ©ÕµÕ¸Ö\82Õ¶,Ô´Õ¸Ö\82Ö\84 Õ¹Õ¥Ö\84 Õ¯Õ¡Ö\80Õ¸Õ² Õ«Ö\80Õ¡Õ¯Õ¡Õ¶Õ¡Ö\81Õ¶ել հետևյալ հարցումը %U մինչև "
"աութենտիֆիկացիան չանցնեք."
#: templates/ERR_ZERO_SIZE_OBJECT:6
-#, fuzzy
msgid "Squid did not receive any data for this request."
msgstr "Քեշը ի պատասխան այս հարցումի ոչ մի տվյալ չի ստացել."
"Squid does not support all request methods for all access protocols. For "
"example, you can not POST a Gopher request."
msgstr ""
-"Squid-ը բոլոր արձանագրությունների համար բոլոր հարցման մեթոդները չի "
-"ուղեկցում . Օրինակ,Gopher արձանագրության համար չեք կարող POST հարցում "
-"կատարել. "
+"Squid-ը բոլոր արձանագրությունների համար բոլոր հարցման մեթոդները չի աջակցում. "
+"Օրինակ, Gopher արձանագրության համար չեք կարող POST հարցում կատարել."
#: templates/ERR_LIFETIME_EXP:6
msgid ""
"connection lifetime."
msgstr ""
"Squid-ը ընդհատեց հարցումը կապ հաստատման առավելագույն ժամանակը գերազանցելու "
-"պատճառով․."
+"պատճառով"
#: templates/ERR_SOCKET_FAILURE:7
msgid ""
"Squid is unable to create a TCP socket, presumably due to excessive load. "
"Please retry your request."
msgstr ""
-"Squid-ը չի կարող ստեղծել TCP Socket, հավանաբար գերբեռնվածության պատճառով․"
-"Խնդրվում է կրկնել հարցումը․ Եթե իրավիճակը կրկնվի, դիմեք քեշի կառավարիչին․ "
+"Squid-ը չի կարող ստեղծել TCP Socket, հավանաբար գերբեռնվածության պատճառով: "
+"Խնդրվում է կրկնել հարցումը: Եթե իրավիճակը կրկնվի, դիմեք քեշի կառավարիչին․:"
#: templates/ERR_FTP_FAILURE:5 templates/ERR_FTP_FORBIDDEN:5
#: templates/ERR_FTP_NOT_FOUND:5 templates/ERR_FTP_PUT_ERROR:5
#: templates/ERR_FTP_UNAVAILABLE:5
msgid "Squid sent the following FTP command:"
-msgstr "Squid-ը ուղարկեց հետևյալ FTP հրամանը: "
+msgstr "Squid-ը ուղարկեց հետևյալ FTP հրամանը:"
#: templates/ERR_DNS_FAIL:6
msgid "The DNS server returned:"
-msgstr "DNS սերվերի պատասխանը: "
+msgstr "DNS սերվերի պատասխանը:"
#: templates/ERR_ESI:6
+#, fuzzy
msgid "The ESI processor returned:"
-msgstr ""
+msgstr "ESI պրոցեսորը պատասխանեց:"
#: templates/ERR_FTP_UNAVAILABLE:4
-#, fuzzy
msgid "The FTP server was too busy to retrieve the URL: <a href=\"%U\">%U</a>"
-msgstr ""
-"URL-ի առաքման ժամանակ FTP սերվերը շատ զբաղված էր: <a href=\"%U\">%U</a>"
+msgstr "URL-ի ստացման ընթացքում FTP սերվերը շատ զբաղված էր: <a href=\"%U\">%U</a>"
#: templates/ERR_INVALID_RESP:5
-#, fuzzy
msgid ""
"The HTTP Response message received from the contacted server could not be "
"understood or was otherwise malformed. Please contact the site operator."
msgstr ""
-"Սերվերից ստացվող պատասխանն անհասկանալի է կամ այլայլված․Դիմեք տվյալ կայքի "
-"կառավարիչներին։Ձեր քեշի կառավարիչը անհրաժեշտության դեպքում կարող է ավելի "
-"մանրակրկիտ նկարագրել խնդրի բնւյթը."
+"Սերվերից ստացվող պատասխանն անհասկանալի է կամ այլայլված: Դիմեք տվյալ կայքի "
+"կառավարիչներին։ Ձեր քեշի կառավարիչը անհրաժեշտության դեպքում կարող է ավելի "
+"մանրակրկիտ նկարագրել խնդրի բնւյթը:"
#: templates/ERR_ICAP_FAILURE:9
msgid "The ICAP server is not reachable."
-msgstr ""
+msgstr "ICAP սերվերը անհասանելի է:"
#: templates/ERR_FTP_NOT_FOUND:4
msgid "The following URL could not be retrieved: <a href=\"%U\">%U</a>"
-msgstr "Հետևյալ URL չի կարող առաքվել: <a href=\"%U\">%U</a>"
+msgstr "Հետևյալ URL-ն հնարավոր չէ ստանալ: <a href=\"%U\">%U</a>"
#: templates/ERR_ACCESS_DENIED:4 templates/ERR_CACHE_ACCESS_DENIED:4
#: templates/ERR_CACHE_MGR_ACCESS_DENIED:4 templates/ERR_CANNOT_FORWARD:4
msgid ""
"The following error was encountered while trying to retrieve the URL: <a "
"href=\"%U\">%U</a>"
-msgstr ""
+msgstr "URL-ի ստացման ընթացքում առաջացավ հետևյալ սխալը: <a href=\"%U\">%U</a>"
#: templates/ERR_URN_RESOLVE:4
msgid ""
"The following error was encountered while trying to retrieve the URN: <a "
"href=\"%U\">%U</a>"
-msgstr ""
+msgstr "URN-ի ստացման ընթացքում առաջացավ հետևյալ սխալը: <a href=\"%U\">%U</a>"
#: templates/ERR_CONNECT_FAIL:7
-#, fuzzy
msgid "The remote host or network may be down. Please try the request again."
-msgstr ""
-"Հեռակա հանգույցը կամ ցանցը չեն պատասխանում. Խնդրվում է կրկնել հարցումը. "
+msgstr "Հեռակա հանգույցը կամ ցանցը չեն պատասխանում: Խնդրվում է կրկնել հարցումը:"
#: templates/ERR_TOO_BIG:5
msgid "The request or reply is too large."
-msgstr "Հարցումը կամ պատասխանը շատ մեծ ծավալ ունեն. "
+msgstr "Հարցումը կամ պատասխանը շատ մեծ ծավալ ունեն."
#: templates/ERR_ACCESS_DENIED:3 templates/ERR_CANNOT_FORWARD:3
#: templates/ERR_CONNECT_FAIL:3 templates/ERR_DNS_FAIL:3 templates/ERR_ESI:3
#: templates/ERR_TOO_BIG:3 templates/ERR_UNSUP_REQ:3
#: templates/ERR_WRITE_ERROR:3 templates/ERR_ZERO_SIZE_OBJECT:3
msgid "The requested URL could not be retrieved"
-msgstr "Պահանջվող URL չի կարող առաքվել"
+msgstr "Պահանջվող URL-ն հնարավոր չէ ստանալ"
#: templates/ERR_FTP_FAILURE:6 templates/ERR_FTP_FORBIDDEN:6
#: templates/ERR_FTP_NOT_FOUND:6 templates/ERR_FTP_PUT_ERROR:6
msgstr "Ստացված պատասխանը: <i>%E</i>"
#: templates/ERR_NO_RELAY:6
-#, fuzzy
msgid ""
"There is no WAIS Relay host defined for this Cache! Yell at the "
"administrator."
-msgstr "Այս քեշի համար WAIS Relay որոշված չէ! Հայտնեք կառավարիչին. "
+msgstr "Այս քեշի համար WAIS Relay-ը որոշված չէ! Հայտնեք կառավարիչին:"
#: templates/ERR_TOO_BIG:8
msgid ""
"operates this cache. Please contact them directly if you feel this is an "
"error."
msgstr ""
+"Այս սահմանափակումը իրականացված է Ձեր ինտերնետ կապ ապահովողի կողմից: Եթե Դուք "
+"սա սխալ եք համարում, դիմեք նրան:"
#: templates/ERR_UNSUP_HTTPVERSION:6
msgid "This Squid does not accept the HTTP version you are attempting to use."
msgstr ""
+"HTTP արձանագրության այն տեսակը,որը Դուք փորձում եք օգտագործել,այս Squid-ը չի "
+"ընդունում:"
#: templates/ERR_FTP_DISABLED:6
msgid "This cache does not support FTP."
-msgstr ""
+msgstr "Այս քեշը FTP արձանագրություն չի աջակցում"
#: templates/ERR_SHUTTING_DOWN:5
-#, fuzzy
msgid ""
"This cache is in the process of shutting down and can not service your "
"request at this time. Please retry your request again soon."
msgstr ""
"Այս քեշը տվյալ պահին գտնվում է անջատման պրոցեսում և չի կարող սպասարկել Ձեր "
-"հարցումը․Կրկնեք հարցումը որոշ ժամանակ անց․"
+"հարցումը: Կրկնեք հարցումը որոշ ժամանակ անց:"
#: templates/ERR_FORWARDING_DENIED:6
-#, fuzzy
msgid ""
"This cache will not forward your request because it is trying to enforce a "
"sibling relationship. Perhaps the client at %i is a cache which has been "
"misconfigured."
msgstr ""
"Այս քեշը անկարող է վերահասցեագրել Ձեր հարցումը sibling տիպի "
-"փոխհարաբերություններ հաստատելու պատճառով. Հավանական է,որ %i -ն սխալ "
+"փոխհարաբերություններ հաստատելու պատճառով: Հավանական է, որ %i -ն սխալ "
"սարքաբերված քեշ է."
#: templates/ERR_ICAP_FAILURE:7
msgid "This means that some aspect of the ICAP communication failed."
-msgstr ""
+msgstr "Սա նշանակում է, որ ICAP կոմունիկացիայի որոշ ասպեկտներ սխալ են:"
#: templates/ERR_FTP_PUT_ERROR:7
msgid ""
"This means that the FTP server may not have permission or space to store the "
"file. Check the path, permissions, diskspace and try again."
msgstr ""
+"Սա նշանակում է,որ FTP սերվերը ֆայլը պահպանելու համար բավարար հիշողության "
+"ծավալ կամ թույտվություն չունի: Ստուգեք ճանապարհը, հիշողության ծավալը, մուտքի "
+"իրավունքները և կրկին փորձեք:"
#: templates/ERR_DNS_FAIL:7
-#, fuzzy
msgid ""
"This means that the cache was not able to resolve the hostname presented in "
"the URL. Check if the address is correct."
msgstr ""
-"Սա նշանակում է Քեշը ի վիճակի չէ որոշել URL ում նշված սերվերի հասցեն. Ստուգեք "
-"Õ°Õ¡Õ½Ö\81Õ¥Õ« Õ¶Õ¥Ö\80Õ´Õ¸Ö\82Õ®Õ´Õ¡Õ¶ Õ³Õ·Õ¿Õ¸Ö\82Õ©ÕµÕ¸Ö\82Õ¶Õ¨. "
+"Սա նշանակում է, որ քեշը ի վիճակի չէ որոշել URL- ում նշված սերվերի հասցեն: "
+"Õ\8dÕ¿Õ¸Ö\82Õ£Õ¥Ö\84 Õ°Õ¡Õ½Ö\81Õ¥Õ« Õ¶Õ¥Ö\80Õ´Õ¸Ö\82Õ®Õ´Õ¡Õ¶ Õ³Õ·Õ¿Õ¸Ö\82Õ©ÕµÕ¸Ö\82Õ¶Õ¨:"
#: templates/ERR_ESI:7
msgid ""
"This means that the surrogate was not able to process the ESI template. "
"Please report this error to the webmaster."
msgstr ""
+"Սա նշանակում է, որ փոխարինողը ի վիճակի չէ մշակել ESI կաղապարը:Խնդրվում է "
+"հայտնել այս մասին քեշի կառավարիչին:"
#: templates/ERR_FTP_NOT_FOUND:7
-#, fuzzy
msgid ""
"This might be caused by an FTP URL with an absolute path (which does not "
"comply with RFC 1738). If this is the cause, then the file can be found at "
"<a href=\"%B\">%B</a>."
msgstr ""
-"Õ\8dÕ¡ Õ¯Õ¡Ö\80Õ¸Õ² Õ§ Õ¬Õ«Õ¶Õ¥Õ¬ FTP URL -Õ« Õ¢Õ¡Ö\81Õ¡Ö\80Õ±Õ¡Õ¯ Õ¸Ö\82Õ²Õ²ով հարցման արդյունք (ինչը չի "
-"համապատասխանում RFC 1738-ին). Եթե սա է սխալի պատճառը,ապա ֆայլը կարող է "
+"Õ\8dÕ¡ Õ¯Õ¡Ö\80Õ¸Õ² Õ§ Õ¬Õ«Õ¶Õ¥Õ¬ FTP URL -Õ« Õ¢Õ¡Ö\81Õ¡Ö\80Õ±Õ¡Õ¯ Õ¸Ö\82Õ²Õ«ով հարցման արդյունք (ինչը չի "
+"համապատասխանում RFC 1738-ին). Եթե սա է սխալի պատճառը, ապա ֆայլը կարող է "
"գնտվել այստեղ <a href=\"%B\">%B</a>."
#: templates/ERR_SECURE_CONNECT_FAIL:7
msgstr ""
#: templates/ERR_CANNOT_FORWARD:6
-#, fuzzy
msgid ""
"This request could not be forwarded to the origin server or to any parent "
"caches. The most likely cause for this error is that the cache administrator "
"all configured parent caches are currently unreachable."
msgstr ""
"Այս հարցումը հնարավոր չէ վերահասցեագրել սկզբնաղբյուր սերվերին կամ ծնողական "
-"քեշերից որևէ մեկին․Սխալի ամենահավանական պատճառներն են Այս սերվերի կառավարիչը "
-"Õ¡Ö\80Õ£Õ¥Õ¬Õ¥Õ¬ Õ§ Õ¢Õ¸Õ¬Õ¸Ö\80 Õ¸Ö\82Õ²Õ«Õ² Õ´Õ«Õ¡Ö\81Õ¸Ö\82Õ´Õ¶Õ¥Ö\80Õ¨ Õ½Õ¯Õ¦Õ¢Õ¶Õ¡Õ²Õ¢ÕµÕ¸Ö\82Ö\80 Õ½Õ¥Ö\80Õ¾Õ¥Ö\80Õ¶Õ¥Ö\80Õ« Õ°Õ¥Õ¿ Ô²Õ¸Õ¬Õ¸Ö\80 Õ®Õ¶Õ¸Õ²Õ¡Õ¯Õ¡Õ¶ "
-"քեշերը տվյալ պահին անհասանելի են."
+"քեշերից որևէ մեկին: Սխալի ամենահավանական պատճառներն են` այս սերվերի "
+"Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö\80Õ«Õ¹Õ¨ Õ¡Ö\80Õ£Õ¥Õ¬Õ¥Õ¬ Õ§ Õ¢Õ¸Õ¬Õ¸Ö\80 Õ¸Ö\82Õ²Õ«Õ² Õ´Õ«Õ¡Ö\81Õ¸Ö\82Õ´Õ¶Õ¥Ö\80Õ¨ Õ½Õ¯Õ¦Õ¢Õ¶Õ¡Õ²Õ¢ÕµÕ¸Ö\82Ö\80 Õ½Õ¥Ö\80Õ¾Õ¥Ö\80Õ¶Õ¥Ö\80Õ« Õ°Õ¥Õ¿ Õ¯Õ¡Õ´ "
+"բոլոր ծնողական քեշերը տվյալ պահին անհասանելի են:"
#: templates/ERR_AGENT_CONFIGURE:10 templates/ERR_AGENT_WPAD:9
msgid ""
"Tools -> Internet Options -> Connection -> LAN Settings ->Proxy"
msgstr ""
+"Գործիքներ -> Ինտերնետ կարգաբերումներ -> Կապ -> LAN կարգաբերումներ "
+"->Պրոքսի"
#: templates/ERR_AGENT_CONFIGURE:7 templates/ERR_AGENT_WPAD:7
msgid ""
"Tools -> Options -> Advanced -> Network -> Connection Settings"
msgstr ""
+"Գործիքներ -> Կարգաբերումներ -> Լրացուցիչ -> Ցանց -> Կապի "
+"կարգաբերումներ"
#: templates/ERR_AGENT_CONFIGURE:13 templates/ERR_AGENT_WPAD:12
msgid ""
"Tools -> Preferences -> Advanced -> Network -> Proxy Servers"
msgstr ""
+"Գործիքներ -> Նախընտրություններ -> Լրացուցիչ -> Ցանց -> Պրոքսի "
+"սերվերներ"
#: templates/ERR_DNS_FAIL:5
msgid "Unable to determine IP address from host name <q>%H</q>"
#: templates/ERR_CANNOT_FORWARD:5
msgid "Unable to forward this request at this time."
-msgstr "Õ\80Õ¶Õ¡Ö\80Õ¡Õ¾Õ¸Ö\80 Õ¹Õ§ Õ¾Õ¥Ö\80Õ¡Õ°Õ¡Õ½Ö\81Õ¥Õ¡Õ£Ö\80Õ¥Õ¬ Õ\81Õ¥Ö\80 Õ°Õ¡Ö\80Ö\81Õ¸Ö\82Õ´Õ¨ Õ¿Õ¾ÕµÕ¡Õ¬ ÕºÕ¡Õ°Õ«Õ¶."
+msgstr "Õ\81Õ¥Ö\80 Õ°Õ¡Ö\80Ö\81Õ¸Ö\82Õ´Õ¨ Õ°Õ¶Õ¡Ö\80Õ¡Õ¾Õ¸Ö\80 Õ¹Õ§ Õ¾Õ¥Ö\80Õ¡Õ°Õ¡Õ½Ö\81Õ¥Õ¡Õ£Ö\80Õ¥Õ¬ Õ¿Õ¾ÕµÕ¡Õ¬ ÕºÕ¡Õ°Õ«Õ¶"
#: templates/ERR_UNSUP_HTTPVERSION:3 templates/ERR_UNSUP_HTTPVERSION:5
msgid "Unsupported HTTP version"
-msgstr ""
+msgstr "HTTP արձանագրության այս վարկածը չի աջակցվում"
#: templates/ERR_UNSUP_REQ:5
msgid "Unsupported Request Method and Protocol"
-msgstr "Õ\89Õ¸Ö\82Õ²Õ¥Õ¯Ö\81Õ¾Õ¸Õ² Õ´Õ¥Õ©Õ¸Õ¤ Ö\87 Õ°Õ¡Ö\80Ö\81Õ´Õ¡Õ¶ Õ¡Ö\80Õ±Õ¡Õ¶Õ¡Õ£Ö\80Õ¸Ö\82Õ©ÕµÕ¸Ö\82Õ¶ "
+msgstr "Õ\80Õ¡Ö\80Ö\81Õ¸Ö\82Õ´ Õ«Ö\80Õ¡Õ¯Õ¡Õ¶Õ¡Ö\81Õ¶Õ¥Õ¬Õ¸Ö\82 Õ´Õ¥Õ©Õ¸Õ¤Õ¨ Ö\87 Õ¡Ö\80Õ±Õ¡Õ¶Õ¡Õ£Ö\80Õ¸Ö\82Õ©ÕµÕ¸Ö\82Õ¶Õ¨ Õ¹Õ¥Õ¶ Õ¡Õ»Õ¡Õ¯Ö\81Õ¾Õ¸Ö\82Õ´"
#: templates/ERR_ONLY_IF_CACHED_MISS:5
msgid ""
#: templates/ERR_AGENT_CONFIGURE:1 templates/ERR_AGENT_CONFIGURE:3
#: templates/ERR_AGENT_WPAD:1 templates/ERR_AGENT_WPAD:3
msgid "Web Browser Configuration"
-msgstr ""
+msgstr "Վեբ բրաուզերի կարգաբերումներ"
#: templates/ERR_WRITE_ERROR:5
msgid "Write Error"
-msgstr "Գրանցման սխալ "
+msgstr "Գրանցման սխալ"
#: templates/ERR_ONLY_IF_CACHED_MISS:6
msgid ""
"directive. The document was not found in the cache, <em>or</em> it required "
"revalidation prohibited by the <q>only-if-cached</q> directive."
msgstr ""
+"Դուք իրականացրեցիք հարցում <q>only-if-cached</q> քեշի կառավարման դիրեկտիվով: "
+"Փաստաթուղթը քեշում բացակայում է <em>կամ</em պահանջվում է <q>only-if-"
+"cached</q> դիրեկտիվի կողմից արգելված հաստատում:"
#: templates/ERR_AGENT_CONFIGURE:4 templates/ERR_AGENT_WPAD:4
msgid ""
"Your Web Browser configuration needs to be corrected to use this network."
-msgstr ""
+msgstr "Այս ցանցից օգտվելու համար Ձեր բրաուզերը անհրաժեշտ է կարգաբերել"
#: templates/ERR_ACCESS_DENIED:7 templates/ERR_AGENT_CONFIGURE:15
#: templates/ERR_AGENT_WPAD:14 templates/ERR_CANNOT_FORWARD:7
msgstr "Ձեր քեշի կառավարիչը <a href=\"mailto:%w%W\">%w</a> է."
#: templates/ERR_INVALID_RESP:6
-#, fuzzy
msgid ""
"Your cache administrator may be able to provide you with more details about "
"the exact nature of the problem if needed."
msgstr ""
-"Սերվերից ստացվող պատասխանն անհասկանալի է կամ այլայլված․Դիմեք տվյալ կայքի "
+"Սերվերից ստացվող պատասխանն անհասկանալի է կամ այլայլված: Դիմեք տվյալ կայքի "
"կառավարիչներին։ Ձեր քեշի կառավարիչը անհրաժեշտության դեպքում կարող է ավելի "
-"մանրակրկիտ նկարագրել խնդրի բնւյթը. "
+"մանրակրկիտ նկարագրել խնդրի բնւյթը:"
#: templates/ERR_ESI:8
msgid "Your webmaster is <a href=\"mailto:%w\">%w</a>."
-msgstr ""
+msgstr "Ձեր կայքի կառավարիչը <a href=\"mailto:%w\">%w</a>"
#: templates/ERR_ZERO_SIZE_OBJECT:5
msgid "Zero Sized Reply"
-msgstr "Զրոյական երկարությամբ պատասխան "
+msgstr "Զրոյական երկարությամբ պատասխան"
#~ msgid "ERROR: The requested URN not be retrieved"
#~ msgstr "ՍԽԱԼ: Պահանջվող URN չի կարող առաքվել"
msgstr "Получен <b>недопустимый ответ</b> при попытке обработки запроса:"
#: templates/ERR_READ_TIMEOUT:7
-#, fuzzy
msgid ""
"A Timeout occurred while waiting to read data from the network. The network "
"or server may be down or congested. Please retry your request."
msgstr ""
-"Превышено время ожидания ответа во время чтения данных из сети. Сеть или "
-"Ñ\81еÑ\80веÑ\80 не Ñ\80абоÑ\82аÑ\8eÑ\82 либо пеÑ\80егÑ\80Ñ\83женÑ\8b. Ð\9fожалÑ\83йÑ\81Ñ\82а, повÑ\82оÑ\80иÑ\82е запÑ\80оÑ\81."
+"Превышен интервал времени ожидания при получении данных из сети. Сеть или "
+"Ñ\81еÑ\80веÑ\80 могÑ\83Ñ\82 бÑ\8bÑ\82Ñ\8cнедоÑ\81Ñ\82Ñ\83пнÑ\8b или пеÑ\80егÑ\80Ñ\83женÑ\8b. Ð\9fовÑ\82оÑ\80иÑ\82е попÑ\8bÑ\82кÑ\83 позже."
#: templates/ERR_URN_RESOLVE:3
msgid "A URL for the requested URN could not be retrieved"
msgstr "Доступ запрещён."
#: templates/ERR_ACCESS_DENIED:6
-#, fuzzy
msgid ""
"Access control configuration prevents your request from being allowed at "
"this time. Please contact your service provider if you feel this is "
"incorrect."
msgstr ""
-"Настройка контроля доступа не даёт возможности выполнить Ваш запрос в "
-"настоящее время. Пожалуйста, свяжитесь с Вашим администратором кэша, если Вы "
-"считаете это неправильным."
+"Система контроля доступа не позволяет выполнить ваш запрос сейчас. "
+"Обратитесь к вашему администратору."
#: templates/ERR_FTP_FORBIDDEN:4
msgid ""
msgstr "Получен недопустимый ответ от сервера ICAP."
#: templates/ERR_READ_ERROR:7
-#, fuzzy
msgid ""
"An error condition occurred while reading data from the network. Please "
"retry your request."
-msgstr ""
-"При попытке чтения данных из сети произошла ошибка. Пожалуйста, повторите "
-"запрос."
+msgstr "Ошибка при получении данных их сети. Повторите запрос."
#: templates/ERR_WRITE_ERROR:7
-#, fuzzy
msgid ""
"An error condition occurred while writing to the network. Please retry your "
"request."
-msgstr ""
-"При попытке отправки данных в сеть произошла ошибка. Пожалуйста, повторите "
-"Ваш запрос."
+msgstr "Ошибка отправки данных. Повторите запрос"
#: templates/ERR_CACHE_ACCESS_DENIED:3 templates/ERR_CACHE_ACCESS_DENIED:5
msgid "Cache Access Denied."
msgstr "ОШИБКА: Запрошенный URL не может быть получен"
#: templates/ERR_URN_RESOLVE:1
-#, fuzzy
msgid "ERROR: The requested URN could not be retrieved"
-msgstr "ОШИБКА: Запрошенный URL не может быть получен"
+msgstr "ERROR: Запрошеный URN не может быть получен"
#: templates/ERR_ESI:5
msgid "ESI Processing failed."
msgstr "Обработка ESI не удалась."
#: templates/ERR_FTP_PUT_CREATED:1 templates/ERR_FTP_PUT_MODIFIED:1
-#, fuzzy
msgid "FTP PUT Successful."
-msgstr "Ð\9aоманда FTP PUT завеÑ\80Ñ\88илаÑ\81Ñ\8c Ñ\83Ñ\81пеÑ\88но: Ñ\84айл Ñ\81оздан"
+msgstr "Ð\9aопиÑ\80ование локалÑ\8cного Ñ\84айла на FTP-Ñ\81еÑ\80веÑ\80 меÑ\82одом PUT завеÑ\80Ñ\88ено."
#: templates/ERR_FTP_PUT_ERROR:3
-#, fuzzy
msgid "FTP PUT upload failed"
-msgstr "Команда FTP PUT (отправка) завершилась аварийно"
+msgstr ""
+"Произошла ошибка во время копирования локального файла на FTP-сервер методом "
+"PUT."
#: templates/ERR_FTP_DISABLED:5
msgid "FTP is Disabled"
#: templates/ERR_AGENT_CONFIGURE:6 templates/ERR_AGENT_WPAD:6
msgid "For Firefox browsers go to: <ul>"
-msgstr ""
+msgstr "Для браузера Firefox перейдите в: <ul>"
#: templates/ERR_AGENT_CONFIGURE:9 templates/ERR_AGENT_WPAD:8
msgid "For Internet Explorer browsers go to: <ul>"
-msgstr ""
+msgstr "Для браузера Internet Explorer перейдите в: <ul>"
#: templates/ERR_AGENT_CONFIGURE:12 templates/ERR_AGENT_WPAD:11
msgid "For Opera browsers go to: <ul>"
-msgstr ""
+msgstr "Для браузера Opera перейдите в: <ul>"
#: templates/ERR_FORWARDING_DENIED:5
msgid "Forwarding Denied."
#: templates/ERR_AGENT_CONFIGURE:5 templates/ERR_AGENT_WPAD:5
msgid "How to find these settings in your browser:"
-msgstr ""
+msgstr "Эти настройки в вашем браузере:"
#: templates/ERR_ICAP_FAILURE:5
msgid "ICAP protocol error."
"Для этого кэша не определен узел Wais Relay. Обратитесь к администратору."
#: templates/ERR_TOO_BIG:8
-#, fuzzy
msgid ""
"These limits have been established by the Internet Service Provider who "
"operates this cache. Please contact them directly if you feel this is an "
"error."
msgstr ""
-"Эти ограничения установлены администратором, который управляет этим кэшем. "
-"Ð\9fожалÑ\83йÑ\81Ñ\82а, Ñ\81вÑ\8fжиÑ\82еÑ\81Ñ\8c Ñ\81 ним, еÑ\81ли Ð\92Ñ\8b Ñ\81Ñ\87иÑ\82аеÑ\82е Ñ\8dÑ\82о непÑ\80авилÑ\8cнÑ\8bм."
+"Эти ограничения были установлены администратором. Свяжитесь с ним для "
+"полÑ\83Ñ\87ениÑ\8f инÑ\84оÑ\80маÑ\86ии."
#: templates/ERR_UNSUP_HTTPVERSION:6
msgid "This Squid does not accept the HTTP version you are attempting to use."
msgstr "Этот кэш не поддерживает протокол FTP."
#: templates/ERR_SHUTTING_DOWN:5
-#, fuzzy
msgid ""
"This cache is in the process of shutting down and can not service your "
"request at this time. Please retry your request again soon."
msgstr ""
-"ÐÑ\82оÑ\82 кÑ\8dÑ\88 наÑ\85одиÑ\82Ñ\81Ñ\8f в пÑ\80оÑ\86еÑ\81Ñ\81е завеÑ\80Ñ\88ениÑ\8f Ñ\80абоÑ\82Ñ\8b и не можеÑ\82 вÑ\8bполниÑ\82Ñ\8c Ð\92аÑ\88 "
-"запÑ\80оÑ\81 в наÑ\81Ñ\82оÑ\8fÑ\89ее вÑ\80емÑ\8f. Ð\9fожалÑ\83йÑ\81Ñ\82а, повÑ\82оÑ\80иÑ\82е запÑ\80оÑ\81 Ñ\87еÑ\80ез некÑ\82оÑ\80ое вÑ\80емÑ\8f."
+"СеÑ\80веÑ\80 в даннÑ\8bй моменÑ\82 вÑ\8bклÑ\8eÑ\87аеÑ\82Ñ\81Ñ\8f и не можеÑ\82 вÑ\8bполниÑ\82Ñ\8c ваÑ\88 запÑ\80оÑ\81. "
+"Ð\9fовÑ\82оÑ\80иÑ\82е попÑ\8bÑ\82кÑ\83 позже."
#: templates/ERR_FORWARDING_DENIED:6
#, fuzzy
"сообщите об этой ошибке веб-мастеру."
#: templates/ERR_FTP_NOT_FOUND:7
-#, fuzzy
msgid ""
"This might be caused by an FTP URL with an absolute path (which does not "
"comply with RFC 1738). If this is the cause, then the file can be found at "
"<a href=\"%B\">%B</a>."
msgstr ""
-"ÐÑ\82о можеÑ\82 бÑ\8bÑ\82Ñ\8c вÑ\8bзвано FTP URL c абÑ\81олÑ\8eÑ\82нÑ\8bм пÑ\83Ñ\82Ñ\91м (коÑ\82оÑ\80Ñ\8bй не соответствует "
-"RFC 1738). Ð\95Ñ\81ли Ñ\8dÑ\82а пÑ\80иÑ\87ина веÑ\80на, Ñ\82о Ñ\84айл можно найÑ\82и по адÑ\80еÑ\81Ñ\83 <a href=\"%B"
-"\">%B</a>."
+"ÐÑ\82о могло пÑ\80оизойÑ\82и из-за абÑ\81олÑ\8eÑ\82ной Ñ\81Ñ\81Ñ\8bлки на FTP (коÑ\82оÑ\80аÑ\8f не соответствует "
+"RFC 1738). Ð\92 Ñ\8dÑ\82ом Ñ\81лÑ\83Ñ\87ае Ñ\84айл можеÑ\82 бÑ\8bÑ\82Ñ\8c полÑ\83Ñ\87ен по адÑ\80еÑ\81Ñ\83 <a href=\"%B\">%"
+"B</a>."
#: templates/ERR_SECURE_CONNECT_FAIL:7
msgid ""
"удостоверением безопасности узла."
#: templates/ERR_CANNOT_FORWARD:6
-#, fuzzy
msgid ""
"This request could not be forwarded to the origin server or to any parent "
"caches. The most likely cause for this error is that the cache administrator "
"does not allow this cache to make direct connections to origin servers, and "
"all configured parent caches are currently unreachable."
msgstr ""
-"Этот запрос не может быть перенаправлен ни к первичному серверу, ни к "
-"родительским кэшам. Наиболее вероятная причина этой ошибки в том, что "
-"администратор запретил прямые соединения к первичным серверам, а все "
-"указанные родительские кэши в данный момент недоступны."
+"Запрос не может быть направлен на сервер-источник файла или на любой "
+"вышестоящий кэширующий прокси-сервер. Наиболее вероятной причиной этой "
+"ошибки является то, что кэш-администратор запретил подключаться к серверам "
+"интернета напрямую, а все вышестоящие кэширующие прокси-серверы в данный "
+"момент не доступны."
#: templates/ERR_AGENT_CONFIGURE:10 templates/ERR_AGENT_WPAD:9
msgid ""
"Tools -> Internet Options -> Connection -> LAN Settings ->Proxy"
msgstr ""
+"Инструменты -> Настройки интернета -> Соединения -> Настройки LAN "
+"-> Прокси"
#: templates/ERR_AGENT_CONFIGURE:7 templates/ERR_AGENT_WPAD:7
msgid ""
"Tools -> Options -> Advanced -> Network -> Connection Settings"
msgstr ""
+"Инструменты -> Опции -> Дополнительно -> Сеть -> Настойки "
+"соединения"
#: templates/ERR_AGENT_CONFIGURE:13 templates/ERR_AGENT_WPAD:12
msgid ""
"Tools -> Preferences -> Advanced -> Network -> Proxy Servers"
msgstr ""
+"Инструменты -> Настройки -> Дополнительно -> Сеть -> "
+"Прокси-серверы"
#: templates/ERR_DNS_FAIL:5
msgid "Unable to determine IP address from host name <q>%H</q>"
#: templates/ERR_AGENT_CONFIGURE:1 templates/ERR_AGENT_CONFIGURE:3
#: templates/ERR_AGENT_WPAD:1 templates/ERR_AGENT_WPAD:3
msgid "Web Browser Configuration"
-msgstr ""
+msgstr "Настройки браузера"
#: templates/ERR_WRITE_ERROR:5
msgid "Write Error"
msgid ""
"Your Web Browser configuration needs to be corrected to use this network."
msgstr ""
+"Необходимо произвести настройку вашего браузера для использования этой сети"
#: templates/ERR_ACCESS_DENIED:7 templates/ERR_AGENT_CONFIGURE:15
#: templates/ERR_AGENT_WPAD:14 templates/ERR_CANNOT_FORWARD:7
-DIST_SUBDIRS = AD_group file_userip LDAP_group LM_group session unix_group wbinfo_group
-SUBDIRS = $(EXTERNAL_ACL_HELPERS)
+DIST_SUBDIRS= \
+ AD_group \
+ eDirectory_userip \
+ file_userip \
+ kerberos_ldap_group \
+ LDAP_group \
+ LM_group \
+ session \
+ unix_group \
+ wbinfo_group
+
+SUBDIRS=$(EXTERNAL_ACL_HELPERS)
+++ /dev/null
-# squid_edir_iplookup - Copyright (C) 2009, 2010 Chad E. Naugle
-#
-#*******************************************************************************
-#
-# Makefile --
-#
-# Builds squid_edir_lookup when run. PORTING NEEDED.
-#
-
-CC = gcc
-LD = gcc
-CFLAGS = -O2 -Wall -Wextra
-PROGNAME = squid_edir_iplookup
-UID = squid
-GID = nogroup
-OBJECTS = main.o iplookup.o util.o
-LIBS = -lldap -llber
-HEADERS = config.h main.h util.h iplookup.h
-
-all: ${PROGNAME}
-
-${PROGNAME}: ${OBJECTS}
- ${LD} ${CFLAGS} -o ${PROGNAME} ${OBJECTS} ${LIBS}
- chmod 0550 ${PROGNAME}
- chown ${UID} ${PROGNAME}
- chgrp ${GID} ${PROGNAME}
-
-clean:
- rm -f *.o ${PROGNAME}
-
-install: ${PROGNAME}
- cp ${PROGNAME} /usr/sbin
-
-main.o: ${HEADERS} main.c
- ${CC} ${CFLAGS} -c main.c
-
-iplookup.o: ${HEADERS} iplookup.c
- ${CC} ${CFLAGS} -c iplookup.c
-
-util.o: ${HEADERS} util.c
- ${CC} ${CFLAGS} -c util.c
--- /dev/null
+include $(top_srcdir)/src/Common.am
+
+libexec_PROGRAMS = ext_edirectory_userip_acl
+
+ext_edirectory_userip_acl_SOURCES = \
+ edui_config.h main.h edui_util.h iplookup.h \
+ main.c edui_util.c iplookup.c
+
+ext_edirectory_userip_acl_LDADD = \
+ $(COMPAT_LIB) \
+ $(LDAPLIB) \
+ $(LBERLIB) \
+ $(XTRA_LIBS)
+
+EXTRA_DIST = config.test README ISSUES INSTALL
--- /dev/null
+#!/bin/sh
+
+# AYJ: currently does not build portable
+exit 1
+
+if [ -f /usr/include/ldap.h ]; then
+ exit 0
+fi
+if [ -f /usr/include/winldap.h ]; then
+ exit 0
+fi
+exit 1
#define _HAVE_CONFIG_H
/* Default program name */
-#define DEFAULT_PROGRAM_NAME "squid_edir_iplookup"
+#define DEFAULT_PROGRAM_NAME "ext_edirectory_userip_acl"
/* Hostname or IP address of LDAP server, default is IPv4 localhost (127.0.0.1) */
/* #define DEFAULT_LDAP_HOST */
*/
#include "main.h"
-#include "util.h"
+#include "edui_util.h"
/* debug() -
*
*/
#include "main.h"
-#include "util.h"
+#include "edui_util.h"
#include "iplookup.h"
/* InitLDAP() - <ldap_t>
*/
#include "main.h"
-#include "util.h"
+#include "edui_util.h"
#include "iplookup.h"
char *search_attrib[] = { "cn", "uid", "networkAddress", "groupMembership", NULL };
conf.mode = 0;
conf.mode |= MODE_INIT;
- /* Set defaults from config.h */
+ /* Set defaults from edui_config.h */
#ifdef DEFAULT_BASE_DN
strcpy(conf.basedn, DEFAULT_BASE_DN);
#endif
#ifndef _HAVE_MAIN_H
#define _HAVE_MAIN_H
-#ifndef _HAVE_CONFIG_H
#include "config.h"
-#endif
+#include "edui_config.h"
#ifndef DEFAULT_PROGRAM_NAME
-#define DEFAULT_PROGRAM_NAME "squid_edir_iplookup"
+#define DEFAULT_PROGRAM_NAME "ext_edirectory_iuserp_acl"
#endif
/* Must ... include ... these ... */
--- /dev/null
+include $(top_srcdir)/src/Common.am
+
+EXTRA_DIST = README config.test cert_tool ext_kerberos_ldap_group_acl.8
+SUBDIRS =
+
+AM_CPPFLAGS = $(INCLUDES) -I$(srcdir)
+
+libexec_SCRIPTS = cert_tool
+
+libexec_PROGRAMS = ext_kerberos_ldap_group_acl
+
+ext_kerberos_ldap_group_acl_SOURCES = \
+ kerberos_ldap_group.cc \
+ support.h \
+ support_group.cc \
+ support_netbios.cc \
+ support_member.cc \
+ support_krb5.cc \
+ support_ldap.cc \
+ support_sasl.cc \
+ support_resolv.cc \
+ support_log.cc
+
+ext_kerberos_ldap_group_acl_LDFLAGS =
+ext_kerberos_ldap_group_acl_LDADD = \
+ $(COMPAT_LIB) \
+ $(LDAPLIB) \
+ $(LBERLIB) \
+ $(LIBSASL) \
+ $(KRB5LIBS) \
+ $(XTRA_LIBS)
--- /dev/null
+--------------------------------------------------------------------------------
+readme.txt is the squid_kerb_ldap read-me file.
+
+Author: Markus Moeller (markus_moeller at compuserve.com)
+
+Copyright (C) 2007 Markus Moeller. All rights reserved.
+--------------------------------------------------------------------------------
+
+squid_kerb_ldap Read Me
+
+Markus Moeller
+June 2, 2007
+
+1 Introduction
+
+squid_kerb_ldap is a reference implementation that supports SASL/GSSAPI authentication
+to an ldap server. It is mainly intended to connect to Active Directory or Openldap based
+ldap servers.
+
+For AD it checks the memberof attribute to determine if a user is member of a group.
+For non AD it checks the memberuid attribute to determine if a user is member of a group and if not it checks if the primary group matches.
+Currently, squid_kerb_ldap supports Squid 2.6 on Linux.
+
+squid_auth_ldap requires either MIT or Heimdal Kerberos libraries and header files.
+
+2 Building and Installation
+
+./configure
+make
+
+Copy the helper squid_kerb_ldap to an apropriate directory.
+
+3 Configuration
+
+a) Configure IE or Firefox to point to the squid proxy by using the fqdn. IE and Firefox will use the
+fqdn to query for a HTTP/fqdn Kerberos service principal.
+
+b) Create a keytab which contains the HTTP/fqdn Kerberos service principal and place it into a directory
+where the squid run user can read the keytab.
+
+c) Add the following line to squid.conf
+
+auth_param negotiate program /usr/sbin/squid_kerb_auth
+auth_param negotiate children 10
+auth_param negotiate keep_alive on
+
+external_acl_type squid_kerb_ldap ttl=3600 negative_ttl=3600 %LOGIN /usr/sbin/squid_kerb_ldap -g GROUP@
+acl ldap_group_check external squid_kerb_ldap
+http_access allow ldap_group_check
+
+If a ntlm helper is used too add a -N option to map the netbios name to a Kerberos realm e.g.
+
+external_acl_type squid_kerb_ldap ttl=3600 negative_ttl=3600 %LOGIN /usr/sbin/squid_kerb_ldap -g GROUP@ -N NETBIOS@KERBEROS.REALM
+acl ldap_group_check external squid_kerb_ldap
+http_access allow ldap_group_check
+
+
+d) Modify squid startup file
+
+Add the following lines to the squid startup script to point squid to a keytab file which
+contains the HTTP/fqdn service principal for the default Kerberos domain. The fqdn must be
+the proxy name set in IE or firefox. You can not use an IP address.
+
+KRB5_KTNAME=/etc/squid/HTTP.keytab
+export KRB5_KTNAME
+
+If you use a different Kerberos domain than the machine itself is in you can point squid to
+the seperate Kerberos config file by setting the following environmnet variable in the startup
+script.
+
+KRB5_CONFIG=/etc/krb5-squid.conf
+export KRB5_CONFIG
+
+4 Miscellaneous
+
+The -i options creates informational messages whereas -d creates full debug output
+
+If squid_kerb_ldap doesn't determine for some reason the right service ldap server you can provide
+it with -u BIND_DN -p BIND_PW -b BIND_PATH -l LDAP_URL
+
+STARTTLS/SSL is supported and the -a options disables server certificate checks
+
+If you serve multiple Kerberos realms add a HTTP/fqdn@REALM service principal per realm to the
+HTTP.keytab file and use the -s GSS_C_NO_NAME option with squid_kerb_auth.
+
+squid_kerb_ldap will determine automagically the right ldap server. The following method is used:
+
+1) For user@REALM
+ 1) Query DNS for SRV record _ldap._tcp.REALM
+ 2) Query DNS for A record REALM
+ 3) Use LDAP_URL if given
+
+2) For user
+ 2) Use LDAP_URL if given
+
+The Groups to check against are determined as follows:
+
+1 For user@REALM
+ 1) Use values given by -g option which contain a @REALM e.g. -g GROUP1@REALM:GROUP2@REALM
+ 2) Use values given by -g option which contain a @ only e.g. -g GROUP1@:GROUP2@
+ 3) Use values given by -g option which do not contain a realm e.g. -g GROUP1:GROUP2
+
+1 For user
+ 3) Use values given by -g option which do not contain a realm e.g. -g GROUP1:GROUP2
+
+
+To support Non-ASCII character use -t <GROUP> or -t <GROUP>@<REALM> instead of -g where GROUP is the hex UTF-8 representation e.g.
+
+ -t 6d61726b7573 instead of -g markus
+
+The REALM must still be based on the ASCII character set. If REALM contains also non ASCII characters use -T <GROUP>@<REALM> where GROUP and REALM are hex UTF-8 representation e.g.
+
+ -T 6d61726b7573@57494e3230303352322e484f4d45 instead of -g markus@WIN2003R2.HOME
+
+For a translation of hex UTF-8 see for example http://www.utf8-chartable.de/unicode-utf8-table.pl
+
+
+
+
--- /dev/null
+#!/bin/ksh
+#
+# -----------------------------------------------------------------------------
+#
+# Author: Markus Moeller (markus_moeller at compuserve.com)
+#
+# Copyright (C) 2007 Markus Moeller. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+# -----------------------------------------------------------------------------
+#
+#
+# creates the following files:
+# <server>.cert
+# secmod.db
+# key3.db
+# cert8.db
+#
+#
+if [ -z "$1" ]; then
+ echo "Usage: `basename $0` ldap-server port"
+ exit 0
+fi
+if [ -z "$2" ]; then
+ port=636
+else
+ port=$2
+fi
+
+server=$1
+
+#
+# Remove old files
+#
+rm ${server}_[0-9]*.cert 2>/dev/null
+#
+# Get certs and store in .cert file
+#
+( openssl s_client -showcerts -connect $server:$port 2>/dev/null <<!
+QUIT
+!
+) | awk 'BEGIN{start=0;ostart=0}{if ( $0 ~ /BEGIN CERTIFICATE/ ) { start=start+1 };
+ if ( start > ostart ) {print $0 >>"'$server'_"start".cert"};
+ if ( $0 ~ /END CERTIFICATE/) { ostart=start } }'
+
+#
+# from mozilla-nss-tools
+# /usr/sfw/bin on Solaris
+#
+#
+# Create database for Sun ldap and pem file for Openldap
+#
+rm ${server}_[0-9]*.pem 2>/dev/null
+let i=0
+ ls ${server}_[0-9]*.cert | while read file; do
+ let i=i+1
+ cat $file >> ${server}_$i.pem
+ CA=`openssl x509 -noout -text -in ${server}_$i.pem | grep -i "CA:.*true"`
+ if [ -n "$CA" ]; then
+ echo "CA is in ${server}_$i.pem"
+ certutil -A -a -n "${server}_$i" -i $file -t "C,," -d .
+ else
+ certutil -A -a -n "${server}_$i" -i $file -t "P,," -d .
+ fi
+ rm $file
+done
+echo "Certs:"
+certutil -d . -L
+echo "are in"
+ls *.db
--- /dev/null
+#!/bin/sh
+# Don't build without gssapi.h
+if [ -f /usr/include/ldap.h -o -f /usr/local/include/ldap.h ]; then
+ # Won't link without SASL as well
+ if [ -f /usr/include/sasl.h -o -f /usr/include/sasl/sasl.h ]; then
+ if [ -f /usr/lib/libsasl.a -o -f /usr/lib/libsasl2.a ]; then
+ exit 0
+ fi
+ if [ -f /usr/lib/libsasl.la -o -f /usr/lib/libsasl2.la ]; then
+ exit 0
+ fi
+ fi
+fi
+exit 1
--- /dev/null
+.if !'po4a'hide' .TH ext_kerberos_ldap_group_acl 8
+.
+.SH NAME
+.if !'po4a'hide' .B ext_kerberos_ldap_group_acl
+.if !'po4a'hide' \-
+Squid LDAP external acl group helper for Kerberos or NTLM credentials.
+.PP
+Version 1.2.2sq
+.
+.SH SYNOPSIS
+.if !'po4a'hide' .B ext_kerberos_ldap_group_acl
+.if !'po4a'hide' .B [\-h] [\-d] [\-i] [\-s] [\-a] [\-D Realm ] [\-N Netbios-Realm-List] [\-m Max-Depth] [\-u Ldap-User] [\-p Ldap-Password] [\-b Ldap-Bind-Path] [\-l Ldap-URL] \-g Group-Realm-List \-t Hex-Group-Realm-List \-T Hex-Group-Hex-Realm-List
+.
+.SH DESCRIPTION
+.B ext_kerberos_ldap_group_acl
+is an installed binary and allows Squid to connect to a LDAP directory to
+authorize users via LDAP groups. Options are specified as parameters on the
+command line, while the username (e.g. user, user@REALM, NDOMAIN\\user) to
+be checked against the LDAP directory are specified on subsequent lines of
+input to the helper, one username per line.
+.PP
+.B ext_kerberos_ldap_group_acl
+will determine the ldap server name from DNS SRV and/or
+A records or a local hosts file (e.g. for the Kerberos Realm SUSE.HOME it
+will look for an SRV record _ldap._tcp.SUSE.HOME and an A record SUSE.HOME
+or a SUSE.HOME hosts entry). If no domain information is available from the
+username the ldap server will be determined through the command line options.
+.PP
+.B ext_kerberos_ldap_group_acl
+requires as a minimum the \-g, \-t or \-T option which
+provides the ldap group name the user has to belong too. For Active Directory
+a recursive group lookup is implemented until a max depth specified by \-m depth.
+For other Ldap servers a RFC2307bis schema of groups is assumed.
+.PP
+Different group names can be specified for different domains using a
+group@domain syntax.
+As expected by the
+.B external_acl_type
+construct of Squid, after
+specifying a username and group followed by a new line, this
+helper will produce either
+.B OK
+or
+.B ERR
+on the following line
+to show if the user is a member of the specified group.
+.
+.SH OPTIONS
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-h
+Display the binary help and command line syntax info using stderr.
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-d
+Write debug messages to stderr.
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-i
+Write informational messages to stderr.
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-s
+Use SSL for the ldap connection.
+.IP
+The CA certificate file can be set via the environment variable TLS_CACERTFILE (default /etc/ssl/certs/cert.pem) (OpenLDAP).
+.IP
+The SSL certificate database can be set via the environment variable SSL_CERTDBPATH (default /etc/certs) (Sun and Mozilla LDAP SDK).
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-a
+Allow SSL without certificate verification.
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-D Realm
+Default Kerberos domain to use for usernames which do not contain domain
+information (e.g. for users using basic authentication).
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-N Netbios-Realm-List
+A list of Netbios name mappings to Kerberos domain names of the form
+Netbios-Name@Kerberos-Realm[:Netbios-Name@Kerberos-Realm] (e.g. for users
+using NTLM authentication).
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-m Max-Depth
+Maximal depth of recursive group search.
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-u Ldap-User
+Username for LDAP server.
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-u Ldap-Password
+Password for LDAP server.
+.IP
+As the password needs to be printed in plain text in your Squid configuration
+it is strongly recommended to use a account with minimal associated privileges.
+This to limit the damage in case someone could get hold of a copy of your Squid
+configuration file or extracts the password used from a process listing.
+.
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-b Ldap-Bind-Path
+LDAP server bind path.
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-u Ldap-URL
+LDAP server URL in form ldap[s]://server:port
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-g Group-Realm-List
+A list of group name per Kerberos domain of the form
+Group|Group@|Group@Realm[:Group@|Group@Realm]
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-t Hex-Group-Realm-List
+A list of group name per Kerberos domain of the
+form Group|Group@|Group@Realm[:Group@|Group@Realm] where group is in
+UTF-8 hex format
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-T Hex-Group-Hex-Realm-List
+A list of group name per Kerberos domain of the form
+Group|Group@|Group@Realm[:Group@|Group@Realm] where group and domain
+is in UTF-8 hex format
+.
+.SH CONFIGURATION
+.PP See FAQ wiki page for examples of how to write configuration snippets. (TBD)
+.PP
+This helper is intended to be used as an
+.B external_acl_type
+helper in
+.B squid.conf.
+.if !'po4a'hide' .P
+.if !'po4a'hide' .ft CR
+.if !'po4a'hide' .nf
+.if !'po4a'hide' external_acl_type kerberos_ldap_group1 ttl=3600 negative_ttl=3600 %LOGIN /path/to/ext_kerberos_ldap_group_acl -g GROUP1
+.if !'po4a'hide' .br
+.if !'po4a'hide' external_acl_type kerberos_ldap_group2 ttl=3600 negative_ttl=3600 %LOGIN /path/to/ext_kerberos_ldap_group_acl -g GROUP2
+.if !'po4a'hide' .br
+.if !'po4a'hide' acl group1 external kerberos_ldap_group1
+.if !'po4a'hide' .br
+.if !'po4a'hide' acl group2 external kerberos_ldap_group2
+.if !'po4a'hide' .fi
+.if !'po4a'hide' .ft
+.PP
+.B NOTE:
+The following squid startup file modification may be required:
+
+Add the following lines to the squid startup script to point squid to a keytab file which
+contains the HTTP/fqdn service principal for the default Kerberos domain. The fqdn must be
+the proxy name set in IE or firefox. You can not use an IP address.
+.if !'po4a'hide' .P
+.if !'po4a'hide' .ft CR
+.if !'po4a'hide' .nf
+.if !'po4a'hide' KRB5_KTNAME=/etc/squid/HTTP.keytab
+.if !'po4a'hide' export KRB5_KTNAME
+.if !'po4a'hide' .fi
+.if !'po4a'hide' .ft
+
+If you use a different Kerberos domain than the machine itself is in you can point squid to
+the seperate Kerberos config file by setting the following environmnet variable in the startup
+script.
+.if !'po4a'hide' .P
+.if !'po4a'hide' .ft CR
+.if !'po4a'hide' .nf
+.if !'po4a'hide' KRB5_CONFIG=/etc/krb5-squid.conf
+.if !'po4a'hide' export KRB5_CONFIG
+.if !'po4a'hide' .fi
+.if !'po4a'hide' .ft
+
+.B ext_kerberos_ldap_group_acl
+will determine automagically the right ldap server. The following method is used:
+
+1) For user@REALM
+ a) Query DNS for SRV record _ldap._tcp.REALM
+ b) Query DNS for A record REALM
+ c) Use LDAP_URL if given
+
+2) For user
+ a) Use domain -D REALM and follow step 1)
+ b) Use LDAP_URL if given
+
+The Groups to check against are determined as follows:
+
+1) For user@REALM
+ a) Use values given by -g option which contain a @REALM e.g. -g GROUP1@REALM:GROUP2@REALM
+ b) Use values given by -g option which contain a @ only e.g. -g GROUP1@:GROUP2@
+ c) Use values given by -g option which do not contain a realm e.g. -g GROUP1:GROUP2
+
+2) For user
+ a) Use values given by -g option which do not contain a realm e.g. -g GROUP1:GROUP2
+
+3) For NDOMAIN\\user
+ a) Use realm given by -N NDOMAIN@REALM and then use values given by -g option which contain a @REALM e.g. -g GROUP1@REALM:GROUP2@REALM
+
+To support Non-ASCII character use -t GROUP or -t GROUP@REALM instead of -g where GROUP is the hex UTF-8 representation e.g.
+
+ -t 6d61726b7573 instead of -g markus
+
+The REALM must still be based on the ASCII character set. If REALM contains also non ASCII characters use -T GROUP@REALM where GROUP and REALM are hex UTF-8 representation e.g.
+
+ -T 6d61726b7573@57494e3230303352322e484f4d45 instead of -g markus@WIN2003R2.HOME
+
+For a translation of hex UTF-8 see for example http://www.utf8-chartable.de/unicode-utf8-table.pl
+
+.
+.SH AUTHOR
+This program was written by
+.if !'po4a'hide' .I Markus Moeller <markus_moeller@compuserve.com>
+.PP
+This manual was written by
+.if !'po4a'hide' .I Markus Moeller <markus_moeller@compuserve.com>
+.
+.SH COPYRIGHT
+This program and documentation is copyright to the authors named above.
+.PP
+Distributed under the GNU General Public License (GNU GPL) version 2 or later (GPLv2+).
+.
+.SH QUESTIONS
+Questions on the usage of this program can be sent to the
+.I Squid Users mailing list
+.if !'po4a'hide' <squid-users@squid-cache.org>
+.
+.SH REPORTING BUGS
+Bug reports need to be made in English.
+See http://wiki.squid-cache.org/SquidFaq/BugReporting for details of what you need to include with your bug report.
+.PP
+Report bugs or bug fixes using http://bugs.squid-cache.org/
+.PP
+Report serious security bugs to
+.I Squid Bugs <squid-bugs@squid-cache.org>
+.PP
+Report ideas for new improvements to the
+.I Squid Developers mailing list
+.if !'po4a'hide' <squid-dev@squid-cache.org>
+.
+.SH SEE ALSO
+.if !'po4a'hide' .BR squid "(8) "
+.if !'po4a'hide' .BR negotiate_kerberos_auth "(8) "
+.br
+.BR RFC1035 " - Domain names - implementation and specification,"
+.br
+.BR RFC2782 " - A DNS RR for specifying the location of services (DNS SRV),"
+.br
+.BR RFC2254 " - The String Representation of LDAP Search Filters,"
+.br
+.BR RFC2307bis " - An Approach for Using LDAP as a Network Information Service
+http://www.padl.com/~lukeh/rfc2307bis.txt,"
+.br
+The Squid FAQ wiki
+.if !'po4a'hide' http://wiki.squid-cache.org/SquidFaq
+.br
+The Squid Configuration Manual
+.if !'po4a'hide' http://www.squid-cache.org/Doc/config/
--- /dev/null
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * Author: Markus Moeller (markus_moeller at compuserve.com)
+ *
+ * Copyright (C) 2007 Markus Moeller. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * As a special exemption, M Moeller gives permission to link this program
+ * with MIT, Heimdal or other GSS/Kerberos libraries, and distribute
+ * the resulting executable, without including the source code for
+ * the Libraries in the source distribution.
+ *
+ * -----------------------------------------------------------------------------
+ */
+/*
+ * Hosted at http://sourceforge.net/projects/squidkerbauth
+ */
+#include "config.h"
+#include "helpers/defines.h"
+#include "util.h"
+
+#ifdef HAVE_LDAP
+
+#include "support.h"
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+void
+init_args(struct main_args *margs)
+{
+ margs->nlist = NULL;
+ margs->glist = NULL;
+ margs->ulist = NULL;
+ margs->tlist = NULL;
+ margs->luser = NULL;
+ margs->lpass = NULL;
+ margs->lbind = NULL;
+ margs->lurl = NULL;
+ margs->ssl = NULL;
+ margs->rc_allow = 0;
+ margs->AD = 0;
+ margs->mdepth = 5;
+ margs->ddomain = NULL;
+ margs->groups = NULL;
+ margs->ndoms = NULL;
+}
+
+void clean_gd(struct gdstruct *gdsp);
+void clean_nd(struct ndstruct *ndsp);
+
+void
+clean_gd(struct gdstruct *gdsp)
+{
+ struct gdstruct *p = NULL, *pp = NULL;
+
+start:
+ p = gdsp;
+ if (!p)
+ return;
+ while (p->next) {
+ pp = p;
+ p = p->next;
+ }
+ if (p->group) {
+ xfree(p->group);
+ p->group = NULL;
+ }
+ if (p->domain) {
+ xfree(p->domain);
+ p->domain = NULL;
+ }
+ if (pp && pp->next) {
+ xfree(pp->next);
+ pp->next = NULL;
+ }
+ if (p == gdsp) {
+ xfree(gdsp);
+ gdsp = NULL;
+ }
+ goto start;
+}
+
+void
+clean_nd(struct ndstruct *ndsp)
+{
+ struct ndstruct *p = NULL, *pp = NULL;
+
+start:
+ p = ndsp;
+ if (!p)
+ return;
+ while (p->next) {
+ pp = p;
+ p = p->next;
+ }
+ if (p->netbios) {
+ xfree(p->netbios);
+ p->netbios = NULL;
+ }
+ if (p->domain) {
+ xfree(p->domain);
+ p->domain = NULL;
+ }
+ if (pp && pp->next) {
+ xfree(pp->next);
+ pp->next = NULL;
+ }
+ if (p == ndsp) {
+ xfree(ndsp);
+ ndsp = NULL;
+ }
+ goto start;
+}
+
+void
+clean_args(struct main_args *margs)
+{
+ if (margs->glist) {
+ xfree(margs->glist);
+ margs->glist = NULL;
+ }
+ if (margs->ulist) {
+ xfree(margs->ulist);
+ margs->ulist = NULL;
+ }
+ if (margs->tlist) {
+ xfree(margs->tlist);
+ margs->tlist = NULL;
+ }
+ if (margs->nlist) {
+ xfree(margs->nlist);
+ margs->nlist = NULL;
+ }
+ if (margs->luser) {
+ xfree(margs->luser);
+ margs->luser = NULL;
+ }
+ if (margs->lpass) {
+ xfree(margs->lpass);
+ margs->lpass = NULL;
+ }
+ if (margs->lbind) {
+ xfree(margs->lbind);
+ margs->lbind = NULL;
+ }
+ if (margs->lurl) {
+ xfree(margs->lurl);
+ margs->lurl = NULL;
+ }
+ if (margs->ssl) {
+ xfree(margs->ssl);
+ margs->ssl = NULL;
+ }
+ if (margs->ddomain) {
+ xfree(margs->ddomain);
+ margs->ddomain = NULL;
+ }
+ if (margs->groups) {
+ clean_gd(margs->groups);
+ margs->groups = NULL;
+ }
+ if (margs->ndoms) {
+ clean_nd(margs->ndoms);
+ margs->ndoms = NULL;
+ }
+}
+
+void strup(char *s);
+
+int
+main(int argc, char *const argv[])
+{
+ char buf[6400];
+ char *user, *domain;
+ char *nuser, *nuser8 = NULL, *netbios;
+ char *c;
+ int opt;
+ int length;
+ struct main_args margs;
+
+ setbuf(stdout, NULL);
+ setbuf(stdin, NULL);
+
+ init_args(&margs);
+
+ while (-1 != (opt = getopt(argc, argv, "diasg:D:N:u:U:t:T:p:l:b:m:h"))) {
+ switch (opt) {
+ case 'd':
+ debug_enabled = 1;
+ break;
+ case 'i':
+ log_enabled = 1;
+ break;
+ case 'a':
+ margs.rc_allow = 1;
+ break;
+ case 's':
+ margs.ssl = (char *) "yes";
+ break;
+ case 'g':
+ margs.glist = xstrdup(optarg);
+ break;
+ case 'D':
+ margs.ddomain = xstrdup(optarg);
+ break;
+ case 'N':
+ margs.nlist = xstrdup(optarg);
+ break;
+ case 'u':
+ margs.luser = xstrdup(optarg);
+ break;
+ case 'U':
+ margs.ulist = xstrdup(optarg);
+ break;
+ case 't':
+ margs.ulist = xstrdup(optarg);
+ break;
+ case 'T':
+ margs.tlist = xstrdup(optarg);
+ break;
+ case 'p':
+ margs.lpass = xstrdup(optarg);
+ /* Hide Password */
+ memset(optarg, 'X', strlen(optarg));
+ break;
+ case 'l':
+ margs.lurl = xstrdup(optarg);
+ break;
+ case 'b':
+ margs.lbind = xstrdup(optarg);
+ break;
+ case 'm':
+ margs.mdepth = atoi(optarg);
+ break;
+ case 'h':
+ fprintf(stderr, "Usage: \n");
+ fprintf(stderr, "squid_kerb_ldap [-d] [-i] -g group list [-D domain] [-N netbios domain map] [-s] [-u ldap user] [-p ldap user password] [-l ldap url] [-b ldap bind path] [-a] [-m max depth] [-h]\n");
+ fprintf(stderr, "-d full debug\n");
+ fprintf(stderr, "-i informational messages\n");
+ fprintf(stderr, "-g group list\n");
+ fprintf(stderr, "-t group list (only group name hex UTF-8 format)\n");
+ fprintf(stderr, "-T group list (all in hex UTF-8 format - except seperator @)\n");
+ fprintf(stderr, "-D default domain\n");
+ fprintf(stderr, "-N netbios to dns domain map\n");
+ fprintf(stderr, "-u ldap user\n");
+ fprintf(stderr, "-p ldap user password\n");
+ fprintf(stderr, "-l ldap url\n");
+ fprintf(stderr, "-b ldap bind path\n");
+ fprintf(stderr, "-s use SSL encryption with Kerberos authentication\n");
+ fprintf(stderr, "-a allow SSL without cert verification\n");
+ fprintf(stderr, "-m maximal depth for recursive searches\n");
+ fprintf(stderr, "-h help\n");
+ fprintf(stderr, "The ldap url, ldap user and ldap user password details are only used if the kerberised\n");
+ fprintf(stderr, "access fails(e.g. unknown domain) or if the username does not contain a domain part\n");
+ fprintf(stderr, "and no default domain is provided.\n");
+ fprintf(stderr, "If the ldap url starts with ldaps:// it is either start_tls or simple SSL\n");
+ fprintf(stderr, "The group list can be:\n");
+ fprintf(stderr, "group - In this case group can be used for all keberised and non kerberised ldap servers\n");
+ fprintf(stderr, "group@ - In this case group can be used for all keberised ldap servers\n");
+ fprintf(stderr, "group@domain - In this case group can be used for ldap servers of domain domain\n");
+ fprintf(stderr, "group1@domain1:group2@domain2:group3@:group4 - A list is build with a colon as seperator\n");
+ fprintf(stderr, "Group membership is determined with AD servers through the users memberof attribute which\n");
+ fprintf(stderr, "is followed to the top (e.g. if the group is a member of a group)\n");
+ fprintf(stderr, "Group membership is determined with non AD servers through the users memberuid (assuming\n");
+ fprintf(stderr, "PosixGroup) or primary group membership (assuming PosixAccount)\n");
+ clean_args(&margs);
+ exit(0);
+ default:
+ warn((char *) "%s| %s: WARNING: unknown option: -%c.\n", LogTime(), PROGRAM, opt);
+ }
+ }
+
+ debug((char *) "%s| %s: INFO: Starting version %s\n", LogTime(), PROGRAM, KERBEROS_LDAP_GROUP_VERSION);
+ if (create_gd(&margs)) {
+ debug((char *) "%s| %s: FATAL: Error in group list: %s\n", LogTime(), PROGRAM, margs.glist ? margs.glist : "NULL");
+ SEND_ERR("");
+ clean_args(&margs);
+ exit(1);
+ }
+ if (create_nd(&margs)) {
+ debug((char *) "%s| %s: FATAL: Error in netbios list: %s\n", LogTime(), PROGRAM, margs.nlist ? margs.nlist : "NULL");
+ SEND_ERR("");
+ clean_args(&margs);
+ exit(1);
+ }
+ while (1) {
+ if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
+ if (ferror(stdin)) {
+ debug((char *) "%s| %s: FATAL: fgets() failed! dying..... errno=%d (%s)\n", LogTime(), PROGRAM, ferror(stdin),
+ strerror(ferror(stdin)));
+
+ SEND_ERR("");
+ clean_args(&margs);
+ exit(1); /* BIIG buffer */
+ }
+ SEND_ERR("");
+ clean_args(&margs);
+ exit(0);
+ }
+ c = (char *) memchr(buf, '\n', sizeof(buf) - 1);
+ if (c) {
+ *c = '\0';
+ length = c - buf;
+ } else {
+ SEND_ERR("");
+ debug((char *) "%s| %s: ERR\n", LogTime(), PROGRAM);
+ continue;
+ }
+
+ user = buf;
+ nuser = strchr(user, '\\');
+ if (!nuser)
+ nuser8 = strstr(user, "%5C");
+ if (!nuser && !nuser8)
+ nuser8 = strstr(user, "%5c");
+ domain = strrchr(user, '@');
+ if (nuser || nuser8) {
+ if (nuser) {
+ *nuser = '\0';
+ nuser++;
+ } else {
+ *nuser8 = '\0';
+ nuser = nuser8 + 3;
+ }
+ netbios = user;
+ if (debug_enabled)
+ debug((char *) "%s| %s: INFO: Got User: %s Netbios Name: %s\n", LogTime(), PROGRAM, nuser, netbios);
+ else
+ log((char *) "%s| %s: INFO: Got User: %s Netbios Name: %s\n", LogTime(), PROGRAM, nuser, netbios);
+ domain = get_netbios_name(&margs, netbios);
+ user = nuser;
+ } else if (domain) {
+ strup(domain);
+ *domain = '\0';
+ domain++;
+ }
+ if (!domain && margs.ddomain) {
+ domain = xstrdup(margs.ddomain);
+ if (debug_enabled)
+ debug((char *) "%s| %s: INFO: Got User: %s set default domain: %s\n", LogTime(), PROGRAM, user, domain);
+ else
+ log((char *) "%s| %s: INFO: Got User: %s set default domain: %s\n", LogTime(), PROGRAM, user, domain);
+ }
+ if (debug_enabled)
+ debug((char *) "%s| %s: INFO: Got User: %s Domain: %s\n", LogTime(), PROGRAM, user, domain ? domain : "NULL");
+ else
+ log((char *) "%s| %s: INFO: Got User: %s Domain: %s\n", LogTime(), PROGRAM, user, domain ? domain : "NULL");
+
+ if (!strcmp(user, "QQ") && domain && !strcmp(domain, "QQ")) {
+ clean_args(&margs);
+ exit(-1);
+ }
+ if (check_memberof(&margs, user, domain)) {
+ SEND_OK("");
+ debug((char *) "%s| %s: DEBUG: OK\n", LogTime(), PROGRAM);
+ } else {
+ SEND_ERR("");
+ debug((char *) "%s| %s: DEBUG: ERR\n", LogTime(), PROGRAM);
+ }
+ }
+
+
+}
+
+void
+strup(char *s)
+{
+ while (*s) {
+ *s = toupper((unsigned char) *s);
+ s++;
+ }
+}
+
+#else
+#include <stdio.h>
+#include <stdlib.h>
+int
+main(int argc, char *const argv[])
+{
+ setbuf(stdout, NULL);
+ setbuf(stdin, NULL);
+ char buf[6400];
+ while (1) {
+ if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
+ }
+ fprintf(stdout, "ERR\n");
+ fprintf(stderr, "LDAP group authorisation not supported\n");
+ }
+}
+#endif
--- /dev/null
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * Author: Markus Moeller (markus_moeller at compuserve.com)
+ *
+ * Copyright (C) 2007 Markus Moeller. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#define KERBEROS_LDAP_GROUP_VERSION "1.2.2sq"
+
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+
+#if HAVE_HEIMDAL_KERBEROS
+#if HAVE_GSSAPI_GSSAPI_H
+#include <gssapi/gssapi.h>
+#elif HAVE_GSSAPI_H
+#include <gssapi.h>
+#endif /* HAVE_GSSAPI_GSSAPI_H/HAVE_GSSAPI_H */
+#if HAVE_KRB5_H
+#if HAVE_BROKEN_SOLARIS_KRB5_H
+#warn "Warning! You have a broken Solaris <krb5.h> fsystem header"
+#warn "http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6837512"
+#endif /* HAVE_BROKEN_SOLARIS_KRB5_H */
+#include <krb5.h>
+#endif /* HAVE_KRB5_H */
+#if HAVE_COM_ERR_H
+#include <com_err.h>
+#else
+#define error_message(code) krb5_get_err_text(kparam.context,code)
+#endif /* HAVE_COM_ERR_H */
+#else /*MIT */
+#ifdef HAVE_GSSAPI_GSSAPI_H
+#include <gssapi/gssapi.h>
+#elif defined(HAVE_GSSAPI_H)
+#include <gssapi.h>
+#endif
+#ifdef HAVE_GSSAPI_GSSAPI_KRB5_H
+#include <gssapi/gssapi_krb5.h>
+#endif
+#ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H
+#include <gssapi/gssapi_generic.h>
+#endif
+#ifdef HAVE_GSSAPI_GSSAPI_EXT_H
+#include <gssapi/gssapi_ext.h>
+#endif
+#ifdef HAVE_KRB5_H
+#if HAVE_BROKEN_SOLARIS_KRB5_H
+#if defined(__cplusplus)
+#define KRB5INT_BEGIN_DECLS extern "C" {
+#define KRB5INT_END_DECLS
+KRB5INT_BEGIN_DECLS
+#endif
+#endif
+#include <krb5.h>
+#endif
+#ifdef HAVE_COM_ERR_H
+#include <com_err.h>
+#endif
+#endif
+#ifndef gss_nt_service_name
+#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
+#endif
+
+#define LDAP_DEPRECATED 1
+#ifdef HAVE_LDAP_REBIND_FUNCTION
+#define LDAP_REFERRALS
+#endif
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+#ifdef HAVE_MOZLDAP_LDAP_H
+#include <mozldap/ldap.h>
+#endif
+
+struct gdstruct {
+ char *group;
+ char *domain;
+ struct gdstruct *next;
+};
+struct ndstruct {
+ char *netbios;
+ char *domain;
+ struct ndstruct *next;
+};
+
+struct main_args {
+ char *glist;
+ char *ulist;
+ char *tlist;
+ char *nlist;
+ char *luser;
+ char *lpass;
+ char *lbind;
+ char *lurl;
+ char *ssl;
+ int rc_allow;
+ int AD;
+ int mdepth;
+ char *ddomain;
+ struct gdstruct *groups;
+ struct ndstruct *ndoms;
+};
+
+SQUIDCEXTERN int log_enabled;
+
+/* the macro overload style is really a gcc-ism */
+#ifdef __GNUC__
+
+
+#define log(X...) \
+ if (log_enabled) { \
+ fprintf(stderr, "%s(%d): pid=%ld :", __FILE__, __LINE__, (long)getpid() ); \
+ fprintf(stderr,X); \
+ } else (void)0
+
+#define error(X...) \
+ fprintf(stderr, "%s(%d): pid=%ld :", __FILE__, __LINE__, (long)getpid() ); \
+ fprintf(stderr,X); \
+
+#define warn(X...) \
+ fprintf(stderr, "%s(%d): pid=%ld :", __FILE__, __LINE__, (long)getpid() ); \
+ fprintf(stderr,X); \
+
+#else /* __GNUC__ */
+
+/* non-GCC compilers can't do the above macro define yet. */
+void log(char *format,...);
+void error(char *format,...);
+void warn(char *format,...);
+#endif
+
+
+struct hstruct {
+ char *host;
+ int port;
+ int priority;
+ int weight;
+};
+
+struct ldap_creds {
+ char *dn;
+ char *pw;
+};
+
+
+void init_args(struct main_args *margs);
+void clean_args(struct main_args *margs);
+const char *LogTime(void);
+
+int check_memberof(struct main_args *margs, char *user, char *domain);
+int get_memberof(struct main_args *margs, char *user, char *domain, char *group);
+
+char *get_netbios_name(struct main_args *margs, char *netbios);
+
+int create_gd(struct main_args *margs);
+int create_nd(struct main_args *margs);
+
+int krb5_create_cache(struct main_args *margs, char *domain);
+void krb5_cleanup(void);
+
+int get_ldap_hostname_list(struct main_args *margs, struct hstruct **hlist, int nhosts, char *domain);
+int get_hostname_list(struct main_args *margs, struct hstruct **hlist, int nhosts, char *name);
+int free_hostname_list(struct hstruct **hlist, int nhosts);
+
+#if defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H) || defined(HAVE_SASL_DARWIN)
+int tool_sasl_bind(LDAP * ld, char *binddn, char *ssl);
+#endif
+
+#define PROGRAM "kerberos_ldap_group"
--- /dev/null
+
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * Author: Markus Moeller (markus_moeller at compuserve.com)
+ *
+ * Copyright (C) 2007 Markus Moeller. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#include "config.h"
+#include "util.h"
+
+#ifdef HAVE_LDAP
+
+#include "support.h"
+
+struct gdstruct *init_gd(void);
+
+struct gdstruct *
+init_gd(void) {
+ struct gdstruct *gdsp;
+ gdsp = (struct gdstruct *) xmalloc(sizeof(struct gdstruct));
+ gdsp->group = NULL;
+ gdsp->domain = NULL;
+ gdsp->next = NULL;
+ return gdsp;
+}
+
+char *utf8dup(struct main_args *margs);
+
+char *
+utf8dup(struct main_args *margs)
+{
+ int c = 0, s;
+ size_t n;
+ char *src;
+ unsigned char *p, *dup;
+
+ src = margs->glist;
+ if (!src)
+ return NULL;
+ for (n = 0; n < strlen(src); n++)
+ if ((unsigned char) src[n] > 127)
+ c++;
+ if (c != 0) {
+ p = (unsigned char *) xmalloc(strlen(src) + c);
+ dup = p;
+ for (n = 0; n < strlen(src); n++) {
+ s = (unsigned char) src[n];
+ if (s > 127 && s < 192) {
+ *p = 194;
+ p++;
+ *p = s;
+ } else if (s > 191 && s < 256) {
+ *p = 195;
+ p++;
+ *p = s - 64;
+ } else
+ *p = s;
+ p++;
+ }
+ *p = '\0';
+ debug((char *) "%s| %s: INFO: Group %s as UTF-8: %s\n", LogTime(), PROGRAM, src, dup);
+ return (char *) dup;
+ } else
+ return xstrdup(src);
+}
+
+char *hex_utf_char(struct main_args *margs, int flag);
+/*
+ * UTF8 = UTF1 / UTFMB
+ * UTFMB = UTF2 / UTF3 / UTF4
+ *
+ * UTF0 = %x80-BF
+ * UTF1 = %x00-7F
+ * UTF2 = %xC2-DF UTF0
+ * UTF3 = %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) /
+ * %xED %x80-9F UTF0 / %xEE-EF 2(UTF0)
+ * UTF4 = %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) /
+ * %xF4 %x80-8F 2(UTF0)
+ *
+ * http://www.utf8-chartable.de/unicode-utf8-table.pl
+ */
+
+char *
+hex_utf_char(struct main_args *margs, int flag)
+{
+ char *up;
+ char *upd;
+ char *ul;
+ int a, n, nl, ival, ichar;
+ int iUTF2, iUTF3, iUTF4;
+
+ if (flag) {
+ up = margs->ulist;
+ } else {
+ up = margs->tlist;
+ }
+
+ if (!up)
+ return NULL;
+
+ upd = strrchr(up, '@');
+ if (upd)
+ a = upd - up;
+ else
+ a = strlen(up);
+
+ ul = (char *) xmalloc(strlen(up));
+ n = 0;
+ nl = 0;
+ iUTF2 = 0;
+ iUTF3 = 0;
+ iUTF4 = 0;
+
+ while (n < (int) strlen(up)) {
+ if (flag && n == a)
+ break;
+ if (up[n] == '@') {
+ ul[nl] = '@';
+ nl++;
+ n++;
+ continue;
+ }
+ ival = up[n];
+ if (ival > 64 && ival < 71)
+ ichar = (ival - 55) * 16;
+ else if (ival > 96 && ival < 103)
+ ichar = (ival - 87) * 16;
+ else if (ival > 47 && ival < 58)
+ ichar = (ival - 48) * 16;
+ else {
+ debug((char *) "%s| %s: WARNING: Invalid Hex value %c\n", LogTime(), PROGRAM, ival);
+ if (ul)
+ xfree(ul);
+ return NULL;
+ }
+
+
+ if (n == a - 1) {
+ debug((char *) "%s| %s: WARNING: Invalid Hex UTF-8 string %s\n", LogTime(), PROGRAM, up);
+ if (ul)
+ xfree(ul);
+ return NULL;
+ }
+ n++;
+ ival = up[n];
+ if (ival > 64 && ival < 71)
+ ichar = ichar + ival - 55;
+ else if (ival > 96 && ival < 103)
+ ichar = ichar + ival - 87;
+ else if (ival > 47 && ival < 58)
+ ichar = ichar + ival - 48;
+ else {
+ debug((char *) "%s| %s: WARNING: Invalid Hex value %c\n", LogTime(), PROGRAM, ival);
+ if (ul)
+ xfree(ul);
+ return NULL;
+ }
+
+ if (iUTF2) {
+ if (iUTF2 == 0xC2 && ichar > 0x7F && ichar < 0xC0) {
+ iUTF2 = 0;
+ ul[nl - 1] = ichar;
+ } else if (iUTF2 == 0xC3 && ichar > 0x7F && ichar < 0xC0) {
+ iUTF2 = 0;
+ ul[nl - 1] = ichar + 64;
+ } else if (iUTF2 > 0xC3 && iUTF2 < 0xE0 && ichar > 0x7F && ichar < 0xC0) {
+ iUTF2 = 0;
+ ul[nl] = ichar;
+ nl++;
+ } else {
+ iUTF2 = 0;
+ ul[nl] = ichar;
+ ul[nl + 1] = '\0';
+ debug((char *) "%s| %s: WARNING: Invalid UTF-8 sequence for Unicode %s\n", LogTime(), PROGRAM, ul);
+ if (ul)
+ xfree(ul);
+ return NULL;
+ }
+ } else if (iUTF3) {
+ if (iUTF3 == 0xE0 && ichar > 0x9F && ichar < 0xC0) {
+ iUTF3 = 1;
+ ul[nl] = ichar;
+ nl++;
+ } else if (iUTF3 > 0xE0 && iUTF3 < 0xED && ichar > 0x7F && ichar < 0xC0) {
+ iUTF3 = 2;
+ ul[nl] = ichar;
+ nl++;
+ } else if (iUTF3 == 0xED && ichar > 0x7F && ichar < 0xA0) {
+ iUTF3 = 3;
+ ul[nl] = ichar;
+ nl++;
+ } else if (iUTF3 > 0xED && iUTF3 < 0xF0 && ichar > 0x7F && ichar < 0xC0) {
+ iUTF3 = 4;
+ ul[nl] = ichar;
+ nl++;
+ } else if (iUTF3 > 0 && iUTF3 < 5 && ichar > 0x7F && ichar < 0xC0) {
+ iUTF3 = 0;
+ ul[nl] = ichar;
+ nl++;
+ } else {
+ iUTF3 = 0;
+ ul[nl] = ichar;
+ ul[nl + 1] = '\0';
+ debug((char *) "%s| %s: WARNING: Invalid UTF-8 sequence for Unicode %s\n", LogTime(), PROGRAM, ul);
+ if (ul)
+ xfree(ul);
+ return NULL;
+ }
+ } else if (iUTF4) {
+ if (iUTF4 == 0xF0 && ichar > 0x8F && ichar < 0xC0) {
+ iUTF4 = 1;
+ ul[nl] = ichar;
+ nl++;
+ } else if (iUTF4 > 0xF0 && iUTF3 < 0xF4 && ichar > 0x7F && ichar < 0xC0) {
+ iUTF4 = 2;
+ ul[nl] = ichar;
+ nl++;
+ } else if (iUTF4 == 0xF4 && ichar > 0x7F && ichar < 0x90) {
+ iUTF4 = 3;
+ ul[nl] = ichar;
+ nl++;
+ } else if (iUTF4 > 0 && iUTF4 < 5 && ichar > 0x7F && ichar < 0xC0) {
+ if (iUTF4 == 4)
+ iUTF4 = 0;
+ else
+ iUTF4 = 4;
+ ul[nl] = ichar;
+ nl++;
+ } else {
+ iUTF4 = 0;
+ ul[nl] = ichar;
+ ul[nl + 1] = '\0';
+ debug((char *) "%s| %s: WARNING: Invalid UTF-8 sequence for Unicode %s\n", LogTime(), PROGRAM, ul);
+ if (ul)
+ xfree(ul);
+ return NULL;
+ }
+ } else if (ichar < 0x80) {
+ /* UTF1 */
+ ul[nl] = ichar;
+ nl++;
+ } else if (ichar > 0xC1 && ichar < 0xE0) {
+ /* UTF2 (Latin) */
+ iUTF2 = ichar;
+ ul[nl] = ichar;
+ nl++;
+ } else if (ichar > 0xDF && ichar < 0xF0) {
+ /* UTF3 */
+ iUTF3 = ichar;
+ ul[nl] = ichar;
+ nl++;
+ } else if (ichar > 0xEF && ichar < 0xF5) {
+ /* UTF4 */
+ iUTF4 = ichar;
+ ul[nl] = ichar;
+ nl++;
+ } else {
+ ul[nl] = ichar;
+ ul[nl + 1] = '\0';
+ debug((char *) "%s| %s: WARNING: Invalid UTF-8 sequence for Unicode %s\n", LogTime(), PROGRAM, ul);
+ if (ul)
+ xfree(ul);
+ return NULL;
+ }
+ n++;
+ }
+
+ ul[nl] = '\0';
+ if (iUTF2 || iUTF3 || iUTF4) {
+ debug((char *) "%s| %s: INFO: iUTF2: %d iUTF3: %d iUTF4: %d\n", LogTime(), PROGRAM, iUTF2, iUTF3, iUTF4);
+ debug((char *) "%s| %s: WARNING: Invalid UTF-8 sequence for Unicode %s\n", LogTime(), PROGRAM, ul);
+ if (ul)
+ xfree(ul);
+ return NULL;
+ }
+ if (flag && upd)
+ ul = strcat(ul, upd);
+ return ul;
+}
+
+
+int
+create_gd(struct main_args *margs)
+{
+ char *gp, *dp;
+ char *hp1, *hp2, *up;
+ char *p;
+ struct gdstruct *gdsp = NULL, *gdspn = NULL;
+ /*
+ * Group list format:
+ *
+ * glist=Pattern1[:Pattern2]
+ *
+ * Pattern=Group Group for all domains(including non Kerberos domains using ldap url options) if no
+ * other group definition for domain exists or users without
+ * domain information.
+ * gdstruct.domain=NULL, gdstruct.group=Group
+ *
+ * or Pattern=Group@ Group for all Kerberos domains if no other group definition
+ * exists
+ * gdstruct.domain="", gdstruct.group=Group
+ *
+ * or Pattern=Group@Domain Group for a specific Kerberos domain
+ * gdstruct.domain=Domain, gdstruct.group=Group
+ *
+ *
+ */
+ hp1 = hex_utf_char(margs, 0);
+ hp2 = hex_utf_char(margs, 1);
+ up = utf8dup(margs);
+ p = up;
+ if (hp1) {
+ if (hp2) {
+ if (up) {
+ p = (char *) xmalloc(strlen(up) + strlen(hp1) + strlen(hp2) + 2);
+ strcpy(p, up);
+ strcat(p, ":");
+ strcat(p, hp1);
+ strcat(p, ":");
+ strcat(p, hp2);
+ } else {
+ p = (char *) xmalloc(strlen(hp1) + strlen(hp2) + 1);
+ strcpy(p, hp1);
+ strcat(p, ":");
+ strcat(p, hp2);
+ }
+ } else {
+ if (up) {
+ p = (char *) xmalloc(strlen(up) + strlen(hp1) + 1);
+ strcpy(p, up);
+ strcat(p, ":");
+ strcat(p, hp1);
+ } else
+ p = hp1;
+ }
+ } else {
+ if (hp2) {
+ if (up) {
+ p = (char *) xmalloc(strlen(up) + strlen(hp2) + 1);
+ strcpy(p, up);
+ strcat(p, ":");
+ strcat(p, hp2);
+ } else
+ p = hp2;
+ } else
+ p = up;
+ }
+ gp = p;
+ debug((char *) "%s| %s: INFO: Group list %s\n", LogTime(), PROGRAM, p ? p : "NULL");
+ dp = NULL;
+
+ if (!p) {
+ debug((char *) "%s| %s: ERROR: No groups defined.\n", LogTime(), PROGRAM);
+ return (1);
+ }
+ while (*p) { /* loop over group list */
+ if (*p == '\n' || *p == '\r') { /* Ignore CR and LF if exist */
+ p++;
+ continue;
+ }
+ if (*p == '@') { /* end of group name - start of domain name */
+ if (p == gp) { /* empty group name not allowed */
+ debug((char *) "%s| %s: ERROR: No group defined for domain %s\n", LogTime(), PROGRAM, p);
+ return (1);
+ }
+ *p = '\0';
+ p++;
+ gdsp = init_gd();
+ gdsp->group = gp;
+ if (gdspn) /* Have already an existing structure */
+ gdsp->next = gdspn;
+ dp = p; /* after @ starts new domain name */
+ } else if (*p == ':') { /* end of group name or end of domain name */
+ if (p == gp) { /* empty group name not allowed */
+ debug((char *) "%s| %s: ERROR: No group defined for domain %s\n", LogTime(), PROGRAM, p);
+ return (1);
+ }
+ *p = '\0';
+ p++;
+ if (dp) { /* end of domain name */
+ gdsp->domain = xstrdup(dp);
+ dp = NULL;
+ } else { /* end of group name and no domain name */
+ gdsp = init_gd();
+ gdsp->group = gp;
+ if (gdspn) /* Have already an existing structure */
+ gdsp->next = gdspn;
+ }
+ gdspn = gdsp;
+ gp = p; /* after : starts new group name */
+ debug((char *) "%s| %s: INFO: Group %s Domain %s\n", LogTime(), PROGRAM, gdsp->group, gdsp->domain ? gdsp->domain : "NULL");
+ } else
+ p++;
+ }
+ if (p == gp) { /* empty group name not allowed */
+ debug((char *) "%s| %s: ERROR: No group defined for domain %s\n", LogTime(), PROGRAM, p);
+ return (1);
+ }
+ if (dp) { /* end of domain name */
+ gdsp->domain = xstrdup(dp);
+ } else { /* end of group name and no domain name */
+ gdsp = init_gd();
+ gdsp->group = gp;
+ if (gdspn) /* Have already an existing structure */
+ gdsp->next = gdspn;
+ }
+ debug((char *) "%s| %s: INFO: Group %s Domain %s\n", LogTime(), PROGRAM, gdsp->group, gdsp->domain ? gdsp->domain : "NULL");
+
+ margs->groups = gdsp;
+ return (0);
+}
+#endif
--- /dev/null
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * Author: Markus Moeller (markus_moeller at compuserve.com)
+ *
+ * Copyright (C) 2007 Markus Moeller. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#include "config.h"
+#include "util.h"
+
+#ifdef HAVE_LDAP
+
+#include "support.h"
+
+struct kstruct {
+ krb5_context context;
+ char *mem_cache_env;
+ krb5_ccache cc;
+} kparam;
+
+#define KT_PATH_MAX 256
+
+void
+krb5_cleanup()
+{
+ if (kparam.context) {
+ if (kparam.cc)
+ krb5_cc_destroy(kparam.context, kparam.cc);
+ krb5_free_context(kparam.context);
+ }
+}
+/*
+ * create Kerberos memory cache
+ */
+int
+krb5_create_cache(struct main_args *margs, char *domain)
+{
+
+ krb5_keytab keytab = 0;
+ krb5_keytab_entry entry;
+ krb5_kt_cursor cursor;
+ krb5_creds *creds = NULL;
+ krb5_creds *tgt_creds = NULL;
+ krb5_principal *principal_list = NULL;
+ krb5_principal principal = NULL;
+ char *service;
+ char *keytab_name = NULL, *principal_name = NULL, *mem_cache = NULL;
+ char buf[KT_PATH_MAX], *p;
+ int nprinc = 0;
+ int i;
+ int retval = 0;
+ int found = 0;
+ krb5_error_code code = 0;
+
+ kparam.context = NULL;
+
+ if (!domain || !strcmp(domain, ""))
+ return (1);
+
+ /*
+ * Initialise Kerberos
+ */
+
+ code = krb5_init_context(&kparam.context);
+ if (code) {
+ error((char *) "%s| %s: ERROR: Error while initialising Kerberos library : %s\n", LogTime(), PROGRAM, error_message(code));
+ retval = 1;
+ goto cleanup;
+ }
+ /*
+ * getting default keytab name
+ */
+
+ debug((char *) "%s| %s: DEBUG: Get default keytab file name\n", LogTime(), PROGRAM);
+ krb5_kt_default_name(kparam.context, buf, KT_PATH_MAX);
+ p = strchr(buf, ':'); /* Find the end if "FILE:" */
+ if (p)
+ p++; /* step past : */
+ keytab_name = xstrdup(p ? p : buf);
+ debug((char *) "%s| %s: DEBUG: Got default keytab file name %s\n", LogTime(), PROGRAM, keytab_name);
+
+ code = krb5_kt_resolve(kparam.context, keytab_name, &keytab);
+ if (code) {
+ error((char *) "%s| %s: ERROR: Error while resolving keytab %s : %s\n", LogTime(), PROGRAM, keytab_name, error_message(code));
+ retval = 1;
+ goto cleanup;
+ }
+ code = krb5_kt_start_seq_get(kparam.context, keytab, &cursor);
+ if (code) {
+ error((char *) "%s| %s: ERROR: Error while starting keytab scan : %s\n", LogTime(), PROGRAM, error_message(code));
+ retval = 1;
+ goto cleanup;
+ }
+ debug((char *) "%s| %s: DEBUG: Get principal name from keytab %s\n", LogTime(), PROGRAM, keytab_name);
+
+ nprinc = 0;
+ while ((code = krb5_kt_next_entry(kparam.context, keytab, &entry, &cursor)) == 0) {
+
+ principal_list = (krb5_principal *) xrealloc(principal_list, sizeof(krb5_principal) * (nprinc + 1));
+ krb5_copy_principal(kparam.context, entry.principal, &principal_list[nprinc++]);
+#ifdef HAVE_HEIMDAL_KERBEROS
+ debug((char *) "%s| %s: DEBUG: Keytab entry has realm name: %s\n", LogTime(), PROGRAM, entry.principal->realm);
+#else
+ debug((char *) "%s| %s: DEBUG: Keytab entry has realm name: %s\n", LogTime(), PROGRAM, krb5_princ_realm(kparam.context, entry.principal)->data);
+#endif
+#ifdef HAVE_HEIMDAL_KERBEROS
+ if (!strcasecmp(domain, entry.principal->realm))
+#else
+ if (!strcasecmp(domain, krb5_princ_realm(kparam.context, entry.principal)->data))
+#endif
+ {
+ code = krb5_unparse_name(kparam.context, entry.principal, &principal_name);
+ if (code) {
+ error((char *) "%s| %s: ERROR: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code));
+ } else {
+ debug((char *) "%s| %s: DEBUG: Found principal name: %s\n", LogTime(), PROGRAM, principal_name);
+ found = 1;
+ }
+ }
+#if defined(HAVE_HEIMDAL_KERBEROS) || ( defined(HAVE_KRB5_KT_FREE_ENTRY) && HAVE_DECL_KRB5_KT_FREE_ENTRY==1)
+ code = krb5_kt_free_entry(kparam.context, &entry);
+#else
+ code = krb5_free_keytab_entry_contents(kparam.context, &entry);
+#endif
+ if (code) {
+ error((char *) "%s| %s: ERROR: Error while freeing keytab entry : %s\n", LogTime(), PROGRAM, error_message(code));
+ retval = 1;
+ break;
+ }
+ if (found)
+ break;
+ }
+
+ if (code && code != KRB5_KT_END) {
+ error((char *) "%s| %s: ERROR: Error while scanning keytab : %s\n", LogTime(), PROGRAM, error_message(code));
+ retval = 1;
+ goto cleanup;
+ }
+ code = krb5_kt_end_seq_get(kparam.context, keytab, &cursor);
+ if (code) {
+ error((char *) "%s| %s: ERROR: Error while ending keytab scan : %s\n", LogTime(), PROGRAM, error_message(code));
+ retval = 1;
+ goto cleanup;
+ }
+ /*
+ * prepare memory credential cache
+ */
+#if !defined(HAVE_KRB5_MEMORY_CACHE) || defined(HAVE_SUN_LDAP_SDK)
+ mem_cache = (char *) xmalloc(strlen("FILE:/tmp/squid_ldap_") + 16);
+ snprintf(mem_cache, strlen("FILE:/tmp/squid_ldap_") + 16, "FILE:/tmp/squid_ldap_%d", (int) getpid());
+#else
+ mem_cache = (char *) xmalloc(strlen("MEMORY:squid_ldap_") + 16);
+ snprintf(mem_cache, strlen("MEMORY:squid_ldap_") + 16, "MEMORY:squid_ldap_%d", (int) getpid());
+#endif
+
+ setenv("KRB5CCNAME", mem_cache, 1);
+ debug((char *) "%s| %s: DEBUG: Set credential cache to %s\n", LogTime(), PROGRAM, mem_cache);
+ code = krb5_cc_resolve(kparam.context, mem_cache, &kparam.cc);
+ if (code) {
+ error((char *) "%s| %s: ERROR: Error while resolving memory ccache : %s\n", LogTime(), PROGRAM, error_message(code));
+ retval = 1;
+ goto cleanup;
+ }
+ /*
+ * if no principal name found in keytab for domain use the prinipal name which can get a TGT
+ */
+ if (!principal_name) {
+ debug((char *) "%s| %s: DEBUG: Did not find a principal in keytab for domain %s.\n", LogTime(), PROGRAM, domain);
+ debug((char *) "%s| %s: DEBUG: Try to get principal of trusted domain.\n", LogTime(), PROGRAM);
+ creds = (krb5_creds *) xmalloc(sizeof(*creds));
+ memset(creds, 0, sizeof(*creds));
+
+ for (i = 0; i < nprinc; i++) {
+ /*
+ * get credentials
+ */
+ code = krb5_unparse_name(kparam.context, principal_list[i], &principal_name);
+ if (code) {
+ debug((char *) "%s| %s: DEBUG: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code));
+ goto loop_end;
+ }
+ debug((char *) "%s| %s: DEBUG: Keytab entry has principal: %s\n", LogTime(), PROGRAM, principal_name);
+
+#if HAVE_GET_INIT_CREDS_KEYTAB
+ code = krb5_get_init_creds_keytab(kparam.context, creds, principal_list[i], keytab, 0, NULL, NULL);
+#else
+ service = (char *) xmalloc(strlen("krbtgt") + 2 * strlen(domain) + 3);
+ snprintf(service, strlen("krbtgt") + 2 * strlen(domain) + 3, "krbtgt/%s@%s", domain, domain);
+ creds->client = principal_list[i];
+ code = krb5_parse_name(kparam.context, service, &creds->server);
+ if (service)
+ xfree(service);
+ code = krb5_get_in_tkt_with_keytab(kparam.context, 0, NULL, NULL, NULL, keytab, NULL, creds, 0);
+#endif
+ if (code) {
+ debug((char *) "%s| %s: DEBUG: Error while initialising credentials from keytab : %s\n", LogTime(), PROGRAM, error_message(code));
+ goto loop_end;
+ }
+ code = krb5_cc_initialize(kparam.context, kparam.cc, principal_list[i]);
+ if (code) {
+ error((char *) "%s| %s: ERROR: Error while initializing memory caches : %s\n", LogTime(), PROGRAM, error_message(code));
+ goto loop_end;
+ }
+ code = krb5_cc_store_cred(kparam.context, kparam.cc, creds);
+ if (code) {
+ debug((char *) "%s| %s: DEBUG: Error while storing credentials : %s\n", LogTime(), PROGRAM, error_message(code));
+ goto loop_end;
+ }
+ if (creds->server)
+ krb5_free_principal(kparam.context, creds->server);
+#ifdef HAVE_HEIMDAL_KERBEROS
+ service = (char *) xmalloc(strlen("krbtgt") + strlen(domain) + strlen(principal_list[i]->realm) + 3);
+ snprintf(service, strlen("krbtgt") + strlen(domain) + strlen(principal_list[i]->realm) + 3, "krbtgt/%s@%s", domain, principal_list[i]->realm);
+#else
+ service = (char *) xmalloc(strlen("krbtgt") + strlen(domain) + strlen(krb5_princ_realm(kparam.context, principal_list[i])->data) + 3);
+ snprintf(service, strlen("krbtgt") + strlen(domain) + strlen(krb5_princ_realm(kparam.context, principal_list[i])->data) + 3, "krbtgt/%s@%s", domain, krb5_princ_realm(kparam.context, principal_list[i])->data);
+#endif
+ code = krb5_parse_name(kparam.context, service, &creds->server);
+ if (service)
+ xfree(service);
+ if (code) {
+ error((char *) "%s| %s: ERROR: Error while initialising TGT credentials : %s\n", LogTime(), PROGRAM, error_message(code));
+ goto loop_end;
+ }
+ code = krb5_get_credentials(kparam.context, 0, kparam.cc, creds, &tgt_creds);
+ if (code) {
+ debug((char *) "%s| %s: DEBUG: Error while getting tgt : %s\n", LogTime(), PROGRAM, error_message(code));
+ goto loop_end;
+ } else {
+ debug((char *) "%s| %s: DEBUG: Found trusted principal name: %s\n", LogTime(), PROGRAM, principal_name);
+ found = 1;
+ break;
+ }
+
+loop_end:
+ if (principal_name)
+ xfree(principal_name);
+ principal_name = NULL;
+ }
+
+ if (tgt_creds)
+ krb5_free_creds(kparam.context, tgt_creds);
+ tgt_creds = NULL;
+ if (creds)
+ krb5_free_creds(kparam.context, creds);
+ creds = NULL;
+ }
+ if (principal_name) {
+
+ debug((char *) "%s| %s: DEBUG: Got principal name %s\n", LogTime(), PROGRAM, principal_name);
+ /*
+ * build principal
+ */
+ code = krb5_parse_name(kparam.context, principal_name, &principal);
+ if (code) {
+ error((char *) "%s| %s: ERROR: Error while parsing name %s : %s\n", LogTime(), PROGRAM, principal_name, error_message(code));
+ retval = 1;
+ goto cleanup;
+ }
+ creds = (krb5_creds *) xmalloc(sizeof(*creds));
+ memset(creds, 0, sizeof(*creds));
+
+ /*
+ * get credentials
+ */
+#if HAVE_GET_INIT_CREDS_KEYTAB
+ code = krb5_get_init_creds_keytab(kparam.context, creds, principal, keytab, 0, NULL, NULL);
+#else
+ service = (char *) xmalloc(strlen("krbtgt") + 2 * strlen(domain) + 3);
+ snprintf(service, strlen("krbtgt") + 2 * strlen(domain) + 3, "krbtgt/%s@%s", domain, domain);
+ creds->client = principal;
+ code = krb5_parse_name(kparam.context, service, &creds->server);
+ if (service)
+ xfree(service);
+ code = krb5_get_in_tkt_with_keytab(kparam.context, 0, NULL, NULL, NULL, keytab, NULL, creds, 0);
+#endif
+ if (code) {
+ error((char *) "%s| %s: ERROR: Error while initialising credentials from keytab : %s\n", LogTime(), PROGRAM, error_message(code));
+ retval = 1;
+ goto cleanup;
+ }
+ code = krb5_cc_initialize(kparam.context, kparam.cc, principal);
+ if (code) {
+ error((char *) "%s| %s: ERROR: Error while initializing memory caches : %s\n", LogTime(), PROGRAM, error_message(code));
+ retval = 1;
+ goto cleanup;
+ }
+ code = krb5_cc_store_cred(kparam.context, kparam.cc, creds);
+ if (code) {
+ error((char *) "%s| %s: ERROR: Error while storing credentials : %s\n", LogTime(), PROGRAM, error_message(code));
+ retval = 1;
+ goto cleanup;
+ }
+ debug((char *) "%s| %s: DEBUG: Stored credentials\n", LogTime(), PROGRAM);
+ } else {
+ debug((char *) "%s| %s: DEBUG: Got no principal name\n", LogTime(), PROGRAM);
+ retval = 1;
+ }
+cleanup:
+ if (keytab)
+ krb5_kt_close(kparam.context, keytab);
+ if (keytab_name)
+ xfree(keytab_name);
+ if (principal_name)
+ xfree(principal_name);
+ if (mem_cache)
+ xfree(mem_cache);
+ if (principal)
+ krb5_free_principal(kparam.context, principal);
+ for (i = 0; i < nprinc; i++) {
+ if (principal_list[i])
+ krb5_free_principal(kparam.context, principal_list[i]);
+ }
+ if (principal_list)
+ xfree(principal_list);
+ if (creds)
+ krb5_free_creds(kparam.context, creds);
+
+ return (retval);
+}
+#endif
--- /dev/null
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * Author: Markus Moeller (markus_moeller at compuserve.com)
+ *
+ * Copyright (C) 2007 Markus Moeller. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#include "config.h"
+#include "util.h"
+
+#ifdef HAVE_LDAP
+
+#include "support.h"
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+char *convert_domain_to_bind_path(char *domain);
+char *escape_filter(char *filter);
+int check_AD(struct main_args *margs, LDAP * ld);
+int ldap_set_defaults(struct main_args *margs, LDAP * ld);
+int ldap_set_ssl_defaults(struct main_args *margs);
+LDAP *tool_ldap_open(struct main_args *margs, char *host, int port, char *ssl);
+
+#define CONNECT_TIMEOUT 2
+#define SEARCH_TIMEOUT 30
+
+#define FILTER "(memberuid=%s)"
+#define ATTRIBUTE "cn"
+#define FILTER_UID "(uid=%s)"
+#define FILTER_GID "(&(gidNumber=%s)(objectclass=posixgroup))"
+#define ATTRIBUTE_GID "gidNumber"
+
+#define FILTER_AD "(samaccountname=%s)"
+#define ATTRIBUTE_AD "memberof"
+
+int get_attributes(struct main_args *margs, LDAP * ld, LDAPMessage * res, const char *attribute /* IN */ , char ***out_val /* OUT (caller frees) */ );
+int search_group_tree(struct main_args *margs, LDAP * ld, char *bindp, char *ldap_group, char *group, int depth);
+
+#if defined(HAVE_SUN_LDAP_SDK) || defined(HAVE_MOZILLA_LDAP_SDK)
+#ifdef HAVE_LDAP_REBINDPROC_CALLBACK
+
+#if defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H) || defined(HAVE_SASL_DARWIN)
+static LDAP_REBINDPROC_CALLBACK ldap_sasl_rebind;
+
+static int LDAP_CALL LDAP_CALLBACK
+ldap_sasl_rebind(
+ LDAP * ld,
+ char **whop,
+ char **credp,
+ int *methodp,
+ int freeit,
+ void *params)
+{
+ struct ldap_creds *cp = (struct ldap_creds *) params;
+ whop = whop;
+ credp = credp;
+ methodp = methodp;
+ freeit = freeit;
+ return tool_sasl_bind(ld, cp->dn, cp->pw);
+}
+#endif
+
+static LDAP_REBINDPROC_CALLBACK ldap_simple_rebind;
+
+static int LDAP_CALL LDAP_CALLBACK
+ldap_simple_rebind(
+ LDAP * ld,
+ char **whop,
+ char **credp,
+ int *methodp,
+ int freeit,
+ void *params)
+{
+ struct ldap_creds *cp = (struct ldap_creds *) params;
+ whop = whop;
+ credp = credp;
+ methodp = methodp;
+ freeit = freeit;
+ return ldap_bind_s(ld, cp->dn, cp->pw, LDAP_AUTH_SIMPLE);
+}
+#elif defined(HAVE_LDAP_REBIND_PROC)
+#if defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H) || defined(HAVE_SASL_DARWIN)
+static LDAP_REBIND_PROC ldap_sasl_rebind;
+
+static int
+ldap_sasl_rebind(
+ LDAP * ld,
+ LDAP_CONST char *url,
+ ber_tag_t request,
+ ber_int_t msgid,
+ void *params)
+{
+ struct ldap_creds *cp = (struct ldap_creds *) params;
+ url = url;
+ request = request;
+ msgid = msgid;
+ return tool_sasl_bind(ld, cp->dn, cp->pw);
+}
+#endif
+
+static LDAP_REBIND_PROC ldap_simple_rebind;
+
+static int
+ldap_simple_rebind(
+ LDAP * ld,
+ LDAP_CONST char *url,
+ ber_tag_t request,
+ ber_int_t msgid,
+ void *params)
+{
+ struct ldap_creds *cp = (struct ldap_creds *) params;
+ url = url;
+ request = request;
+ msgid = msgid;
+ return ldap_bind_s(ld, cp->dn, cp->pw, LDAP_AUTH_SIMPLE);
+}
+
+#elif defined(HAVE_LDAP_REBIND_FUNCTION)
+#ifndef LDAP_REFERRALS
+#define LDAP_REFERRALS
+#endif
+#if defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H) || defined(HAVE_SASL_DARWIN)
+static LDAP_REBIND_FUNCTION ldap_sasl_rebind;
+
+static int
+ldap_sasl_rebind(
+ LDAP * ld,
+ char **whop,
+ char **credp,
+ int *methodp,
+ int freeit,
+ void *params)
+{
+ struct ldap_creds *cp = (struct ldap_creds *) params;
+ whop = whop;
+ credp = credp;
+ methodp = methodp;
+ freeit = freeit;
+ return tool_sasl_bind(ld, cp->dn, cp->pw);
+}
+#endif
+
+static LDAP_REBIND_FUNCTION ldap_simple_rebind;
+
+static int
+ldap_simple_rebind(
+ LDAP * ld,
+ char **whop,
+ char **credp,
+ int *methodp,
+ int freeit,
+ void *params)
+{
+ struct ldap_creds *cp = (struct ldap_creds *) params;
+ whop = whop;
+ credp = credp;
+ methodp = methodp;
+ freeit = freeit;
+ return ldap_bind_s(ld, cp->dn, cp->pw, LDAP_AUTH_SIMPLE);
+}
+#else
+#error "No rebind functione defined"
+#endif
+#else /* HAVE_SUN_LDAP_SDK */
+#if defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H) || defined(HAVE_SASL_DARWIN)
+static LDAP_REBIND_PROC ldap_sasl_rebind;
+
+static int
+ldap_sasl_rebind(
+ LDAP * ld,
+ LDAP_CONST char *url,
+ ber_tag_t request,
+ ber_int_t msgid,
+ void *params)
+{
+ struct ldap_creds *cp = (struct ldap_creds *) params;
+ url = url;
+ request = request;
+ msgid = msgid;
+ return tool_sasl_bind(ld, cp->dn, cp->pw);
+}
+#endif
+
+static LDAP_REBIND_PROC ldap_simple_rebind;
+
+static int
+ldap_simple_rebind(
+ LDAP * ld,
+ LDAP_CONST char *url,
+ ber_tag_t request,
+ ber_int_t msgid,
+ void *params)
+{
+
+ struct ldap_creds *cp = (struct ldap_creds *) params;
+ url = url;
+ request = request;
+ msgid = msgid;
+ return ldap_bind_s(ld, cp->dn, cp->pw, LDAP_AUTH_SIMPLE);
+}
+
+#endif
+char *
+convert_domain_to_bind_path(char *domain)
+{
+ char *dp, *bindp = NULL, *bp = NULL;
+ int i = 0;
+
+ if (!domain)
+ return NULL;
+
+ for (dp = domain; *dp; dp++) {
+ if (*dp == '.')
+ i++;
+ }
+ /*
+ * add dc= and
+ * replace . with ,dc= => new length = old length + #dots * 3 + 3
+ */
+ bindp = (char *) xmalloc(strlen(domain) + 3 + i * 3 + 1);
+ bp = bindp;
+ strcpy(bp, "dc=");
+ bp += 3;
+ for (dp = domain; *dp; dp++) {
+ if (*dp == '.') {
+ strcpy(bp, ",dc=");
+ bp += 4;
+ } else
+ *bp++ = *dp;
+ }
+ *bp = '\0';
+ return bindp;
+}
+
+char *
+escape_filter(char *filter)
+{
+ int i;
+ char *ldap_filter_esc, *ldf;
+
+ i = 0;
+ for (ldap_filter_esc = filter; *ldap_filter_esc; ldap_filter_esc++) {
+ if ((*ldap_filter_esc == '*') ||
+ (*ldap_filter_esc == '(') ||
+ (*ldap_filter_esc == ')') ||
+ (*ldap_filter_esc == '\\'))
+ i = i + 3;
+ }
+
+ ldap_filter_esc = (char *) xcalloc(strlen(filter) + i + 1, sizeof(char));
+ ldf = ldap_filter_esc;
+ for (; *filter; filter++) {
+ if (*filter == '*') {
+ strcpy(ldf, "\\2a");
+ ldf = ldf + 3;
+ } else if (*filter == '(') {
+ strcpy(ldf, "\\28");
+ ldf = ldf + 3;
+ } else if (*filter == ')') {
+ strcpy(ldf, "\\29");
+ ldf = ldf + 3;
+ } else if (*filter == '\\') {
+ strcpy(ldf, "\\5c");
+ ldf = ldf + 3;
+ } else {
+ *ldf = *filter;
+ ldf++;
+ }
+ }
+ *ldf = '\0';
+
+ return ldap_filter_esc;
+};
+
+int
+check_AD(struct main_args *margs, LDAP * ld)
+{
+ LDAPMessage *res;
+ char **attr_value = NULL;
+ struct timeval searchtime;
+ int max_attr = 0;
+ int j, rc = 0;
+
+#define FILTER_SCHEMA "(objectclass=*)"
+#define ATTRIBUTE_SCHEMA "schemaNamingContext"
+#define FILTER_SAM "(ldapdisplayname=samaccountname)"
+
+ searchtime.tv_sec = SEARCH_TIMEOUT;
+ searchtime.tv_usec = 0;
+
+ debug((char *) "%s| %s: DEBUG: Search ldap server with bind path \"\" and filter: %s\n", LogTime(), PROGRAM, FILTER_SCHEMA);
+ rc = ldap_search_ext_s(ld, (char *) "", LDAP_SCOPE_BASE, (char *) FILTER_SCHEMA, NULL, 0,
+ NULL, NULL, &searchtime, 0, &res);
+
+ if (rc == LDAP_SUCCESS)
+ max_attr = get_attributes(margs, ld, res, ATTRIBUTE_SCHEMA, &attr_value);
+
+ if (max_attr == 1) {
+ ldap_msgfree(res);
+ debug((char *) "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n", LogTime(), PROGRAM, attr_value[0], FILTER_SAM);
+ rc = ldap_search_ext_s(ld, attr_value[0], LDAP_SCOPE_SUBTREE, (char *) FILTER_SAM, NULL, 0,
+ NULL, NULL, &searchtime, 0, &res);
+ debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(), PROGRAM, ldap_count_entries(ld, res), ldap_count_entries(ld, res) > 1 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
+ if (ldap_count_entries(ld, res) > 0)
+ margs->AD = 1;
+ } else
+ debug((char *) "%s| %s: DEBUG: Did not find ldap entry for subschemasubentry\n", LogTime(), PROGRAM);
+ debug((char *) "%s| %s: DEBUG: Determined ldap server %sas an Active Directory server\n", LogTime(), PROGRAM, margs->AD ? "" : "not ");
+ /*
+ * Cleanup
+ */
+ if (attr_value) {
+ for (j = 0; j < max_attr; j++) {
+ xfree(attr_value[j]);
+ }
+ xfree(attr_value);
+ attr_value = NULL;
+ }
+ ldap_msgfree(res);
+ return rc;
+}
+int
+search_group_tree(struct main_args *margs, LDAP * ld, char *bindp, char *ldap_group, char *group, int depth)
+{
+ LDAPMessage *res = NULL;
+ char **attr_value = NULL;
+ int max_attr = 0;
+ char *filter = NULL;
+ char *search_exp = NULL;
+ int j, rc = 0, retval = 0;
+ char *av = NULL, *avp = NULL;
+ int ldepth;
+ char *ldap_filter_esc = NULL;
+ struct timeval searchtime;
+
+#define FILTER_GROUP_AD "(&(%s)(objectclass=group))"
+#define FILTER_GROUP "(&(memberuid=%s)(objectclass=posixgroup))"
+
+ searchtime.tv_sec = SEARCH_TIMEOUT;
+ searchtime.tv_usec = 0;
+
+ if (margs->AD)
+ filter = (char *) FILTER_GROUP_AD;
+ else
+ filter = (char *) FILTER_GROUP;
+
+ ldap_filter_esc = escape_filter(ldap_group);
+
+ search_exp = (char *) xmalloc(strlen(filter) + strlen(ldap_filter_esc) + 1);
+ snprintf(search_exp, strlen(filter) + strlen(ldap_filter_esc) + 1, filter, ldap_filter_esc);
+
+ if (ldap_filter_esc)
+ xfree(ldap_filter_esc);
+
+ if (depth > margs->mdepth) {
+ debug((char *) "%s| %s: DEBUG: Max search depth reached %d>%d\n", LogTime(), PROGRAM, depth, margs->mdepth);
+ return 0;
+ }
+ debug((char *) "%s| %s: DEBUG: Search ldap server with bind path %s and filter : %s\n", LogTime(), PROGRAM, bindp, search_exp);
+ rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE,
+ search_exp, NULL, 0,
+ NULL, NULL, &searchtime, 0, &res);
+ if (search_exp)
+ xfree(search_exp);
+
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error searching ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ ldap_unbind_s(ld);
+ return 0;
+ }
+ debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(), PROGRAM, ldap_count_entries(ld, res), ldap_count_entries(ld, res) > 1 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
+
+ if (margs->AD)
+ max_attr = get_attributes(margs, ld, res, ATTRIBUTE_AD, &attr_value);
+ else
+ max_attr = get_attributes(margs, ld, res, ATTRIBUTE, &attr_value);
+
+ /*
+ * Compare group names
+ */
+ retval = 0;
+ ldepth = depth + 1;
+ for (j = 0; j < max_attr; j++) {
+
+ /* Compare first CN= value assuming it is the same as the group name itself */
+ av = attr_value[j];
+ if (!strncasecmp("CN=", av, 3)) {
+ av += 3;
+ if ((avp = strchr(av, ','))) {
+ *avp = '\0';
+ }
+ }
+ if (debug_enabled) {
+ int n;
+ debug((char *) "%s| %s: DEBUG: Entry %d \"%s\" in hex UTF-8 is ", LogTime(), PROGRAM, j + 1, av);
+ for (n = 0; av[n] != '\0'; n++)
+ fprintf(stderr, "%02x", (unsigned char) av[n]);
+ fprintf(stderr, "\n");
+ }
+ if (!strcasecmp(group, av)) {
+ retval = 1;
+ debug((char *) "%s| %s: DEBUG: Entry %d \"%s\" matches group name \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
+ break;
+ } else
+ debug((char *) "%s| %s: DEBUG: Entry %d \"%s\" does not match group name \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
+ /*
+ * Do recursive group search
+ */
+ debug((char *) "%s| %s: DEBUG: Perform recursive group search for group \"%s\"\n", LogTime(), PROGRAM, av);
+ av = attr_value[j];
+ if (search_group_tree(margs, ld, bindp, av, group, ldepth)) {
+ retval = 1;
+ if (!strncasecmp("CN=", av, 3)) {
+ av += 3;
+ if ((avp = strchr(av, ','))) {
+ *avp = '\0';
+ }
+ }
+ if (debug_enabled)
+ debug((char *) "%s| %s: DEBUG: Entry %d \"%s\" is member of group named \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
+ else
+ break;
+
+ }
+ }
+
+ /*
+ * Cleanup
+ */
+ if (attr_value) {
+ for (j = 0; j < max_attr; j++) {
+ xfree(attr_value[j]);
+ }
+ xfree(attr_value);
+ attr_value = NULL;
+ }
+ ldap_msgfree(res);
+
+ return retval;
+}
+
+int
+ldap_set_defaults(struct main_args *margs, LDAP * ld)
+{
+ int val, rc = 0;
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+ struct timeval tv;
+#endif
+ val = LDAP_VERSION3;
+ rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &val);
+ if (rc != LDAP_SUCCESS) {
+ debug((char *) "%s| %s: DEBUG: Error while setting protocol version: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ return rc;
+ }
+ rc = ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
+ if (rc != LDAP_SUCCESS) {
+ debug((char *) "%s| %s: DEBUG: Error while setting referrals off: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ return rc;
+ }
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+ tv.tv_sec = CONNECT_TIMEOUT;
+ tv.tv_usec = 0;
+ rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
+ if (rc != LDAP_SUCCESS) {
+ debug((char *) "%s| %s: DEBUG: Error while setting network timeout: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ return rc;
+ }
+#endif /* LDAP_OPT_NETWORK_TIMEOUT */
+ return LDAP_SUCCESS;
+}
+
+int
+ldap_set_ssl_defaults(struct main_args *margs)
+{
+#if defined(HAVE_OPENLDAP) || defined(HAVE_LDAPSSL_CLIENT_INIT)
+ int rc = 0;
+#endif
+#ifdef HAVE_OPENLDAP
+ int val;
+ char *ssl_cacertfile = NULL;
+ int free_path;
+#elif defined(HAVE_LDAPSSL_CLIENT_INIT)
+ char *ssl_certdbpath = NULL;
+#endif
+
+#ifdef HAVE_OPENLDAP
+ if (!margs->rc_allow) {
+ debug((char *) "%s| %s: DEBUG: Enable server certificate check for ldap server.\n", LogTime(), PROGRAM);
+ val = LDAP_OPT_X_TLS_DEMAND;
+ rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &val);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_REQUIRE_CERT DEMAND for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ return rc;
+ }
+ ssl_cacertfile = getenv("TLS_CACERTFILE");
+ free_path = 0;
+ if (!ssl_cacertfile) {
+ ssl_cacertfile = xstrdup("/etc/ssl/certs/cert.pem");
+ free_path = 1;
+ }
+ debug((char *) "%s| %s: DEBUG: Set certificate file for ldap server to %s.(Changeable through setting environment variable TLS_CACERTFILE)\n", LogTime(), PROGRAM, ssl_cacertfile);
+ rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ssl_cacertfile);
+ if (ssl_cacertfile && free_path) {
+ xfree(ssl_cacertfile);
+ ssl_cacertfile = NULL;
+ }
+ if (rc != LDAP_OPT_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_CACERTFILE for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ return rc;
+ }
+ } else {
+ debug((char *) "%s| %s: DEBUG: Disable server certificate check for ldap server.\n", LogTime(), PROGRAM);
+ val = LDAP_OPT_X_TLS_ALLOW;
+ rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &val);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_REQUIRE_CERT ALLOW for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ return rc;
+ }
+ }
+#elif defined(HAVE_LDAPSSL_CLIENT_INIT)
+ /*
+ * Solaris SSL ldap calls require path to certificate database
+ */
+ /*
+ * rc = ldapssl_client_init( ssl_certdbpath, NULL );
+ * rc = ldapssl_advclientauth_init( ssl_certdbpath, NULL , 0 , NULL, NULL, 0, NULL, 2);
+ */
+ ssl_certdbpath = getenv("SSL_CERTDBPATH");
+ if (!ssl_certdbpath) {
+ ssl_certdbpath = xstrdup("/etc/certs");
+ }
+ debug((char *) "%s| %s: DEBUG: Set certificate database path for ldap server to %s.(Changeable through setting environment variable SSL_CERTDBPATH)\n", LogTime(), PROGRAM, ssl_certdbpath);
+ if (!margs->rc_allow) {
+ rc = ldapssl_advclientauth_init(ssl_certdbpath, NULL, 0, NULL, NULL, 0, NULL, 2);
+ } else {
+ rc = ldapssl_advclientauth_init(ssl_certdbpath, NULL, 0, NULL, NULL, 0, NULL, 0);
+ debug((char *) "%s| %s: DEBUG: Disable server certificate check for ldap server.\n", LogTime(), PROGRAM);
+ }
+ if (ssl_certdbpath) {
+ xfree(ssl_certdbpath);
+ ssl_certdbpath = NULL;
+ }
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while setting SSL for ldap server: %s\n", LogTime(), PROGRAM, ldapssl_err2string(rc));
+ return rc;
+ }
+#else
+ error((char *) "%s| %s: ERROR: SSL not supported by ldap library\n", LogTime(), PROGRAM);
+#endif
+ return LDAP_SUCCESS;
+}
+
+int
+get_attributes(struct main_args *margs, LDAP * ld, LDAPMessage * res, const char *attribute, char ***ret_value)
+{
+
+ LDAPMessage *msg;
+ char **attr_value = NULL;
+ int max_attr = 0;
+
+ attr_value = *ret_value;
+ /*
+ * loop over attributes
+ */
+ debug((char *) "%s| %s: DEBUG: Search ldap entries for attribute : %s\n", LogTime(), PROGRAM, attribute);
+ for (msg = ldap_first_entry(ld, res); msg; msg = ldap_next_entry(ld, msg)) {
+
+ BerElement *b;
+ char *attr;
+
+ switch (ldap_msgtype(msg)) {
+
+ case LDAP_RES_SEARCH_ENTRY:
+
+ for (attr = ldap_first_attribute(ld, msg, &b); attr;
+ attr = ldap_next_attribute(ld, msg, b)) {
+ if (strcasecmp(attr, attribute) == 0) {
+ struct berval **values;
+ int il;
+
+ if ((values = ldap_get_values_len(ld, msg, attr)) != NULL) {
+ for (il = 0; values[il] != NULL; il++) {
+
+ attr_value = (char **) xrealloc(attr_value, (il + 1) * sizeof(char *));
+ if (!attr_value)
+ break;
+
+ attr_value[il] = (char *) xmalloc(values[il]->bv_len + 1);
+ memcpy(attr_value[il], values[il]->bv_val, values[il]->bv_len);
+ attr_value[il][values[il]->bv_len] = 0;
+ }
+ max_attr = il;
+ }
+ ber_bvecfree(values);
+ }
+ ldap_memfree(attr);
+ }
+ ber_free(b, 0);
+ break;
+ case LDAP_RES_SEARCH_REFERENCE:
+ debug((char *) "%s| %s: DEBUG: Received a search reference message\n", LogTime(), PROGRAM);
+ break;
+ case LDAP_RES_SEARCH_RESULT:
+ debug((char *) "%s| %s: DEBUG: Received a search result message\n", LogTime(), PROGRAM);
+ break;
+ default:
+ break;
+ }
+ }
+
+ debug((char *) "%s| %s: DEBUG: %d ldap entr%s found with attribute : %s\n", LogTime(), PROGRAM, max_attr, max_attr > 1 || max_attr == 0 ? "ies" : "y", attribute);
+
+ *ret_value = attr_value;
+ return max_attr;
+}
+
+/*
+ * call to open ldap server with or without SSL
+ */
+LDAP *
+tool_ldap_open(struct main_args * margs, char *host, int port, char *ssl)
+{
+ LDAP *ld;
+#ifdef HAVE_OPENLDAP
+ LDAPURLDesc *url = NULL;
+ char *ldapuri = NULL;
+#endif
+ int rc = 0;
+
+ /*
+ * Use ldap open here to check if TCP connection is possible. If possible use it.
+ * (Not sure if this is the best way)
+ */
+#ifdef HAVE_OPENLDAP
+ url = (LDAPURLDesc *) xmalloc(sizeof(*url));
+ memset(url, 0, sizeof(*url));
+#ifdef HAVE_LDAP_URL_LUD_SCHEME
+ if (ssl)
+ url->lud_scheme = (char *) "ldaps";
+ else
+ url->lud_scheme = (char *) "ldap";
+#endif
+ url->lud_host = host;
+ url->lud_port = port;
+#ifdef HAVE_LDAP_SCOPE_DEFAULT
+ url->lud_scope = LDAP_SCOPE_DEFAULT;
+#else
+ url->lud_scope = LDAP_SCOPE_SUBTREE;
+#endif
+#ifdef HAVE_LDAP_URL_DESC2STR
+ ldapuri = ldap_url_desc2str(url);
+#elif defined(HAVE_LDAP_URL_PARSE)
+ rc = ldap_url_parse(ldapuri, &url);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while parsing url: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ if (ldapuri)
+ xfree(ldapuri);
+ if (url)
+ xfree(url);
+ return NULL;
+ }
+#else
+#error "No URL parsing function"
+#endif
+ if (url) {
+ xfree(url);
+ url = NULL;
+ }
+ rc = ldap_initialize(&ld, ldapuri);
+ if (ldapuri)
+ xfree(ldapuri);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while initialising connection to ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ ldap_unbind(ld);
+ ld = NULL;
+ return NULL;
+ }
+#else
+ ld = ldap_init(host, port);
+#endif
+ rc = ldap_set_defaults(margs, ld);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while setting default options for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ ldap_unbind(ld);
+ ld = NULL;
+ return NULL;
+ }
+ if (ssl) {
+ /*
+ * Try Start TLS first
+ */
+ debug((char *) "%s| %s: DEBUG: Set SSL defaults\n", LogTime(), PROGRAM);
+ rc = ldap_set_ssl_defaults(margs);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while setting SSL default options for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ ldap_unbind(ld);
+ ld = NULL;
+ return NULL;
+ }
+#ifdef HAVE_OPENLDAP
+ /*
+ * Use tls if possible
+ */
+ rc = ldap_start_tls_s(ld, NULL, NULL);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while setting start_tls for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ ldap_unbind(ld);
+ ld = NULL;
+ url = (LDAPURLDesc *) xmalloc(sizeof(*url));
+ memset(url, 0, sizeof(*url));
+#ifdef HAVE_LDAP_URL_LUD_SCHEME
+ url->lud_scheme = (char *) "ldaps";
+#endif
+ url->lud_host = host;
+ url->lud_port = port;
+#ifdef HAVE_LDAP_SCOPE_DEFAULT
+ url->lud_scope = LDAP_SCOPE_DEFAULT;
+#else
+ url->lud_scope = LDAP_SCOPE_SUBTREE;
+#endif
+#ifdef HAVE_LDAP_URL_DESC2STR
+ ldapuri = ldap_url_desc2str(url);
+#elif defined(HAVE_LDAP_URL_PARSE)
+ rc = ldap_url_parse(ldapuri, &url);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while parsing url: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ if (ldapuri)
+ xfree(ldapuri);
+ if (url)
+ xfree(url);
+ return NULL;
+ }
+#else
+#error "No URL parsing function"
+#endif
+ if (url) {
+ xfree(url);
+ url = NULL;
+ }
+ rc = ldap_initialize(&ld, ldapuri);
+ if (ldapuri)
+ xfree(ldapuri);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while initialising connection to ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ ldap_unbind(ld);
+ ld = NULL;
+ return NULL;
+ }
+ rc = ldap_set_defaults(margs, ld);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while setting default options for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ ldap_unbind(ld);
+ ld = NULL;
+ return NULL;
+ }
+ }
+#elif defined(HAVE_LDAPSSL_CLIENT_INIT)
+ ld = ldapssl_init(host, port, 1);
+ if (!ld) {
+ error((char *) "%s| %s: ERROR: Error while setting SSL for ldap server: %s\n", LogTime(), PROGRAM, ldapssl_err2string(rc));
+ ldap_unbind(ld);
+ ld = NULL;
+ return NULL;
+ }
+ rc = ldap_set_defaults(margs, ld);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while setting default options for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ ldap_unbind(ld);
+ ld = NULL;
+ return NULL;
+ }
+#else
+ error((char *) "%s| %s: ERROR: SSL not supported by ldap library\n", LogTime(), PROGRAM);
+#endif
+ }
+ return ld;
+}
+
+/*
+ * ldap calls to get attribute from Ldap Directory Server
+ */
+int
+get_memberof(struct main_args *margs, char *user, char *domain, char *group)
+{
+ LDAP *ld = NULL;
+ LDAPMessage *res;
+#ifndef HAVE_SUN_LDAP_SDK
+ int ldap_debug = 0;
+#endif
+ struct ldap_creds *lcreds = NULL;
+ char *bindp = NULL;
+ char *filter = NULL;
+ char *search_exp;
+ struct timeval searchtime;
+ int i, j, rc = 0, kc = 1;
+ int retval;
+ char **attr_value = NULL;
+ char *av = NULL, *avp = NULL;
+ int max_attr = 0;
+ struct hstruct *hlist = NULL;
+ int nhosts = 0;
+ char *hostname;
+ char *host;
+ int port;
+ char *ssl = NULL;
+ char *p;
+ char *ldap_filter_esc = NULL;
+
+
+ searchtime.tv_sec = SEARCH_TIMEOUT;
+ searchtime.tv_usec = 0;
+ /*
+ * Fill Kerberos memory cache with credential from keytab for SASL/GSSAPI
+ */
+ if (domain) {
+ debug((char *) "%s| %s: DEBUG: Setup Kerberos credential cache\n", LogTime(), PROGRAM);
+
+ kc = krb5_create_cache(margs, domain);
+ if (kc) {
+ error((char *) "%s| %s: ERROR: Error during setup of Kerberos credential cache\n", LogTime(), PROGRAM);
+ }
+ }
+ if (kc && (!margs->lurl || !margs->luser | !margs->lpass)) {
+ /*
+ * If Kerberos fails and no url given exit here
+ */
+ retval = 0;
+ goto cleanup;
+ }
+#ifndef HAVE_SUN_LDAP_SDK
+ /*
+ * Initialise ldap
+ */
+ ldap_debug = 127 /* LDAP_DEBUG_TRACE */ ;
+ ldap_debug = -1 /* LDAP_DEBUG_ANY */ ;
+ ldap_debug = 0;
+ (void) ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &ldap_debug);
+#endif
+ debug((char *) "%s| %s: DEBUG: Initialise ldap connection\n", LogTime(), PROGRAM);
+
+ if (domain && !kc) {
+ if (margs->ssl) {
+ debug((char *) "%s| %s: DEBUG: Enable SSL to ldap servers\n", LogTime(), PROGRAM);
+ }
+ debug((char *) "%s| %s: DEBUG: Canonicalise ldap server name for domain %s\n", LogTime(), PROGRAM, domain);
+ /*
+ * Loop over list of ldap servers of users domain
+ */
+ nhosts = get_ldap_hostname_list(margs, &hlist, 0, domain);
+ for (i = 0; i < nhosts; i++) {
+ port = 389;
+ if (hlist[i].port != -1)
+ port = hlist[i].port;
+ debug((char *) "%s| %s: DEBUG: Setting up connection to ldap server %s:%d\n", LogTime(), PROGRAM, hlist[i].host, port);
+
+ ld = tool_ldap_open(margs, hlist[i].host, port, margs->ssl);
+ if (!ld)
+ continue;
+
+ /*
+ * ldap bind with SASL/GSSAPI authentication (only possible if a domain was part of the username)
+ */
+
+#if defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H) || defined(HAVE_SASL_DARWIN)
+ debug((char *) "%s| %s: DEBUG: Bind to ldap server with SASL/GSSAPI\n", LogTime(), PROGRAM);
+
+ rc = tool_sasl_bind(ld, bindp, margs->ssl);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while binding to ldap server with SASL/GSSAPI: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ ldap_unbind(ld);
+ ld = NULL;
+ continue;
+ }
+ lcreds = (ldap_creds *) xmalloc(sizeof(struct ldap_creds));
+ lcreds->dn = bindp ? xstrdup(bindp) : NULL;
+ lcreds->pw = margs->ssl ? xstrdup(margs->ssl) : NULL;
+ ldap_set_rebind_proc(ld, ldap_sasl_rebind, (char *) lcreds);
+ if (ld != NULL) {
+ debug((char *) "%s| %s: DEBUG: %s initialised %sconnection to ldap server %s:%d\n", LogTime(), PROGRAM, ld ? "Successfully" : "Failed to", margs->ssl ? "SSL protected " : "", hlist[i].host, port);
+ break;
+ }
+#else
+ ldap_unbind(ld);
+ ld = NULL;
+ error((char *) "%s| %s: ERROR: SASL not supported on system\n", LogTime(), PROGRAM);
+ continue;
+#endif
+ }
+ nhosts = free_hostname_list(&hlist, nhosts);
+ if (ld == NULL) {
+ debug((char *) "%s| %s: DEBUG: Error during initialisation of ldap connection: %s\n", LogTime(), PROGRAM, strerror(errno));
+ }
+ bindp = convert_domain_to_bind_path(domain);
+ }
+ if ((!domain || !ld) && margs->lurl && strstr(margs->lurl, "://")) {
+ /*
+ * If username does not contain a domain and a url was given then try it
+ */
+ hostname = strstr(margs->lurl, "://") + 3;
+ ssl = strstr(margs->lurl, "ldaps://");
+ if (ssl) {
+ debug((char *) "%s| %s: DEBUG: Enable SSL to ldap servers\n", LogTime(), PROGRAM);
+ }
+ debug((char *) "%s| %s: DEBUG: Canonicalise ldap server name %s\n", LogTime(), PROGRAM, hostname);
+ /*
+ * Loop over list of ldap servers
+ */
+ host = xstrdup(hostname);
+ port = 389;
+ if ((p = strchr(host, ':'))) {
+ *p = '\0';
+ p++;
+ port = atoi(p);
+ }
+ nhosts = get_hostname_list(margs, &hlist, 0, host);
+ if (host)
+ xfree(host);
+ host = NULL;
+ for (i = 0; i < nhosts; i++) {
+
+ ld = tool_ldap_open(margs, hlist[i].host, port, ssl);
+ if (!ld)
+ continue;
+ /*
+ * ldap bind with username/password authentication
+ */
+
+ debug((char *) "%s| %s: DEBUG: Bind to ldap server with Username/Password\n", LogTime(), PROGRAM);
+ rc = ldap_simple_bind_s(ld, margs->luser, margs->lpass);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error while binding to ldap server with Username/Password: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ ldap_unbind(ld);
+ ld = NULL;
+ continue;
+ }
+ lcreds = (ldap_creds *) xmalloc(sizeof(struct ldap_creds));
+ lcreds->dn = xstrdup(margs->luser);
+ lcreds->pw = xstrdup(margs->lpass);
+ ldap_set_rebind_proc(ld, ldap_simple_rebind, (char *) lcreds);
+ debug((char *) "%s| %s: DEBUG: %s set up %sconnection to ldap server %s:%d\n", LogTime(), PROGRAM, ld ? "Successfully" : "Failed to", ssl ? "SSL protected " : "", hlist[i].host, port);
+ break;
+
+ }
+ nhosts = free_hostname_list(&hlist, nhosts);
+ if (bindp)
+ xfree(bindp);
+ if (margs->lbind) {
+ bindp = xstrdup(margs->lbind);
+ } else {
+ bindp = convert_domain_to_bind_path(domain);
+ }
+ }
+ if (ld == NULL) {
+ debug((char *) "%s| %s: DEBUG: Error during initialisation of ldap connection: %s\n", LogTime(), PROGRAM, strerror(errno));
+ retval = 0;
+ goto cleanup;
+ }
+ /*
+ * ldap search for user
+ */
+ /*
+ * Check if server is AD by querying for attribute samaccountname
+ */
+ margs->AD = 0;
+ rc = check_AD(margs, ld);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error determining ldap server type: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ ldap_unbind(ld);
+ ld = NULL;
+ retval = 0;
+ goto cleanup;
+ }
+ if (margs->AD)
+ filter = (char *) FILTER_AD;
+ else
+ filter = (char *) FILTER;
+
+ ldap_filter_esc = escape_filter(user);
+
+ search_exp = (char *) xmalloc(strlen(filter) + strlen(ldap_filter_esc) + 1);
+ snprintf(search_exp, strlen(filter) + strlen(ldap_filter_esc) + 1, filter, ldap_filter_esc);
+
+ if (ldap_filter_esc)
+ xfree(ldap_filter_esc);
+
+ debug((char *) "%s| %s: DEBUG: Search ldap server with bind path %s and filter : %s\n", LogTime(), PROGRAM, bindp, search_exp);
+ rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE,
+ search_exp, NULL, 0,
+ NULL, NULL, &searchtime, 0, &res);
+ if (search_exp)
+ xfree(search_exp);
+
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error searching ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ ldap_unbind(ld);
+ ld = NULL;
+ retval = 0;
+ goto cleanup;
+ }
+ debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(), PROGRAM, ldap_count_entries(ld, res), ldap_count_entries(ld, res) > 1 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
+
+ if (ldap_count_entries(ld, res) != 0) {
+
+ if (margs->AD)
+ max_attr = get_attributes(margs, ld, res, ATTRIBUTE_AD, &attr_value);
+ else {
+ max_attr = get_attributes(margs, ld, res, ATTRIBUTE, &attr_value);
+ }
+
+ /*
+ * Compare group names
+ */
+ retval = 0;
+ for (j = 0; j < max_attr; j++) {
+
+ /* Compare first CN= value assuming it is the same as the group name itself */
+ av = attr_value[j];
+ if (!strncasecmp("CN=", av, 3)) {
+ av += 3;
+ if ((avp = strchr(av, ','))) {
+ *avp = '\0';
+ }
+ }
+ if (debug_enabled) {
+ int n;
+ debug((char *) "%s| %s: DEBUG: Entry %d \"%s\" in hex UTF-8 is ", LogTime(), PROGRAM, j + 1, av);
+ for (n = 0; av[n] != '\0'; n++)
+ fprintf(stderr, "%02x", (unsigned char) av[n]);
+ fprintf(stderr, "\n");
+ }
+ if (!strcasecmp(group, av)) {
+ retval = 1;
+ if (debug_enabled)
+ debug((char *) "%s| %s: DEBUG: Entry %d \"%s\" matches group name \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
+ else
+ break;
+ } else
+ debug((char *) "%s| %s: DEBUG: Entry %d \"%s\" does not match group name \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
+ }
+ /*
+ * Do recursive group search for AD only since posixgroups can not contain other groups
+ */
+ if (!retval && margs->AD) {
+ if (debug_enabled && max_attr > 0) {
+ debug((char *) "%s| %s: DEBUG: Perform recursive group search\n", LogTime(), PROGRAM);
+ }
+ for (j = 0; j < max_attr; j++) {
+
+ av = attr_value[j];
+ if (search_group_tree(margs, ld, bindp, av, group, 1)) {
+ retval = 1;
+ if (!strncasecmp("CN=", av, 3)) {
+ av += 3;
+ if ((avp = strchr(av, ','))) {
+ *avp = '\0';
+ }
+ }
+ if (debug_enabled)
+ debug((char *) "%s| %s: DEBUG: Entry %d group \"%s\" is (in)direct member of group \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
+ else
+ break;
+ }
+ }
+ }
+ /*
+ * Cleanup
+ */
+ if (attr_value) {
+ for (j = 0; j < max_attr; j++) {
+ xfree(attr_value[j]);
+ }
+ xfree(attr_value);
+ attr_value = NULL;
+ }
+ ldap_msgfree(res);
+ } else if (ldap_count_entries(ld, res) == 0 && margs->AD) {
+ ldap_msgfree(res);
+ ldap_unbind(ld);
+ ld = NULL;
+ retval = 0;
+ goto cleanup;
+ } else {
+ ldap_msgfree(res);
+ retval = 0;
+ }
+
+ if (!margs->AD && retval == 0) {
+ /*
+ * Check for primary Group membership
+ */
+ debug((char *) "%s| %s: DEBUG: Search for primary group membership: \"%s\"\n", LogTime(), PROGRAM, group);
+ filter = (char *) FILTER_UID;
+
+ ldap_filter_esc = escape_filter(user);
+
+ search_exp = (char *) xmalloc(strlen(filter) + strlen(ldap_filter_esc) + 1);
+ snprintf(search_exp, strlen(filter) + strlen(ldap_filter_esc) + 1, filter, ldap_filter_esc);
+
+ if (ldap_filter_esc)
+ xfree(ldap_filter_esc);
+
+ debug((char *) "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n", LogTime(), PROGRAM, bindp, search_exp);
+ rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE,
+ search_exp, NULL, 0,
+ NULL, NULL, &searchtime, 0, &res);
+ if (search_exp)
+ xfree(search_exp);
+
+ debug((char *) "%s| %s: DEBUG: Found %d ldap entr%s\n", LogTime(), PROGRAM, ldap_count_entries(ld, res), ldap_count_entries(ld, res) > 1 || ldap_count_entries(ld, res) == 0 ? "ies" : "y");
+
+ max_attr = get_attributes(margs, ld, res, ATTRIBUTE_GID, &attr_value);
+
+ if (max_attr == 1) {
+ char **attr_value_2 = NULL;
+ int max_attr_2 = 0;
+
+ ldap_msgfree(res);
+ filter = (char *) FILTER_GID;
+
+ ldap_filter_esc = escape_filter(attr_value[0]);
+
+ search_exp = (char *) xmalloc(strlen(filter) + strlen(ldap_filter_esc) + 1);
+ snprintf(search_exp, strlen(filter) + strlen(ldap_filter_esc) + 1, filter, ldap_filter_esc);
+
+ if (ldap_filter_esc)
+ xfree(ldap_filter_esc);
+
+ debug((char *) "%s| %s: DEBUG: Search ldap server with bind path %s and filter: %s\n", LogTime(), PROGRAM, bindp, search_exp);
+ rc = ldap_search_ext_s(ld, bindp, LDAP_SCOPE_SUBTREE,
+ search_exp, NULL, 0,
+ NULL, NULL, &searchtime, 0, &res);
+ if (search_exp)
+ xfree(search_exp);
+
+ max_attr_2 = get_attributes(margs, ld, res, ATTRIBUTE, &attr_value_2);
+ /*
+ * Compare group names
+ */
+ retval = 0;
+ if (max_attr_2 == 1) {
+
+ /* Compare first CN= value assuming it is the same as the group name itself */
+ av = attr_value_2[0];
+ if (!strcasecmp(group, av)) {
+ retval = 1;
+ debug((char *) "%s| %s: DEBUG: \"%s\" matches group name \"%s\"\n", LogTime(), PROGRAM, av, group);
+ } else
+ debug((char *) "%s| %s: DEBUG: \"%s\" does not match group name \"%s\"\n", LogTime(), PROGRAM, av, group);
+
+ }
+ /*
+ * Cleanup
+ */
+ if (attr_value_2) {
+ for (j = 0; j < max_attr_2; j++) {
+ xfree(attr_value_2[j]);
+ }
+ xfree(attr_value_2);
+ attr_value_2 = NULL;
+ }
+ ldap_msgfree(res);
+
+ debug((char *) "%s| %s: DEBUG: Users primary group %s %s\n", LogTime(), PROGRAM, retval ? "matches" : "does not match", group);
+
+ } else
+ debug((char *) "%s| %s: DEBUG: Did not find ldap entry for group %s\n", LogTime(), PROGRAM, group);
+ /*
+ * Cleanup
+ */
+ if (attr_value) {
+ for (j = 0; j < max_attr; j++) {
+ xfree(attr_value[j]);
+ }
+ xfree(attr_value);
+ attr_value = NULL;
+ }
+ }
+ rc = ldap_unbind(ld);
+ ld = NULL;
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Error unbind ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ }
+ debug((char *) "%s| %s: DEBUG: Unbind ldap server\n", LogTime(), PROGRAM);
+cleanup:
+ if (domain)
+ krb5_cleanup();
+ if (lcreds) {
+ if (lcreds->dn)
+ xfree(lcreds->dn);
+ if (lcreds->pw)
+ xfree(lcreds->pw);
+ xfree(lcreds);
+ }
+ if (bindp)
+ xfree(bindp);
+ bindp = NULL;
+ return (retval);
+
+}
+#endif
--- /dev/null
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * Author: Markus Moeller (markus_moeller at compuserve.com)
+ *
+ * Copyright (C) 2007 Markus Moeller. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#include "config.h"
+
+#ifdef HAVE_LDAP
+
+#include "support.h"
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+const char *
+LogTime()
+{
+ struct tm *tm;
+ struct timeval now;
+ static time_t last_t = 0;
+ static char buf[128];
+
+ gettimeofday(&now, NULL);
+ if (now.tv_sec != last_t) {
+ tm = localtime(&now.tv_sec);
+ strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
+ last_t = now.tv_sec;
+ }
+ return buf;
+}
+/* default off */
+int log_enabled = 0;
+
+#ifndef __GNUC__
+/* under gcc a macro define in compat/debug.h is used instead */
+
+void
+log(char *format,...)
+{
+ if (!log_enabled)
+ return;
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+void
+error(char *format,...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+void
+warn(char *format,...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+#endif /* __GNUC__ */
+#endif
--- /dev/null
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * Author: Markus Moeller (markus_moeller at compuserve.com)
+ *
+ * Copyright (C) 2007 Markus Moeller. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#include "config.h"
+#include "util.h"
+
+#ifdef HAVE_LDAP
+
+#include "support.h"
+
+int
+check_memberof(struct main_args *margs, char *user, char *domain)
+{
+
+ /*
+ * Check order:
+ *
+ * 1. Check domain against list of groups per domain
+ * 1a. If domain does not exist in list try default domain
+ * 1b. If default domain does not exist use default group against ldap url with user/password
+ * 1c. If default group does not exist exit with error.
+ * 2. Query ldap membership
+ * 2a. Use GSSAPI/SASL with HTTP/fqdn@DOMAIN credentials from keytab
+ * 2b. Use username/password with TLS
+ *
+ */
+ struct gdstruct *gr;
+ int found = 0;
+
+
+ /* Check users domain */
+
+ gr = margs->groups;
+ while (gr && domain) {
+ debug((char *) "%s| %s: DEBUG: User domain loop: group@domain %s@%s\n", LogTime(), PROGRAM, gr->group, gr->domain ? gr->domain : "NULL");
+ if (gr->domain && !strcasecmp(gr->domain, domain)) {
+ debug((char *) "%s| %s: DEBUG: Found group@domain %s@%s\n", LogTime(), PROGRAM, gr->group, gr->domain);
+ /* query ldap */
+ if (get_memberof(margs, user, domain, gr->group)) {
+ if (debug_enabled)
+ debug((char *) "%s| %s: INFO: User %s is member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain);
+ else
+ log((char *) "%s| %s: INFO: User %s is member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain);
+ found++;
+ break;
+ } else {
+ if (debug_enabled)
+ debug((char *) "%s| %s: INFO: User %s is not member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain);
+ else
+ log((char *) "%s| %s: INFO: User %s is not member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain);
+ }
+ }
+ gr = gr->next;
+ }
+
+ if (found)
+ return (1);
+
+ /* Check default domain */
+
+ gr = margs->groups;
+ while (gr && domain) {
+ debug((char *) "%s| %s: DEBUG: Default domain loop: group@domain %s@%s\n", LogTime(), PROGRAM, gr->group, gr->domain ? gr->domain : "NULL");
+ if (gr->domain && !strcasecmp(gr->domain, "")) {
+ debug((char *) "%s| %s: DEBUG: Found group@domain %s@%s\n", LogTime(), PROGRAM, gr->group, gr->domain);
+ /* query ldap */
+ if (get_memberof(margs, user, domain, gr->group)) {
+ if (debug_enabled)
+ debug((char *) "%s| %s: INFO: User %s is member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain);
+ else
+ log((char *) "%s| %s: INFO: User %s is member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain);
+ found++;
+ break;
+ } else {
+ if (debug_enabled)
+ debug((char *) "%s| %s: INFO: User %s is not member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain);
+ else
+ log((char *) "%s| %s: INFO: User %s is not member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain);
+ }
+ }
+ gr = gr->next;
+ }
+
+ if (found)
+ return (1);
+
+ /* Check default group with ldap url */
+
+ gr = margs->groups;
+ while (gr) {
+ debug((char *) "%s| %s: DEBUG: Default group loop: group@domain %s@%s\n", LogTime(), PROGRAM, gr->group, gr->domain ? gr->domain : "NULL");
+ if (!gr->domain) {
+ debug((char *) "%s| %s: DEBUG: Found group@domain %s@%s\n", LogTime(), PROGRAM, gr->group, gr->domain ? gr->domain : "NULL");
+ /* query ldap */
+ if (get_memberof(margs, user, domain, gr->group)) {
+ if (debug_enabled)
+ debug((char *) "%s| %s: INFO: User %s is member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain ? gr->domain : "NULL");
+ else
+ log((char *) "%s| %s: INFO: User %s is member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain ? gr->domain : "NULL");
+ found++;
+ break;
+ } else {
+ if (debug_enabled)
+ debug((char *) "%s| %s: INFO: User %s is not member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain ? gr->domain : "NULL");
+ else
+ log((char *) "%s| %s: INFO: User %s is not member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain ? gr->domain : "NULL");
+ }
+ }
+ gr = gr->next;
+ }
+
+ if (found)
+ return (1);
+
+ return (0);
+}
+#endif
--- /dev/null
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * Author: Markus Moeller (markus_moeller at compuserve.com)
+ *
+ * Copyright (C) 2007 Markus Moeller. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#include "config.h"
+#include "util.h"
+
+#ifdef HAVE_LDAP
+
+#include "support.h"
+
+struct ndstruct *init_nd(void);
+
+struct ndstruct *
+init_nd(void) {
+ struct ndstruct *ndsp;
+ ndsp = (struct ndstruct *) xmalloc(sizeof(struct ndstruct));
+ ndsp->netbios = NULL;
+ ndsp->domain = NULL;
+ ndsp->next = NULL;
+ return ndsp;
+}
+
+int
+create_nd(struct main_args *margs)
+{
+ char *np, *dp;
+ char *p;
+ struct ndstruct *ndsp = NULL, *ndspn = NULL;
+ /*
+ * netbios list format:
+ *
+ * nlist=Pattern1[:Pattern2]
+ *
+ * Pattern=NetbiosName@Domain Netbios Name for a specific Kerberos domain
+ * ndstruct.domain=Domain, ndstruct.netbios=NetbiosName
+ *
+ *
+ */
+ p = margs->nlist;
+ np = margs->nlist;
+ debug((char *) "%s| %s: DEBUG: Netbios list %s\n", LogTime(), PROGRAM, margs->nlist ? margs->nlist : "NULL");
+ dp = NULL;
+
+ if (!p) {
+ debug((char *) "%s| %s: DEBUG: No netbios names defined.\n", LogTime(), PROGRAM);
+ return (0);
+ }
+ while (*p) { /* loop over group list */
+ if (*p == '\n' || *p == '\r') { /* Ignore CR and LF if exist */
+ p++;
+ continue;
+ }
+ if (*p == '@') { /* end of group name - start of domain name */
+ if (p == np) { /* empty group name not allowed */
+ debug((char *) "%s| %s: DEBUG: No netbios name defined for domain %s\n", LogTime(), PROGRAM, p);
+ return (1);
+ }
+ *p = '\0';
+ p++;
+ ndsp = init_nd();
+ ndsp->netbios = xstrdup(np);
+ if (ndspn) /* Have already an existing structure */
+ ndsp->next = ndspn;
+ dp = p; /* after @ starts new domain name */
+ } else if (*p == ':') { /* end of group name or end of domain name */
+ if (p == np) { /* empty group name not allowed */
+ debug((char *) "%s| %s: DEBUG: No netbios name defined for domain %s\n", LogTime(), PROGRAM, p);
+ return (1);
+ }
+ *p = '\0';
+ p++;
+ if (dp) { /* end of domain name */
+ ndsp->domain = xstrdup(dp);
+ dp = NULL;
+ } else { /* end of group name and no domain name */
+ ndsp = init_nd();
+ ndsp->netbios = xstrdup(np);
+ if (ndspn) /* Have already an existing structure */
+ ndsp->next = ndspn;
+ }
+ ndspn = ndsp;
+ np = p; /* after : starts new group name */
+ if (!ndsp->domain || !strcmp(ndsp->domain, "")) {
+ debug((char *) "%s| %s: DEBUG: No domain defined for netbios name %s\n", LogTime(), PROGRAM, ndsp->netbios);
+ return (1);
+ }
+ debug((char *) "%s| %s: DEBUG: Netbios name %s Domain %s\n", LogTime(), PROGRAM, ndsp->netbios, ndsp->domain);
+ } else
+ p++;
+ }
+ if (p == np) { /* empty group name not allowed */
+ debug((char *) "%s| %s: DEBUG: No netbios name defined for domain %s\n", LogTime(), PROGRAM, p);
+ return (1);
+ }
+ if (dp) { /* end of domain name */
+ ndsp->domain = xstrdup(dp);
+ } else { /* end of group name and no domain name */
+ ndsp = init_nd();
+ ndsp->netbios = xstrdup(np);
+ if (ndspn) /* Have already an existing structure */
+ ndsp->next = ndspn;
+ }
+ if (!ndsp->domain || !strcmp(ndsp->domain, "")) {
+ debug((char *) "%s| %s: DEBUG: No domain defined for netbios name %s\n", LogTime(), PROGRAM, ndsp->netbios);
+ return (1);
+ }
+ debug((char *) "%s| %s: DEBUG: Netbios name %s Domain %s\n", LogTime(), PROGRAM, ndsp->netbios, ndsp->domain);
+
+ margs->ndoms = ndsp;
+ return (0);
+}
+
+char *
+get_netbios_name(struct main_args *margs, char *netbios)
+{
+ struct ndstruct *nd;
+
+ nd = margs->ndoms;
+ while (nd && netbios) {
+ debug((char *) "%s| %s: DEBUG: Netbios domain loop: netbios@domain %s@%s\n", LogTime(), PROGRAM, nd->netbios, nd->domain);
+ if (nd->netbios && !strcasecmp(nd->netbios, netbios)) {
+ debug((char *) "%s| %s: DEBUG: Found netbios@domain %s@%s\n", LogTime(), PROGRAM, nd->netbios, nd->domain);
+ return (nd->domain);
+ }
+ nd = nd->next;
+ }
+
+ return NULL;
+}
+#endif
--- /dev/null
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * Author: Markus Moeller (markus_moeller at compuserve.com)
+ *
+ * Copyright (C) 2007 Markus Moeller. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#include "config.h"
+#include "util.h"
+
+#ifdef HAVE_LDAP
+
+#include "support.h"
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_RESOLV_H
+#include <resolv.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+
+void nsError(int nserror, char *server);
+static int compare_hosts(struct hstruct *h1, struct hstruct *h2);
+static void swap(struct hstruct *a, struct hstruct *b);
+static void sort(struct hstruct *array, int nitems, int (*cmp) (struct hstruct *, struct hstruct *), int begin, int end);
+static void msort(struct hstruct *array, size_t nitems, int (*cmp) (struct hstruct *, struct hstruct *));
+
+/*
+ * See http://www.ietf.org/rfc/rfc1035.txt
+ */
+/*
+ * See http://www.ietf.org/rfc/rfc2782.txt
+ *
+ */
+void
+nsError(int nserror, char *service)
+{
+ switch (nserror) {
+ case HOST_NOT_FOUND:
+ error((char *) "%s| %s: ERROR: res_search: Unknown service record: %s\n", LogTime(), PROGRAM, service);
+ break;
+ case NO_DATA:
+ error((char *) "%s| %s: ERROR: res_search: No SRV record for %s\n", LogTime(), PROGRAM, service);
+ break;
+ case TRY_AGAIN:
+ error((char *) "%s| %s: ERROR: res_search: No response for SRV query\n", LogTime(), PROGRAM);
+ break;
+ default:
+ error((char *) "%s| %s: ERROR: res_search: Unexpected error: %s\n", LogTime(), PROGRAM, strerror(nserror));
+ }
+}
+
+static void
+swap(struct hstruct *a, struct hstruct *b)
+{
+ struct hstruct c;
+
+ c.host = a->host;
+ c.priority = a->priority;
+ c.weight = a->weight;
+ a->priority = b->priority;
+ a->weight = b->weight;
+ b->host = c.host;
+ b->priority = c.priority;
+ b->weight = c.weight;
+}
+
+static void
+sort(struct hstruct *array, int nitems, int (*cmp) (struct hstruct *, struct hstruct *), int begin, int end)
+{
+ if (end > begin) {
+ int pivot = begin;
+ int l = begin + 1;
+ int r = end;
+ while (l < r) {
+ if (cmp(&array[l], &array[pivot]) <= 0) {
+ l += 1;
+ } else {
+ r -= 1;
+ swap(&array[l], &array[r]);
+ }
+ }
+ l -= 1;
+ swap(&array[begin], &array[l]);
+ sort(array, nitems, cmp, begin, l);
+ sort(array, nitems, cmp, r, end);
+ }
+}
+
+static void
+msort(struct hstruct *array, size_t nitems, int (*cmp) (struct hstruct *, struct hstruct *))
+{
+ sort(array, nitems, cmp, 0, nitems - 1);
+}
+
+static int
+compare_hosts(struct hstruct *host1, struct hstruct *host2)
+{
+ /*
+ *
+ * The comparison function must return an integer less than, equal to,
+ * or greater than zero if the first argument is considered to be
+ * respectively less than, equal to, or greater than the second.
+ */
+ if ((host1->priority < host2->priority) && (host1->priority != -1))
+ return -1;
+ if ((host1->priority < host2->priority) && (host1->priority == -1))
+ return 1;
+ if ((host1->priority > host2->priority) && (host2->priority != -1))
+ return 1;
+ if ((host1->priority > host2->priority) && (host2->priority == -1))
+ return -1;
+ if (host1->priority == host2->priority) {
+ if (host1->weight > host2->weight)
+ return -1;
+ if (host1->weight < host2->weight)
+ return 1;
+ }
+ return 0;
+}
+
+int
+free_hostname_list(struct hstruct **hlist, int nhosts)
+{
+ struct hstruct *hp = NULL;
+ int i;
+
+ hp = *hlist;
+ for (i = 0; i < nhosts; i++) {
+ if (hp[i].host)
+ xfree(hp[i].host);
+ hp[i].host = NULL;
+ }
+
+
+ if (hp)
+ xfree(hp);
+ hp = NULL;
+ *hlist = hp;
+ return 0;
+}
+
+int
+get_hostname_list(struct main_args *margs, struct hstruct **hlist, int nhosts, char *name)
+{
+ /*
+ * char host[sysconf(_SC_HOST_NAME_MAX)];
+ */
+ char host[1024];
+ struct addrinfo *hres = NULL, *hres_list;
+ int rc, count;
+ struct hstruct *hp = NULL;
+
+ if (!name)
+ return (nhosts);
+
+ hp = *hlist;
+ rc = getaddrinfo((const char *) name, NULL, NULL, &hres);
+ if (rc != 0) {
+ error((char *) "%s| %s: ERROR: Error while resolving hostname with getaddrinfo: %s\n", LogTime(), PROGRAM, gai_strerror(rc));
+ return (nhosts);
+ }
+ hres_list = hres;
+ count = 0;
+ while (hres_list) {
+ count++;
+ hres_list = hres_list->ai_next;
+ }
+ hres_list = hres;
+ count = 0;
+ while (hres_list) {
+ rc = getnameinfo(hres_list->ai_addr, hres_list->ai_addrlen, host, sizeof(host), NULL, 0, 0);
+ if (rc != 0) {
+ error((char *) "%s| %s: ERROR: Error while resolving ip address with getnameinfo: %s\n", LogTime(), PROGRAM, gai_strerror(rc));
+ freeaddrinfo(hres);
+ *hlist = hp;
+ return (nhosts);
+ }
+ count++;
+ debug((char *) "%s| %s: DEBUG: Resolved address %d of %s to %s\n", LogTime(), PROGRAM, count, name, host);
+
+ hp = (struct hstruct *) xrealloc(hp, sizeof(struct hstruct) * (nhosts + 1));
+ hp[nhosts].host = xstrdup(host);
+ hp[nhosts].port = -1;
+ hp[nhosts].priority = -1;
+ hp[nhosts].weight = -1;
+ nhosts++;
+
+ hres_list = hres_list->ai_next;
+ }
+
+ freeaddrinfo(hres);
+ *hlist = hp;
+ return (nhosts);
+}
+
+int
+get_ldap_hostname_list(struct main_args *margs, struct hstruct **hlist, int nh, char *domain)
+{
+
+ /*
+ * char name[sysconf(_SC_HOST_NAME_MAX)];
+ */
+ char name[1024];
+ char host[NS_MAXDNAME];
+ char *service;
+ struct hstruct *hp = NULL;
+ int nhosts = 0;
+ int size;
+ int type, rdlength;
+ int priority, weight, port;
+ int len, olen;
+ int i, j, k;
+ u_char *buffer;
+ u_char *p;
+
+ if (margs->ssl) {
+ service = (char *) xmalloc(strlen("_ldaps._tcp.") + strlen(domain) + 1);
+ strcpy(service, "_ldaps._tcp.");
+ } else {
+ service = (char *) xmalloc(strlen("_ldap._tcp.") + strlen(domain) + 1);
+ strcpy(service, "_ldap._tcp.");
+ }
+ strcat(service, domain);
+
+#ifndef PACKETSZ_MULT
+ /*
+ * It seems Solaris doesn't give back the real length back when res_search uses a to small buffer
+ * Set a bigger one here
+ */
+#define PACKETSZ_MULT 10
+#endif
+
+ hp = *hlist;
+ buffer = (u_char *) xmalloc(PACKETSZ_MULT * NS_PACKETSZ);
+ if ((len = res_search(service, ns_c_in, ns_t_srv, (u_char *) buffer, PACKETSZ_MULT * NS_PACKETSZ)) < 0) {
+ error((char *) "%s| %s: ERROR: Error while resolving service record %s with res_search\n", LogTime(), PROGRAM, service);
+ nsError(h_errno, service);
+ if (margs->ssl) {
+ xfree(service);
+ service = (char *) xmalloc(strlen("_ldap._tcp.") + strlen(domain) + 1);
+ strcpy(service, "_ldap._tcp.");
+ strcat(service, domain);
+ if ((len = res_search(service, ns_c_in, ns_t_srv, (u_char *) buffer, PACKETSZ_MULT * NS_PACKETSZ)) < 0) {
+ error((char *) "%s| %s: ERROR: Error while resolving service record %s with res_search\n", LogTime(), PROGRAM, service);
+ nsError(h_errno, service);
+ goto cleanup;
+ }
+ } else {
+ goto cleanup;
+ }
+ }
+ if (len > PACKETSZ_MULT * NS_PACKETSZ) {
+ olen = len;
+ buffer = (u_char *) xrealloc(buffer, len);
+ if ((len = res_search(service, ns_c_in, ns_t_srv, (u_char *) buffer, len)) < 0) {
+ error((char *) "%s| %s: ERROR: Error while resolving service record %s with res_search\n", LogTime(), PROGRAM, service);
+ nsError(h_errno, service);
+ goto cleanup;
+ }
+ if (len > olen) {
+ error((char *) "%s| %s: ERROR: Reply to big: buffer: %d reply length: %d\n", LogTime(), PROGRAM, olen, len);
+ goto cleanup;
+ }
+ }
+ p = buffer;
+ p += 6 * NS_INT16SZ; /* Header(6*16bit) = id + flags + 4*section count */
+ if (p > buffer + len) {
+ error((char *) "%s| %s: ERROR: Message to small: %d < header size\n", LogTime(), PROGRAM, len);
+ goto cleanup;
+ }
+ if ((size = dn_expand(buffer, buffer + len, p, name, sysconf(_SC_HOST_NAME_MAX))) < 0) {
+ error((char *) "%s| %s: ERROR: Error while expanding query name with dn_expand: %s\n", LogTime(), PROGRAM, strerror(errno));
+ goto cleanup;
+ }
+ p += size; /* Query name */
+ p += 2 * NS_INT16SZ; /* Query type + class (2*16bit) */
+ if (p > buffer + len) {
+ error((char *) "%s| %s: ERROR: Message to small: %d < header + query name,type,class \n", LogTime(), PROGRAM, len);
+ goto cleanup;
+ }
+ while (p < buffer + len) {
+ if ((size = dn_expand(buffer, buffer + len, p, name, sysconf(_SC_HOST_NAME_MAX))) < 0) {
+ error((char *) "%s| %s: ERROR: Error while expanding answer name with dn_expand: %s\n", LogTime(), PROGRAM, strerror(errno));
+ goto cleanup;
+ }
+ p += size; /* Resource Record name */
+ if (p > buffer + len) {
+ error((char *) "%s| %s: ERROR: Message to small: %d < header + query name,type,class + answer name\n", LogTime(), PROGRAM, len);
+ goto cleanup;
+ }
+ NS_GET16(type, p); /* RR type (16bit) */
+ p += NS_INT16SZ + NS_INT32SZ; /* RR class + ttl (16bit+32bit) */
+ if (p > buffer + len) {
+ error((char *) "%s| %s: ERROR: Message to small: %d < header + query name,type,class + answer name + RR type,class,ttl\n", LogTime(), PROGRAM, len);
+ goto cleanup;
+ }
+ NS_GET16(rdlength, p); /* RR data length (16bit) */
+
+ if (type == ns_t_srv) { /* SRV record */
+ if (p > buffer + len) {
+ error((char *) "%s| %s: ERROR: Message to small: %d < header + query name,type,class + answer name + RR type,class,ttl + RR data length\n", LogTime(), PROGRAM, len);
+ goto cleanup;
+ }
+ NS_GET16(priority, p); /* Priority (16bit) */
+ if (p > buffer + len) {
+ error((char *) "%s| %s: ERROR: Message to small: %d < SRV RR + priority\n", LogTime(), PROGRAM, len);
+ goto cleanup;
+ }
+ NS_GET16(weight, p); /* Weight (16bit) */
+ if (p > buffer + len) {
+ error((char *) "%s| %s: ERROR: Message to small: %d < SRV RR + priority + weight\n", LogTime(), PROGRAM, len);
+ goto cleanup;
+ }
+ NS_GET16(port, p); /* Port (16bit) */
+ if (p > buffer + len) {
+ error((char *) "%s| %s: ERROR: Message to small: %d < SRV RR + priority + weight + port\n", LogTime(), PROGRAM, len);
+ goto cleanup;
+ }
+ if ((size = dn_expand(buffer, buffer + len, p, host, NS_MAXDNAME)) < 0) {
+ error((char *) "%s| %s: ERROR: Error while expanding SRV RR name with dn_expand: %s\n", LogTime(), PROGRAM, strerror(errno));
+ goto cleanup;
+ }
+ debug((char *) "%s| %s: DEBUG: Resolved SRV %s record to %s\n", LogTime(), PROGRAM, service, host);
+ hp = (struct hstruct *) xrealloc(hp, sizeof(struct hstruct) * (nh + 1));
+ hp[nh].host = xstrdup(host);
+ hp[nh].port = port;
+ hp[nh].priority = priority;
+ hp[nh].weight = weight;
+ nh++;
+ p += size;
+ } else {
+ p += rdlength;
+ }
+ if (p > buffer + len) {
+ error((char *) "%s| %s: ERROR: Message to small: %d < SRV RR + priority + weight + port + name\n", LogTime(), PROGRAM, len);
+ goto cleanup;
+ }
+ }
+ if (p != buffer + len) {
+#if (SIZEOF_LONG == 8)
+ error("%s| %s: ERROR: Inconsistence message length: %ld!=0\n", LogTime(), PROGRAM, buffer + len - p);
+#else
+ error((char *) "%s| %s: ERROR: Inconsistence message length: %d!=0\n", LogTime(), PROGRAM, buffer + len - p);
+#endif
+ goto cleanup;
+ }
+ nhosts = get_hostname_list(margs, &hp, nh, domain);
+
+ /* Remove duplicates */
+ for (i = 0; i < nhosts; i++) {
+ for (j = i + 1; j < nhosts; j++) {
+ if (!strcasecmp(hp[i].host, hp[j].host)) {
+ if (hp[i].port == hp[j].port ||
+ (hp[i].port == -1 && hp[j].port == 389) ||
+ (hp[i].port == 389 && hp[j].port == -1)) {
+ xfree(hp[j].host);
+ for (k = j + 1; k < nhosts; k++) {
+ hp[k - 1].host = hp[k].host;
+ hp[k - 1].port = hp[k].port;
+ hp[k - 1].priority = hp[k].priority;
+ hp[k - 1].weight = hp[k].weight;
+ }
+ j--;
+ nhosts--;
+ hp = (struct hstruct *) xrealloc(hp, sizeof(struct hstruct) * (nhosts + 1));
+ }
+ }
+ }
+ }
+
+ /* Sort by Priority / Weight */
+ msort(hp, nhosts, compare_hosts);
+
+ if (debug_enabled) {
+ debug((char *) "%s| %s: DEBUG: Sorted ldap server names for domain %s:\n", LogTime(), PROGRAM, domain);
+ for (i = 0; i < nhosts; i++) {
+ debug((char *) "%s| %s: DEBUG: Host: %s Port: %d Priority: %d Weight: %d\n", LogTime(), PROGRAM, hp[i].host, hp[i].port, hp[i].priority, hp[i].weight);
+ }
+ }
+ if (buffer)
+ xfree(buffer);
+ if (service)
+ xfree(service);
+ *hlist = hp;
+ return (nhosts);
+
+cleanup:
+ if (buffer)
+ xfree(buffer);
+ if (service)
+ xfree(service);
+ *hlist = hp;
+ return (nhosts);
+}
+#endif
--- /dev/null
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * Author: Markus Moeller (markus_moeller at compuserve.com)
+ *
+ * Copyright (C) 2007 Markus Moeller. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#include "config.h"
+#include "util.h"
+
+#ifdef HAVE_LDAP
+
+#include "support.h"
+
+#ifdef HAVE_SASL_H
+#include <sasl.h>
+#elif defined(HAVE_SASL_SASL_H)
+#include <sasl/sasl.h>
+#elif defined(HAVE_SASL_DARWIN)
+typedef struct sasl_interact {
+ unsigned long id; /* same as client/user callback ID */
+ const char *challenge; /* presented to user (e.g. OTP challenge) */
+ const char *prompt; /* presented to user (e.g. "Username: ") */
+ const char *defresult; /* default result string */
+ const void *result; /* set to point to result */
+ unsigned len; /* set to length of result */
+} sasl_interact_t;
+
+#define SASL_CB_USER 0x4001 /* client user identity to login as */
+#define SASL_CB_AUTHNAME 0x4002 /* client authentication name */
+#define SASL_CB_PASS 0x4004 /* client passphrase-based secret */
+#define SASL_CB_ECHOPROMPT 0x4005 /* challenge and client enterred result */
+#define SASL_CB_NOECHOPROMPT 0x4006 /* challenge and client enterred result */
+#define SASL_CB_GETREALM 0x4008 /* realm to attempt authentication in */
+#define SASL_CB_LIST_END 0 /* end of list */
+#endif
+
+#if defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H) || defined(HAVE_SASL_DARWIN)
+void *lutil_sasl_defaults(
+ LDAP * ld,
+ char *mech,
+ char *realm,
+ char *authcid,
+ char *passwd,
+ char *authzid);
+
+LDAP_SASL_INTERACT_PROC lutil_sasl_interact;
+
+int lutil_sasl_interact(
+ LDAP * ld,
+ unsigned flags,
+ void *defaults,
+ void *in);
+
+void lutil_sasl_freedefs(
+ void *defaults);
+
+
+/*
+ * SASL definitions for openldap support
+ */
+
+
+typedef struct lutil_sasl_defaults_s {
+ char *mech;
+ char *realm;
+ char *authcid;
+ char *passwd;
+ char *authzid;
+ char **resps;
+ int nresps;
+} lutilSASLdefaults;
+
+void *
+lutil_sasl_defaults(
+ LDAP * ld,
+ char *mech,
+ char *realm,
+ char *authcid,
+ char *passwd,
+ char *authzid)
+{
+ lutilSASLdefaults *defaults;
+
+ defaults = (lutilSASLdefaults *) xmalloc(sizeof(lutilSASLdefaults));
+
+ if (defaults == NULL)
+ return NULL;
+
+ defaults->mech = mech ? xstrdup(mech) : NULL;
+ defaults->realm = realm ? xstrdup(realm) : NULL;
+ defaults->authcid = authcid ? xstrdup(authcid) : NULL;
+ defaults->passwd = passwd ? xstrdup(passwd) : NULL;
+ defaults->authzid = authzid ? xstrdup(authzid) : NULL;
+
+ if (defaults->mech == NULL) {
+ ldap_get_option(ld, LDAP_OPT_X_SASL_MECH, &defaults->mech);
+ }
+ if (defaults->realm == NULL) {
+ ldap_get_option(ld, LDAP_OPT_X_SASL_REALM, &defaults->realm);
+ }
+ if (defaults->authcid == NULL) {
+ ldap_get_option(ld, LDAP_OPT_X_SASL_AUTHCID, &defaults->authcid);
+ }
+ if (defaults->authzid == NULL) {
+ ldap_get_option(ld, LDAP_OPT_X_SASL_AUTHZID, &defaults->authzid);
+ }
+ defaults->resps = NULL;
+ defaults->nresps = 0;
+
+ return defaults;
+}
+
+static int
+interaction(
+ unsigned flags,
+ sasl_interact_t * interact,
+ lutilSASLdefaults * defaults)
+{
+ const char *dflt = interact->defresult;
+
+ int noecho = 0;
+ int challenge = 0;
+
+ flags = flags;
+ switch (interact->id) {
+ case SASL_CB_GETREALM:
+ if (defaults)
+ dflt = defaults->realm;
+ break;
+ case SASL_CB_AUTHNAME:
+ if (defaults)
+ dflt = defaults->authcid;
+ break;
+ case SASL_CB_PASS:
+ if (defaults)
+ dflt = defaults->passwd;
+ noecho = 1;
+ break;
+ case SASL_CB_USER:
+ if (defaults)
+ dflt = defaults->authzid;
+ break;
+ case SASL_CB_NOECHOPROMPT:
+ noecho = 1;
+ challenge = 1;
+ break;
+ case SASL_CB_ECHOPROMPT:
+ challenge = 1;
+ break;
+ }
+
+ if (dflt && !*dflt)
+ dflt = NULL;
+
+ /* input must be empty */
+ interact->result = (dflt && *dflt) ? dflt : "";
+ interact->len = (unsigned) strlen((const char *) interact->result);
+
+ return LDAP_SUCCESS;
+}
+
+int
+lutil_sasl_interact(
+ LDAP * ld,
+ unsigned flags,
+ void *defaults,
+ void *in)
+{
+ sasl_interact_t *interact = (sasl_interact_t *) in;
+
+ if (ld == NULL)
+ return LDAP_PARAM_ERROR;
+
+ while (interact->id != SASL_CB_LIST_END) {
+ int rc = interaction(flags, interact, (lutilSASLdefaults *) defaults);
+
+ if (rc)
+ return rc;
+ interact++;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+void
+lutil_sasl_freedefs(
+ void *defaults)
+{
+ lutilSASLdefaults *defs = (lutilSASLdefaults *) defaults;
+
+ if (defs->mech)
+ xfree(defs->mech);
+ if (defs->realm)
+ xfree(defs->realm);
+ if (defs->authcid)
+ xfree(defs->authcid);
+ if (defs->passwd)
+ xfree(defs->passwd);
+ if (defs->authzid)
+ xfree(defs->authzid);
+ if (defs->resps)
+ xfree(defs->resps);
+
+ xfree(defs);
+}
+
+int
+tool_sasl_bind(LDAP * ld, char *binddn, char *ssl)
+{
+ /*
+ * unsigned sasl_flags = LDAP_SASL_AUTOMATIC;
+ * unsigned sasl_flags = LDAP_SASL_QUIET;
+ */
+ /*
+ * Avoid SASL messages
+ */
+#ifdef HAVE_SUN_LDAP_SDK
+ unsigned sasl_flags = LDAP_SASL_INTERACTIVE;
+#else
+ unsigned sasl_flags = LDAP_SASL_QUIET;
+#endif
+ char *sasl_realm = NULL;
+ char *sasl_authc_id = NULL;
+ char *sasl_authz_id = NULL;
+#ifdef HAVE_SUN_LDAP_SDK
+ char *sasl_mech = (char *) "GSSAPI";
+#else
+ char *sasl_mech = NULL;
+#endif
+ /*
+ * Force encryption
+ */
+ char *sasl_secprops;
+ /*
+ * char *sasl_secprops = (char *)"maxssf=56";
+ * char *sasl_secprops = NULL;
+ */
+ struct berval passwd = {0, NULL};
+ void *defaults;
+ int rc = LDAP_SUCCESS;
+
+ if (ssl)
+ sasl_secprops = (char *) "maxssf=0";
+ else
+ sasl_secprops = (char *) "maxssf=56";
+ /* sasl_secprops = (char *)"maxssf=0"; */
+ /* sasl_secprops = (char *)"maxssf=56"; */
+
+ if (sasl_secprops != NULL) {
+ rc = ldap_set_option(ld, LDAP_OPT_X_SASL_SECPROPS,
+ (void *) sasl_secprops);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: Could not set LDAP_OPT_X_SASL_SECPROPS: %s: %s\n", LogTime(), PROGRAM, sasl_secprops, ldap_err2string(rc));
+ return rc;
+ }
+ }
+ defaults = lutil_sasl_defaults(ld,
+ sasl_mech,
+ sasl_realm,
+ sasl_authc_id,
+ passwd.bv_val,
+ sasl_authz_id);
+
+ rc = ldap_sasl_interactive_bind_s(ld, binddn,
+ sasl_mech, NULL, NULL,
+ sasl_flags, lutil_sasl_interact, defaults);
+
+ lutil_sasl_freedefs(defaults);
+ if (rc != LDAP_SUCCESS) {
+ error((char *) "%s| %s: ERROR: ldap_sasl_interactive_bind_s error: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+ }
+ return rc;
+}
+#else
+void dummy(void);
+void
+dummy(void)
+{
+ fprintf(stderr, "%s| %s: ERROR: Dummy function\n", LogTime(), PROGRAM);
+}
+
+#endif
+#endif
include $(top_srcdir)/src/Common.am
-EXTRA_DIST = README COPYING config.test
+EXTRA_DIST = README COPYING config.test negotiate_kerberos_auth.8
SUBDIRS =
libexec_PROGRAMS = negotiate_kerberos_auth negotiate_kerberos_auth_test
negotiate_kerberos_auth_LDADD = $(COMPAT_LIB) $(XTRA_LIBS) $(KRB5LIBS)
negotiate_kerberos_auth_test_LDFLAGS =
negotiate_kerberos_auth_test_LDADD = $(COMPAT_LIB) $(XTRA_LIBS) $(KRB5LIBS)
+
+man_MANS = negotiate_kerberos_auth.8
for (i = 0; i < 64; i++)
base64_value[(int) base64_code[i]] = i;
- base64_value[(int)'='] = 0;
+ base64_value[(int) '='] = 0;
base64_initialized = 1;
}
}
end:
if (out_cnt >= result_size) {
- result[result_size - 1] = '\0'; /* terminate */
+ result[result_size - 1] = '\0'; /* terminate */
} else {
result[out_cnt] = '\0'; /* terminate */
}
#!/bin/sh
# Don't build without gssapi.h
-if test -f /usr/include/gssapi/gssapi.h || test -f /usr/include/gssapi.h ; then
+if test -f /usr/include/gssapi/gssapi.h || test -f /usr/include/gssapi.h || test -f /usr/include/kerberosV/gssapi.h ; then
exit 0
fi
exit 1
--- /dev/null
+.if !'po4a'hide' .TH negotiate_kerberos_auth 8
+.
+.SH NAME
+.if !'po4a'hide' .B negotiate_kerberos_auth
+.if !'po4a'hide' \-
+Squid kerberos based authentication helper
+.PP
+Version 3.0.3sq
+.
+.SH SYNOPSIS
+.if !'po4a'hide' .B negotiate_kerberos_auth
+.if !'po4a'hide' .B [\-h] [\-d] [\-i] [\-r] [\-s Service-Principal-Name]
+.
+.SH DESCRIPTION
+.B negotiate_kerberos_auth
+is an installed binary and allows Squid to authenticate users via the Negotiate
+protocol and Kerberos.
+
+.SH OPTIONS
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-h
+Display the binary help and command line syntax info using stderr.
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-d
+Write debug messages to stderr.
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-i
+Write informational messages to stderr.
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-r
+Remove realm from username before returning the username to squid.
+.if !'po4a'hide' .TP 12
+.if !'po4a'hide' .B \-s Service-Principal-name
+Provide Service Principal Name.
+.
+.SH CONFIGURATION
+.PP See FAQ wiki page for examples of how to write configuration snippets. (TBD)
+.PP
+This helper is intended to be used as an
+.B external_acl_type
+helper in
+.B squid.conf.
+.if !'po4a'hide' .P
+.if !'po4a'hide' .ft CR
+.if !'po4a'hide' .nf
+.if !'po4a'hide' auth_param negotiate program /path/to/negotiate_kerberos_auth
+.if !'po4a'hide' .br
+.if !'po4a'hide' auth_param negotiate children 10
+.if !'po4a'hide' .br
+.if !'po4a'hide' auth_param negotiate keep_alive on
+.if !'po4a'hide' .fi
+.if !'po4a'hide' .ft
+.PP
+.B NOTE:
+The following squid startup file modification may be required:
+
+Add the following lines to the squid startup script to point squid to a keytab file which
+contains the HTTP/fqdn service principal for the default Kerberos domain. The fqdn must be
+the proxy name set in IE or firefox. You can not use an IP address.
+
+KRB5_KTNAME=/etc/squid/HTTP.keytab
+export KRB5_KTNAME
+
+If you use a different Kerberos domain than the machine itself is in you can point squid to
+the seperate Kerberos config file by setting the following environmnet variable in the startup
+script.
+
+KRB5_CONFIG=/etc/krb5-squid.conf
+export KRB5_CONFIG
+
+Kerberos can keep a replay cache to detect the reuse of Kerberos tickets (usually only possible
+in a 5 minute window) . If squid is under high load with Negotiate(Kerberos) proxy authentication
+requests the replay cache checks can create high CPU load. If the environment does not require
+high security the replay cache check can be disabled for MIT based Kerberos implementations by
+adding the following to the startup script
+
+KRB5RCACHETYPE=none
+export KRB5RCACHETYPE
+
+If negotiate_kerberos_auth doesn't determine for some reason the right service principal you can provide
+it with -s HTTP/fqdn.
+
+If you serve multiple Kerberos realms add a HTTP/fqdn@REALM service principal per realm to the
+HTTP.keytab file and use the -s GSS_C_NO_NAME option with negotiate_kerberos_auth.
+
+.
+.SH AUTHOR
+This program was written by
+.if !'po4a'hide' .I Markus Moeller <markus_moeller@compuserve.com>
+.PP
+This manual was written by
+.if !'po4a'hide' .I Markus Moeller <markus_moeller@compuserve.com>
+.
+.SH COPYRIGHT
+This program and documentation is copyright to the authors named above.
+.PP
+Distributed under the GNU General Public License (GNU GPL) version 2 or later (GPLv2+).
+.
+.SH QUESTIONS
+Questions on the usage of this program can be sent to the
+.I Squid Users mailing list
+.if !'po4a'hide' <squid-users@squid-cache.org>
+.
+.SH REPORTING BUGS
+Bug reports need to be made in English.
+See http://wiki.squid-cache.org/SquidFaq/BugReporting for details of what you need to include with your bug report.
+.PP
+Report bugs or bug fixes using http://bugs.squid-cache.org/
+.PP
+Report serious security bugs to
+.I Squid Bugs <squid-bugs@squid-cache.org>
+.PP
+Report ideas for new improvements to the
+.I Squid Developers mailing list
+.if !'po4a'hide' <squid-dev@squid-cache.org>
+.
+.SH SEE ALSO
+.if !'po4a'hide' .BR squid "(8) "
+.if !'po4a'hide' .BR ext_kerberos_ldap_group_acl "(8) "
+.br
+.BR RFC4559 " - SPNEGO-based Kerberos and NTLM HTTP Authentication in Microsoft Windows,"
+.br
+.BR RFC2478 " - The Simple and Protected GSS-API Negotiation Mechanism,"
+.br
+.BR RFC1964 " - The Kerberos Version 5 GSS-API Mechanism,"
+.br
+The Squid FAQ wiki
+.if !'po4a'hide' http://wiki.squid-cache.org/SquidFaq
+.br
+The Squid Configuration Manual
+.if !'po4a'hide' http://www.squid-cache.org/Doc/config/
+.if !'po4a'hide' http://wiki.squid-cache.org/ConfigExamples/Authenticate/Kerberos
#define MAX_AUTHTOKEN_LEN 65535
#endif
#ifndef SQUID_KERB_AUTH_VERSION
-#define SQUID_KERB_AUTH_VERSION "3.0.2sq"
+#define SQUID_KERB_AUTH_VERSION "3.0.3sq"
#endif
int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status,
char *gethost_name(void);
static const char *LogTime(void);
-static const unsigned char ntlmProtocol[] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', 0 };
+static const unsigned char ntlmProtocol[] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0};
static const char *
LogTime()
gethost_name(void)
{
/*
- char hostname[sysconf(_SC_HOST_NAME_MAX)];
- */
+ * char hostname[sysconf(_SC_HOST_NAME_MAX)];
+ */
char hostname[1024];
struct addrinfo *hres = NULL, *hres_list;
int rc, count;
freeaddrinfo(hres);
return NULL;
}
-
freeaddrinfo(hres);
hostname[sysconf(_SC_HOST_NAME_MAX) - 1] = '\0';
return (xstrdup(hostname));
GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string);
if (maj_stat == GSS_S_COMPLETE) {
if (sizeof(buf) > len + status_string.length + 1) {
- snprintf(buf + len, (sizeof(buf)-len), "%s", (char *) status_string.value);
+ snprintf(buf + len, (sizeof(buf) - len), "%s", (char *) status_string.value);
len += status_string.length;
}
gss_release_buffer(&min_stat, &status_string);
gss_release_buffer(&min_stat, &status_string);
}
if (sizeof(buf) > len + 2) {
- snprintf(buf + len, (sizeof(buf)-len), "%s", ". ");
+ snprintf(buf + len, (sizeof(buf) - len), "%s", ". ");
len += 2;
}
msg_ctx = 0;
GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string);
if (maj_stat == GSS_S_COMPLETE) {
if (sizeof(buf) > len + status_string.length) {
- snprintf(buf + len,(sizeof(buf)-len), "%s", (char *) status_string.value);
+ snprintf(buf + len, (sizeof(buf) - len), "%s", (char *) status_string.value);
len += status_string.length;
}
gss_release_buffer(&min_stat, &status_string);
}
gss_release_buffer(&min_stat, &status_string);
}
- debug("%s| %s: ERROR: %s failed: %s\n", LogTime(), PROGRAM, function, buf);
+ debug((char *) "%s| %s: ERROR: %s failed: %s\n", LogTime(), PROGRAM, function, buf);
fprintf(stdout, "BH %s failed: %s\n", function, buf);
if (log)
fprintf(stderr, "%s| %s: INFO: User not authenticated\n", LogTime(),
}
}
- debug("%s| %s: INFO: Starting version %s\n", LogTime(), PROGRAM, SQUID_KERB_AUTH_VERSION);
+ debug((char *) "%s| %s: INFO: Starting version %s\n", LogTime(), PROGRAM, SQUID_KERB_AUTH_VERSION);
if (service_principal && strcasecmp(service_principal, "GSS_C_NO_NAME")) {
service.value = service_principal;
service.length = strlen((char *) service.value);
exit(-1);
}
service.value = xmalloc(strlen(service_name) + strlen(host_name) + 2);
- snprintf((char*)service.value, strlen(service_name) + strlen(host_name) + 2,
+ snprintf((char *) service.value, strlen(service_name) + strlen(host_name) + 2,
"%s@%s", service_name, host_name);
service.length = strlen((char *) service.value);
}
while (1) {
if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
if (ferror(stdin)) {
- debug("%s| %s: FATAL: fgets() failed! dying..... errno=%d (%s)\n",
+ debug((char *) "%s| %s: FATAL: fgets() failed! dying..... errno=%d (%s)\n",
LogTime(), PROGRAM, ferror(stdin),
strerror(ferror(stdin)));
fprintf(stdout, "BH input error\n");
exit(0);
}
-
- c = (char*)memchr(buf, '\n', sizeof(buf) - 1);
+ c = (char *) memchr(buf, '\n', sizeof(buf) - 1);
if (c) {
*c = '\0';
length = c - buf;
err = 1;
}
if (err) {
- debug("%s| %s: ERROR: Oversized message\n", LogTime(), PROGRAM);
+ debug((char *) "%s| %s: ERROR: Oversized message\n", LogTime(), PROGRAM);
fprintf(stdout, "BH Oversized message\n");
err = 0;
continue;
}
-
- debug("%s| %s: DEBUG: Got '%s' from squid (length: %d).\n", LogTime(), PROGRAM, buf, length);
+ debug((char *) "%s| %s: DEBUG: Got '%s' from squid (length: %d).\n", LogTime(), PROGRAM, buf, length);
if (buf[0] == '\0') {
- debug("%s| %s: ERROR: Invalid request\n", LogTime(), PROGRAM);
+ debug((char *) "%s| %s: ERROR: Invalid request\n", LogTime(), PROGRAM);
fprintf(stdout, "BH Invalid request\n");
continue;
}
-
if (strlen(buf) < 2) {
- debug("%s| %s: ERROR: Invalid request [%s]\n", LogTime(), PROGRAM, buf);
+ debug((char *) "%s| %s: ERROR: Invalid request [%s]\n", LogTime(), PROGRAM, buf);
fprintf(stdout, "BH Invalid request\n");
continue;
}
-
if (!strncmp(buf, "QQ", 2)) {
gss_release_buffer(&minor_status, &input_token);
gss_release_buffer(&minor_status, &output_token);
fprintf(stdout, "BH quit command\n");
exit(0);
}
-
if (strncmp(buf, "YR", 2) && strncmp(buf, "KK", 2)) {
- debug("%s| %s: ERROR: Invalid request [%s]\n", LogTime(), PROGRAM, buf);
+ debug((char *) "%s| %s: ERROR: Invalid request [%s]\n", LogTime(), PROGRAM, buf);
fprintf(stdout, "BH Invalid request\n");
continue;
}
gss_delete_sec_context(&minor_status, &gss_context, NULL);
gss_context = GSS_C_NO_CONTEXT;
}
-
if (strlen(buf) <= 3) {
- debug("%s| %s: ERROR: Invalid negotiate request [%s]\n", LogTime(), PROGRAM, buf);
+ debug((char *) "%s| %s: ERROR: Invalid negotiate request [%s]\n", LogTime(), PROGRAM, buf);
fprintf(stdout, "BH Invalid negotiate request\n");
continue;
}
-
input_token.length = ska_base64_decode_len(buf + 3);
- debug("%s| %s: DEBUG: Decode '%s' (decoded length: %d).\n",
+ debug((char *) "%s| %s: DEBUG: Decode '%s' (decoded length: %d).\n",
LogTime(), PROGRAM, buf + 3, (int) input_token.length);
input_token.value = xmalloc(input_token.length);
- ska_base64_decode((char*)input_token.value, buf + 3, input_token.length);
+ ska_base64_decode((char *) input_token.value, buf + 3, input_token.length);
if ((input_token.length >= sizeof ntlmProtocol + 1) &&
(!memcmp(input_token.value, ntlmProtocol, sizeof ntlmProtocol))) {
- debug("%s| %s: WARNING: received type %d NTLM token\n",
+ debug((char *) "%s| %s: WARNING: received type %d NTLM token\n",
LogTime(), PROGRAM,
(int) *((unsigned char *) input_token.value +
sizeof ntlmProtocol));
sizeof ntlmProtocol));
goto cleanup;
}
-
if (service_principal) {
if (strcasecmp(service_principal, "GSS_C_NO_NAME")) {
major_status = gss_import_name(&minor_status, &service,
if (output_token.length) {
- spnegoToken = (const unsigned char*)output_token.value;
+ spnegoToken = (const unsigned char *) output_token.value;
spnegoTokenLength = output_token.length;
- token = (char*)xmalloc(ska_base64_encode_len(spnegoTokenLength));
+ token = (char *) xmalloc(ska_base64_encode_len(spnegoTokenLength));
if (token == NULL) {
- debug("%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
+ debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
fprintf(stdout, "BH Not enough memory\n");
goto cleanup;
}
-
ska_base64_encode(token, (const char *) spnegoToken,
ska_base64_encode_len(spnegoTokenLength), spnegoTokenLength);
if (check_gss_err(major_status, minor_status, "gss_accept_sec_context()", log))
goto cleanup;
if (major_status & GSS_S_CONTINUE_NEEDED) {
- debug("%s| %s: INFO: continuation needed\n", LogTime(), PROGRAM);
+ debug((char *) "%s| %s: INFO: continuation needed\n", LogTime(), PROGRAM);
fprintf(stdout, "TT %s\n", token);
goto cleanup;
}
if (check_gss_err(major_status, minor_status, "gss_display_name()", log))
goto cleanup;
- user = (char*)xmalloc(output_token.length + 1);
+ user = (char *) xmalloc(output_token.length + 1);
if (user == NULL) {
- debug("%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
+ debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
fprintf(stdout, "BH Not enough memory\n");
goto cleanup;
}
*p = '\0';
}
fprintf(stdout, "AF %s %s\n", token, user);
- debug("%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, token, user);
+ debug((char *) "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, token, user);
if (log)
fprintf(stderr, "%s| %s: INFO: User %s authenticated\n", LogTime(),
PROGRAM, user);
if (check_gss_err(major_status, minor_status, "gss_accept_sec_context()", log))
goto cleanup;
if (major_status & GSS_S_CONTINUE_NEEDED) {
- debug("%s| %s: INFO: continuation needed\n", LogTime(), PROGRAM);
+ debug((char *) "%s| %s: INFO: continuation needed\n", LogTime(), PROGRAM);
fprintf(stdout, "NA %s\n", token);
goto cleanup;
}
/*
* Return dummy token AA. May need an extra return tag then AF
*/
- user = (char*)xmalloc(output_token.length + 1);
+ user = (char *) xmalloc(output_token.length + 1);
if (user == NULL) {
- debug("%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
+ debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
fprintf(stdout, "BH Not enough memory\n");
goto cleanup;
}
*p = '\0';
}
fprintf(stdout, "AF %s %s\n", "AA==", user);
- debug("%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, "AA==", user);
+ debug((char *) "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, "AA==", user);
if (log)
fprintf(stderr, "%s| %s: INFO: User %s authenticated\n", LogTime(),
PROGRAM, user);
gettimeofday(&now, NULL);
if (now.tv_sec != last_t) {
- tm = localtime((const time_t*)&now.tv_sec);
+ tm = localtime((const time_t *) &now.tv_sec);
strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
last_t = now.tv_sec;
}
}
#ifndef gss_mech_spnego
-static gss_OID_desc _gss_mech_spnego = { 6, (void *) "\x2b\x06\x01\x05\x05\x02" };
+static gss_OID_desc _gss_mech_spnego = {6, (void *) "\x2b\x06\x01\x05\x05\x02"};
gss_OID gss_mech_spnego = &_gss_mech_spnego;
#endif
GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string);
if (maj_stat == GSS_S_COMPLETE) {
if (sizeof(buf) > len + status_string.length + 1) {
- snprintf(buf + len, (sizeof(buf)-len), "%s", (char *)status_string.value);
+ snprintf(buf + len, (sizeof(buf) - len), "%s", (char *) status_string.value);
len += status_string.length;
}
gss_release_buffer(&min_stat, &status_string);
gss_release_buffer(&min_stat, &status_string);
}
if (sizeof(buf) > len + 2) {
- snprintf(buf + len, (sizeof(buf)-len), "%s", ". ");
+ snprintf(buf + len, (sizeof(buf) - len), "%s", ". ");
len += 2;
}
msg_ctx = 0;
GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string);
if (maj_stat == GSS_S_COMPLETE) {
if (sizeof(buf) > len + status_string.length) {
- snprintf(buf + len, (sizeof(buf)-len), "%s", (char *) status_string.value);
+ snprintf(buf + len, (sizeof(buf) - len), "%s", (char *) status_string.value);
len += status_string.length;
}
gss_release_buffer(&min_stat, &status_string);
PROGRAM);
return NULL;
}
-
service.value = xmalloc(strlen("HTTP") + strlen(proxy) + 2);
- snprintf((char*)service.value, strlen("HTTP") + strlen(proxy) + 2, "%s@%s", "HTTP", proxy);
+ snprintf((char *) service.value, strlen("HTTP") + strlen(proxy) + 2, "%s@%s", "HTTP", proxy);
service.length = strlen((char *) service.value);
major_status = gss_import_name(&minor_status, &service,
goto cleanup;
if (output_token.length) {
- token = (char*)xmalloc(ska_base64_encode_len(output_token.length));
+ token = (char *) xmalloc(ska_base64_encode_len(output_token.length));
ska_base64_encode(token, (const char *) output_token.value,
ska_base64_encode_len(output_token.length), output_token.length);
}
-
-
cleanup:
gss_delete_sec_context(&minor_status, &gss_context, NULL);
gss_release_buffer(&minor_status, &service);
exit(0);
}
+
#else
#include <stdlib.h>
int
{
exit(-1);
}
+
#endif /* HAVE_GSSAPI */
#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n");
#ifdef __GNUC__
#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
-#define SEND3(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
+#define SEND4(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
#else
/* no gcc, no debugging. varargs macros are a gcc extension */
#define SEND2(X,Y) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
-#define SEND3(X,Y,Z) debug("sending '" X "' to squid\n",Y,Z); printf(X "\n",Y,Z);
+#define SEND4(X,Y,Z,W) debug("sending '" X "' to squid\n",Y,Z); printf(X "\n",Y,Z);
#endif
const char *authenticate_ntlm_domain = "WORKGROUP";
if (strip_domain_enabled) {
SEND2("AF %s", user);
} else {
- SEND3("AF %s%s%s", domain, (*domain?"\\":""), user);
+ SEND4("AF %s%s%s", domain, (*domain?"\\":""), user);
}
} else {
lc(user);
lc(domain);
- SEND3("NA invalid credentials, user=%s%s%s", domain, (*domain?"\\":""), user);
+ SEND4("NA invalid credentials, user=%s%s%s", domain, (*domain?"\\":""), user);
}
} else {
SEND("BH wrong packet type! user=");
*/
#define SQUID_NO_ALLOC_PROTECT 1
#include "config.h"
+#include "compat/debug.h"
#include "libntlmauth/ntlmauth.h"
#include "libntlmauth/smb.h"
#include "libntlmauth/rfcnb.h"
my_program_name, my_program_name);
}
-int debug_enabled=0;
+/* int debug_enabled=0; defined in libcompat */
void
process_options(int argc, char *argv[])
--- /dev/null
+#ifndef __SQUID_PSIGNAL_H
+#define __SQUID_PSIGNAL_H
+
+#include "config.h"
+
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+extern void psignal(int sig, const char* msg);
+
+#endif /* __SQUID_PSIGNAL_H */
md5.c \
Profiler.c \
win32lib.c
+
libmiscutil_a_SOURCES = \
MemPool.cc \
MemPoolChunked.cc \
## Special Universal .h dependency test script
## aborts if error encountered
testHeaders: $(top_srcdir)/include/*.h
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(top_srcdir)/include" || exit 1
+ $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" $^ || exit 1
TESTS += testHeaders
CLEANFILES += testHeaders
#include "TrieNode.h"
#include "TrieCharTransform.h"
-#ifndef _USE_INLINE_
+#if !_USE_INLINE_
#include "Trie.cci"
#endif
}
}
-#ifndef _USE_INLINE_
+#if !_USE_INLINE_
#include "TrieNode.cci"
#endif
--- /dev/null
+/*
+ * Author: Jens-S. V?ckler <voeckler@rvs.uni-hannover.de>
+ * Ripped from Purge tool implementation.
+ */
+#include "config.h"
+#include "psignal.h"
+
+#if _SQUID_AIX_
+extern const char* const sys_siglist[];
+#define _sys_nsig 64
+#define _sys_siglist sys_siglist
+#endif
+
+/// purpose: print message, colon, space, signal name and LF.
+/// paramtr: sig (IN): signal number
+/// msg (IN): message to prepend
+void
+psignal( int sig, const char* msg )
+{
+ if ( msg && *msg ) fprintf( stderr, "%s: ", msg );
+ if ( sig > 0 && sig < _sys_nsig )
+ fprintf( stderr, "%s\n", _sys_siglist[sig] );
+ else
+ fputs( "(unknown)\n", stderr );
+}
#if HAVE_STDIO_H
#include <stdio.h>
#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "squid.h"
+#include "base/AsyncJobCalls.h"
#include "base/TextException.h"
#include "BodyPipe.h"
public:
typedef UnaryMemFunT<BodyProducer, BodyPipe::Pointer> Parent;
- BodyProducerDialer(BodyProducer *aProducer, Parent::Method aHandler,
- BodyPipe::Pointer bp): Parent(aProducer, aHandler, bp) {}
+ BodyProducerDialer(const BodyProducer::Pointer &aProducer,
+ Parent::Method aHandler, BodyPipe::Pointer bp):
+ Parent(aProducer, aHandler, bp) {}
virtual bool canDial(AsyncCall &call);
};
public:
typedef UnaryMemFunT<BodyConsumer, BodyPipe::Pointer> Parent;
- BodyConsumerDialer(BodyConsumer *aConsumer, Parent::Method aHandler,
- BodyPipe::Pointer bp): Parent(aConsumer, aHandler, bp) {}
+ BodyConsumerDialer(const BodyConsumer::Pointer &aConsumer,
+ Parent::Method aHandler, BodyPipe::Pointer bp):
+ Parent(aConsumer, aHandler, bp) {}
virtual bool canDial(AsyncCall &call);
};
if (!Parent::canDial(call))
return false;
- BodyProducer *producer = object;
+ const BodyProducer::Pointer &producer = job;
BodyPipe::Pointer pipe = arg1;
if (!pipe->stillProducing(producer)) {
debugs(call.debugSection, call.debugLevel, HERE << producer <<
if (!Parent::canDial(call))
return false;
- BodyConsumer *consumer = object;
+ const BodyConsumer::Pointer &consumer = job;
BodyPipe::Pointer pipe = arg1;
if (!pipe->stillConsuming(consumer)) {
debugs(call.debugSection, call.debugLevel, HERE << consumer <<
void
BodyPipe::clearProducer(bool atEof)
{
- if (theProducer) {
+ if (theProducer.set()) {
debugs(91,7, HERE << "clearing BodyPipe producer" << status());
- theProducer = NULL;
+ theProducer.clear();
if (atEof) {
if (!bodySizeKnown())
theBodySize = thePutSize;
}
bool
-BodyPipe::setConsumerIfNotLate(Consumer *aConsumer)
+BodyPipe::setConsumerIfNotLate(const Consumer::Pointer &aConsumer)
{
assert(!theConsumer);
- assert(aConsumer);
+ assert(aConsumer.set()); // but might be invalid
// TODO: convert this into an exception and remove IfNotLate suffix
// If there is something consumed already, we are in an auto-consuming mode
void
BodyPipe::clearConsumer()
{
- if (theConsumer) {
+ if (theConsumer.set()) {
debugs(91,7, HERE << "clearing consumer" << status());
- theConsumer = NULL;
+ theConsumer.clear();
if (consumedSize() && !exhausted()) {
AsyncCall::Pointer call= asyncCall(91, 7,
"BodyProducer::noteBodyConsumerAborted",
void
BodyPipe::scheduleBodyDataNotification()
{
- if (theConsumer) {
+ if (theConsumer.valid()) { // TODO: allow asyncCall() to check this instead
AsyncCall::Pointer call = asyncCall(91, 7,
"BodyConsumer::noteMoreBodyDataAvailable",
BodyConsumerDialer(theConsumer,
void
BodyPipe::scheduleBodyEndNotification()
{
- if (theConsumer) {
+ if (theConsumer.valid()) { // TODO: allow asyncCall() to check this instead
if (bodySizeKnown() && bodySize() == thePutSize) {
AsyncCall::Pointer call = asyncCall(91, 7,
"BodyConsumer::noteBodyProductionEnded",
outputBuffer.Printf(" %d+%d", (int)theBuf.contentSize(), (int)theBuf.spaceSize());
outputBuffer.Printf(" pipe%p", this);
- if (theProducer)
- outputBuffer.Printf(" prod%p", theProducer);
- if (theConsumer)
- outputBuffer.Printf(" cons%p", theConsumer);
+ if (theProducer.set())
+ outputBuffer.Printf(" prod%p", theProducer.get());
+ if (theConsumer.set())
+ outputBuffer.Printf(" cons%p", theConsumer.get());
if (mustAutoConsume)
outputBuffer.append(" A", 2);
#define SQUID_BODY_PIPE_H
#include "MemBuf.h"
-#include "base/AsyncCall.h"
#include "base/AsyncJob.h"
+#include "base/CbcPointer.h"
class BodyPipe;
class BodyProducer: virtual public AsyncJob
{
public:
+ typedef CbcPointer<BodyProducer> Pointer;
+
BodyProducer():AsyncJob("BodyProducer") {}
virtual ~BodyProducer() {}
class BodyConsumer: virtual public AsyncJob
{
public:
+ typedef CbcPointer<BodyConsumer> Pointer;
+
BodyConsumer():AsyncJob("BodyConsumer") {}
virtual ~BodyConsumer() {}
bool mayNeedMoreData() const { return !bodySizeKnown() || needsMoreData(); }
bool needsMoreData() const { return bodySizeKnown() && unproducedSize() > 0; }
uint64_t unproducedSize() const; // size of still unproduced data
- bool stillProducing(const Producer *producer) const { return theProducer == producer; }
+ bool stillProducing(const Producer::Pointer &producer) const { return theProducer == producer; }
void expectProductionEndAfter(uint64_t extraSize); ///< sets or checks body size
// called by consumers
- bool setConsumerIfNotLate(Consumer *aConsumer);
+ bool setConsumerIfNotLate(const Consumer::Pointer &aConsumer);
void clearConsumer(); // aborts if still piping
size_t getMoreData(MemBuf &buf);
void consume(size_t size);
bool expectMoreAfter(uint64_t offset) const;
bool exhausted() const; // saw eof/abort and all data consumed
- bool stillConsuming(const Consumer *consumer) const { return theConsumer == consumer; }
+ bool stillConsuming(const Consumer::Pointer &consumer) const { return theConsumer == consumer; }
// start or continue consuming when there is no consumer
void enableAutoConsumption();
private:
int64_t theBodySize; // expected total content length, if known
- Producer *theProducer; // content producer, if any
- Consumer *theConsumer; // content consumer, if any
+ Producer::Pointer theProducer; // content producer, if any
+ Consumer::Pointer theConsumer; // content consumer, if any
uint64_t thePutSize; // ever-increasing total
uint64_t theGetSize; // ever-increasing total
virtual void run (StoreEntry *sentry);
ReconfigureAction();
};
+ class RotateAction : public CacheManagerAction
+ {
+ public:
+ virtual void run (StoreEntry *sentry);
+ RotateAction();
+ };
class OfflineToggleAction : public CacheManagerAction
{
public:
// All job dialers with comm parameters are merged into one since they
// all have exactly one callback argument and differ in Params type only
template <class C, class Params_>
-class CommCbMemFunT: public JobDialer, public CommDialerParamsT<Params_>
+class CommCbMemFunT: public JobDialer<C>, public CommDialerParamsT<Params_>
{
public:
typedef Params_ Params;
typedef void (C::*Method)(const Params &io);
- CommCbMemFunT(C *obj, Method meth): JobDialer(obj),
- CommDialerParamsT<Params>(obj), object(obj), method(meth) {}
+ CommCbMemFunT(const CbcPointer<C> &job, Method meth): JobDialer<C>(job),
+ CommDialerParamsT<Params_>(job.get()),
+ method(meth) {}
virtual bool canDial(AsyncCall &c) {
- return JobDialer::canDial(c) &&
+ return JobDialer<C>::canDial(c) &&
this->params.syncWithComm();
}
}
public:
- C *object;
Method method;
protected:
- virtual void doDial() { (object->*method)(this->params); }
+ virtual void doDial() { ((&(*this->job))->*method)(this->params); }
};
## Because we use libcompat for comm_err.h header protections ...
INCLUDES += $(KRB5INCS)
+## Loadable Modules requires LTDL include paths.
+## Because we need this to use the libray linking headers...
+if USE_LOADABLE_MODULES
+INCLUDES += $(INCLTDL)
+endif
+
## make all compiled sources depend on generated files
## XXX: Do we really need this? Does auto-dependency tracking work?
$(OBJS): $(top_srcdir)/include/version.h $(top_builddir)/include/autoconf.h
static void squidaio_queue_request(squidaio_request_t *);
static void squidaio_cleanup_request(squidaio_request_t *);
-static void *squidaio_thread_loop(void *);
+SQUIDCEXTERN void *squidaio_thread_loop(void *);
static void squidaio_do_open(squidaio_request_t *);
static void squidaio_do_read(squidaio_request_t *);
static void squidaio_do_write(squidaio_request_t *);
squidaio_initialised = 0;
}
-static void *
+void *
squidaio_thread_loop(void *ptr)
{
squidaio_thread_t *threadp = (squidaio_thread_t *)ptr;
{"Set-Cookie", HDR_SET_COOKIE, ftStr},
{"TE", HDR_TE, ftStr},
{"Title", HDR_TITLE, ftStr},
- {"Trailers", HDR_TRAILERS, ftStr},
+ {"Trailer", HDR_TRAILER, ftStr},
{"Transfer-Encoding", HDR_TRANSFER_ENCODING, ftStr},
{"Translate", HDR_TRANSLATE, ftStr}, /* for now. may need to crop */
{"Unless-Modified-Since", HDR_UNLESS_MODIFIED_SINCE, ftStr}, /* for now ignore. may need to crop */
static HttpHeaderMask HopByHopHeadersMask;
static http_hdr_type HopByHopHeadersArr[] = {
HDR_CONNECTION, HDR_KEEP_ALIVE, /*HDR_PROXY_AUTHENTICATE,*/ HDR_PROXY_AUTHORIZATION,
- HDR_TE, HDR_TRAILERS, HDR_TRANSFER_ENCODING, HDR_UPGRADE, HDR_PROXY_CONNECTION
+ HDR_TE, HDR_TRAILER, HDR_TRANSFER_ENCODING, HDR_UPGRADE, HDR_PROXY_CONNECTION
};
/* header accounting */
addEntry(e);
}
+ if (chunked()) {
+ // RFC 2616 section 4.4: ignore Content-Length with Transfer-Encoding
+ delById(HDR_CONTENT_LENGTH);
+ }
+
PROF_stop(HttpHeaderParse);
return 1; /* even if no fields where found, it is a valid header */
reset:
extern const HttpHeaderStat *dump_stat; /* argh! */
const HttpHeaderStat *dump_stat = NULL;
-static void
+void
httpHeaderFieldStatDumper(StoreEntry * sentry, int idx, double val, double size, int count)
{
const int id = (int) val;
/* class forward declarations */
-class HttpVersion;
class HttpHdrContRange;
class HttpHdrCc;
class HttpHdrSc;
HDR_SET_COOKIE,
HDR_TE,
HDR_TITLE,
- HDR_TRAILERS,
+ HDR_TRAILER,
HDR_TRANSFER_ENCODING,
HDR_TRANSLATE, /* IIS custom header we may need to cut off */
HDR_UNLESS_MODIFIED_SINCE, /* IIS custom header we may need to cut off */
int hasListMember(http_hdr_type id, const char *member, const char separator) const;
int hasByNameListMember(const char *name, const char *member, const char separator) const;
void removeHopByHopEntries();
+ inline bool chunked() const; ///< whether message uses chunked Transfer-Encoding
/* protected, do not use these, use interface functions instead */
Vector<HttpHeaderEntry *> entries; /**< parsed fields in raw format */
extern int httpHeaderParseQuotedString (const char *start, String *val);
SQUIDCEXTERN int httpHeaderHasByNameListMember(const HttpHeader * hdr, const char *name, const char *member, const char separator);
SQUIDCEXTERN void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask);
-int httpMsgIsPersistent(HttpVersion const &http_ver, const HttpHeader * hdr);
-
SQUIDCEXTERN void httpHeaderCalcMask(HttpHeaderMask * mask, http_hdr_type http_hdr_type_enums[], size_t count);
+inline bool
+HttpHeader::chunked() const
+{
+ return has(HDR_TRANSFER_ENCODING) &&
+ hasListMember(HDR_TRANSFER_ENCODING, "chunked", ',');
+}
+
#endif /* SQUID_HTTPHEADER_H */
httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive)
{
String list;
- http_hdr_type ht;
int res;
/* what type of header do we have? */
+#if USE_HTTP_VIOLATIONS
if (hdr->has(HDR_PROXY_CONNECTION))
- ht = HDR_PROXY_CONNECTION;
- else if (hdr->has(HDR_CONNECTION))
- ht = HDR_CONNECTION;
+ list = hdr->getList(HDR_PROXY_CONNECTION);
else
- return 0;
-
- list = hdr->getList(ht);
+#endif
+ if (hdr->has(HDR_CONNECTION))
+ list = hdr->getList(HDR_CONNECTION);
+ else
+ return 0;
res = strListIsMember(&list, directive, ',');
content_length = clen;
}
-/* returns true if connection should be "persistent"
- * after processing this message */
-int
-httpMsgIsPersistent(HttpVersion const &http_ver, const HttpHeader * hdr)
+bool
+HttpMsg::persistent() const
{
- if ((http_ver.major >= 1) && (http_ver.minor >= 1)) {
+ if (http_ver > HttpVersion(1, 0)) {
/*
* for modern versions of HTTP: persistent unless there is
* a "Connection: close" header.
*/
- return !httpHeaderHasConnDir(hdr, "close");
+ return !httpHeaderHasConnDir(&header, "close");
} else {
/*
* Persistent connections in Netscape 3.x are allegedly broken,
* return false if it is a browser connection. If there is a
* VIA header, then we assume this is NOT a browser connection.
*/
- const char *agent = hdr->getStr(HDR_USER_AGENT);
+ const char *agent = header.getStr(HDR_USER_AGENT);
- if (agent && !hdr->has(HDR_VIA)) {
+ if (agent && !header.has(HDR_VIA)) {
if (!strncasecmp(agent, "Mozilla/3.", 10))
return 0;
}
/* for old versions of HTTP: persistent if has "keep-alive" */
- return httpHeaderHasConnDir(hdr, "keep-alive");
+ return httpHeaderHasConnDir(&header, "keep-alive");
}
}
/// [re]sets Content-Length header and cached value
void setContentLength(int64_t clen);
+ /**
+ * \retval true the message sender asks to keep the connection open.
+ * \retval false the message sender will close the connection.
+ *
+ * Factors other than the headers may result in connection closure.
+ */
+ bool persistent() const;
+
public:
HttpVersion http_ver;
static http_hdr_type Denied304HeadersArr[] = {
// hop-by-hop headers
HDR_CONNECTION, HDR_KEEP_ALIVE, HDR_PROXY_AUTHENTICATE, HDR_PROXY_AUTHORIZATION,
- HDR_TE, HDR_TRAILERS, HDR_TRANSFER_ENCODING, HDR_UPGRADE,
+ HDR_TE, HDR_TRAILER, HDR_TRANSFER_ENCODING, HDR_UPGRADE,
// entity headers
HDR_ALLOW, HDR_CONTENT_ENCODING, HDR_CONTENT_LANGUAGE, HDR_CONTENT_LENGTH,
HDR_CONTENT_MD5, HDR_CONTENT_RANGE, HDR_CONTENT_TYPE, HDR_LAST_MODIFIED
{
HttpMsg::hdrCacheInit();
+ http_ver = sline.version;
content_length = header.getInt64(HDR_CONTENT_LENGTH);
date = header.getTime(HDR_DATE);
last_modified = header.getTime(HDR_LAST_MODIFIED);
surrogate_control = header.getSc();
content_range = header.getContRange();
- keep_alive = httpMsgIsPersistent(sline.version, &header);
+ keep_alive = persistent() ? 1 : 0;
const char *str = header.getStr(HDR_CONTENT_TYPE);
if (str)
expectBody = true;
if (expectBody) {
- if (header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ','))
+ if (header.chunked())
theSize = -1;
else if (content_length >= 0)
theSize = content_length;
expectBody = Config.onoff.request_entities ? true : false;
else if (method == METHOD_PUT || method == METHOD_POST)
expectBody = true;
- else if (header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ','))
+ else if (header.chunked())
expectBody = true;
else if (content_length >= 0)
expectBody = true;
expectBody = false;
if (expectBody) {
- if (header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ','))
+ if (header.chunked())
theSize = -1;
else if (content_length >= 0)
theSize = content_length;
return ((this->major != that.major) || (this->minor != that.minor));
}
+ bool operator <(const HttpVersion& that) const {
+ return (this->major < that.major ||
+ (this->major == that.major && this->minor < that.minor));
+ }
+
+ bool operator >(const HttpVersion& that) const {
+ return (this->major > that.major ||
+ (this->major == that.major && this->minor > that.minor));
+ }
+
+ bool operator <=(const HttpVersion& that) const {
+ return !(*this > that);
+ }
+
+ bool operator >=(const HttpVersion& that) const {
+ return !(*this < that);
+ }
};
#endif /* SQUID_HTTPVERSION_H */
DiskIO_DiskDaemon_diskd_LDADD = $(COMPAT_LIB) $(XTRA_LIBS)
-DEFAULT_HTTP_PORT = $(CACHE_HTTP_PORT)
-DEFAULT_ICP_PORT = $(CACHE_ICP_PORT)
+DEFAULT_HTTP_PORT = 3128
+DEFAULT_ICP_PORT = 3130
DEFAULT_PREFIX = $(prefix)
DEFAULT_CONFIG_DIR = $(sysconfdir)
DEFAULT_CONFIG_FILE = $(DEFAULT_CONFIG_DIR)/squid.conf
DEFAULT_CACHE_LOG = $(DEFAULT_LOG_PREFIX)/cache.log
DEFAULT_ACCESS_LOG = $(DEFAULT_LOG_PREFIX)/access.log
DEFAULT_STORE_LOG = $(DEFAULT_LOG_PREFIX)/store.log
-DEFAULT_PID_FILE = $(DEFAULT_PIDFILE)
DEFAULT_NETDB_FILE = $(DEFAULT_LOG_PREFIX)/netdb.state
DEFAULT_SWAP_DIR = $(localstatedir)/cache
DEFAULT_PINGER = $(libexecdir)/`echo pinger | sed '$(transform);s/$$/$(EXEEXT)/'`
DEFAULT_DISKD = $(libexecdir)/`echo diskd | sed '$(transform);s/$$/$(EXEEXT)/'`
DEFAULT_ICON_DIR = $(datadir)/icons
DEFAULT_ERROR_DIR = $(datadir)/errors
-DEFAULT_HOSTS = $(OPT_DEFAULT_HOSTS)
# Make location configure settings available to the code
DEFS += -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" -DDEFAULT_SQUID_DATA_DIR=\"$(datadir)\" -DDEFAULT_SQUID_CONFIG_DIR=\"$(sysconfdir)\"
tests/testCacheManager.cc \
tests/testCacheManager.h \
tests/testMain.cc \
+ tests/stub_main_cc.cc \
time.cc \
BodyPipe.cc \
cache_manager.cc \
tests/testEvent.cc \
tests/testEvent.h \
tests/testMain.cc \
+ tests/stub_main_cc.cc \
time.cc \
BodyPipe.cc \
cache_manager.cc \
tests/testEventLoop.cc \
tests/testEventLoop.h \
tests/testMain.cc \
+ tests/stub_main_cc.cc \
time.cc \
BodyPipe.cc \
cache_manager.cc \
$(squid_COMMSOURCES) \
ConfigOption.cc \
ConfigParser.cc \
+ tests/stub_main_cc.cc \
debug.cc \
$(DELAY_POOL_SOURCE) \
disk.cc \
tests/testHttpRequestMethod.h \
tests/testHttpRequestMethod.cc \
tests/testMain.cc \
+ tests/stub_main_cc.cc \
time.cc \
BodyPipe.cc \
cache_manager.cc \
tests/testURLScheme.cc \
tests/testURLScheme.h \
tests/testMain.cc \
+ tests/stub_main_cc.cc \
time.cc \
BodyPipe.cc \
cache_manager.cc \
## Special Universal .h dependency test script
## aborts if error encountered
testHeaders: $(srcdir)/*.h $(srcdir)/DiskIO/*.h $(srcdir)/DiskIO/*/*.h
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(srcdir)" || exit 1
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(srcdir)/DiskIO" || exit 1
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(srcdir)/DiskIO/AIO" || exit 1
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(srcdir)/DiskIO/Blocking" || exit 1
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(srcdir)/DiskIO/DiskDaemon" || exit 1
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(srcdir)/DiskIO/DiskThreads" || exit 1
+ $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" $^ || exit 1
## src/repl/ has no .h files and its own makefile.
CLEANFILES += testHeaders
if (requestBodySource->getMoreData(buf)) {
debugs(9,3, HERE << "will write " << buf.contentSize() << " request body bytes");
typedef CommCbMemFunT<ServerStateData, CommIoCbParams> Dialer;
- requestSender = asyncCall(93,3, "ServerStateData::sentRequestBody",
- Dialer(this, &ServerStateData::sentRequestBody));
+ requestSender = JobCallback(93,3,
+ Dialer, this, ServerStateData::sentRequestBody);
comm_write_mbuf(conn->fd, &buf, requestSender);
} else {
debugs(9,3, HERE << "will wait for more request body bytes or eof");
}
adaptedHeadSource = initiateAdaptation(
- new Adaptation::Iterator(this, vrep, cause, group));
- startedAdaptation = adaptedHeadSource != NULL;
+ new Adaptation::Iterator(vrep, cause, group));
+ startedAdaptation = initiated(adaptedHeadSource);
Must(startedAdaptation);
}
#if USE_ADAPTATION
BodyPipe::Pointer virginBodyDestination; /**< to provide virgin response body */
- Adaptation::Initiate *adaptedHeadSource; /**< to get adapted response headers */
+ CbcPointer<Adaptation::Initiate> adaptedHeadSource; /**< to get adapted response headers */
BodyPipe::Pointer adaptedBodySource; /**< to consume adated response body */
bool adaptationAccessCheckPending;
if (Config::Enabled) {
// the new check will call the callback and delete self, eventually
- return AsyncStart(new AccessCheck(
- ServiceFilter(method, vp, req, rep), cb, cbdata));
+ AsyncJob::Start(new AccessCheck( // we do not store so not a CbcPointer
+ ServiceFilter(method, vp, req, rep), cb, cbdata));
+ return true;
}
debugs(83, 3, HERE << "adaptation off, skipping");
#include "HttpMsg.h"
#include "adaptation/Initiator.h"
#include "adaptation/Initiate.h"
+#include "base/AsyncJobCalls.h"
namespace Adaptation
{
public:
typedef UnaryMemFunT<Initiator, HttpMsg*> Parent;
- AnswerDialer(Initiator *obj, Parent::Method meth, HttpMsg *msg):
- Parent(obj, meth, msg) { HTTPMSGLOCK(arg1); }
- AnswerDialer(const AnswerDialer &d):
- Parent(d) { HTTPMSGLOCK(arg1); }
+ AnswerDialer(const Parent::JobPointer &job, Parent::Method meth,
+ HttpMsg *msg): Parent(job, meth, msg) { HTTPMSGLOCK(arg1); }
+ AnswerDialer(const AnswerDialer &d): Parent(d) { HTTPMSGLOCK(arg1); }
virtual ~AnswerDialer() { HTTPMSGUNLOCK(arg1); }
+
+private:
+ AnswerDialer &operator =(const AnswerDialer &); // not implemented
};
} // namespace Adaptation
/* Initiate */
-Adaptation::Initiate::Initiate(const char *aTypeName, Initiator *anInitiator):
- AsyncJob(aTypeName), theInitiator(anInitiator)
+Adaptation::Initiate::Initiate(const char *aTypeName): AsyncJob(aTypeName)
{
- assert(theInitiator);
}
Adaptation::Initiate::~Initiate()
// can assert(!(wasStarted && theInitiator)).
}
+void
+Adaptation::Initiate::initiator(const CbcPointer<Initiator> &i)
+{
+ Must(!theInitiator);
+ Must(i.valid());
+ theInitiator = i;
+}
+
+
// internal cleanup
void Adaptation::Initiate::swanSong()
{
debugs(93, 5, HERE << "swan sings" << status());
- if (theInitiator) {
+ if (theInitiator.set()) {
debugs(93, 3, HERE << "fatal failure; sending abort notification");
tellQueryAborted(true); // final by default
}
void Adaptation::Initiate::clearInitiator()
{
- if (theInitiator)
- theInitiator.clear();
+ theInitiator.clear();
}
void Adaptation::Initiate::sendAnswer(HttpMsg *msg)
{
assert(msg);
- if (theInitiator.isThere()) {
- CallJob(93, 5, __FILE__, __LINE__, "Initiator::noteAdaptAnswer",
- AnswerDialer(theInitiator.ptr(), &Initiator::noteAdaptationAnswer, msg));
- }
+ CallJob(93, 5, __FILE__, __LINE__, "Initiator::noteAdaptationAnswer",
+ AnswerDialer(theInitiator, &Initiator::noteAdaptationAnswer, msg));
clearInitiator();
}
void Adaptation::Initiate::tellQueryAborted(bool final)
{
- if (theInitiator.isThere()) {
- CallJobHere1(93, 5, theInitiator.ptr(),
- Initiator::noteAdaptationQueryAbort, final);
- }
+ CallJobHere1(93, 5, theInitiator,
+ Initiator, noteAdaptationQueryAbort, final);
clearInitiator();
}
{
return AsyncJob::status(); // for now
}
-
-
-/* InitiatorHolder */
-
-Adaptation::InitiatorHolder::InitiatorHolder(Initiator *anInitiator):
- prime(0), cbdata(0)
-{
- if (anInitiator) {
- cbdata = cbdataReference(anInitiator->toCbdata());
- prime = anInitiator;
- }
-}
-
-Adaptation::InitiatorHolder::InitiatorHolder(const InitiatorHolder &anInitiator):
- prime(0), cbdata(0)
-{
- if (anInitiator != NULL && cbdataReferenceValid(anInitiator.cbdata)) {
- cbdata = cbdataReference(anInitiator.cbdata);
- prime = anInitiator.prime;
- }
-}
-
-Adaptation::InitiatorHolder::~InitiatorHolder()
-{
- clear();
-}
-
-void Adaptation::InitiatorHolder::clear()
-{
- if (prime) {
- prime = NULL;
- cbdataReferenceDone(cbdata);
- }
-}
-
-Adaptation::Initiator *Adaptation::InitiatorHolder::ptr()
-{
- assert(isThere());
- return prime;
-}
-
-bool
-Adaptation::InitiatorHolder::isThere()
-{
- return prime && cbdataReferenceValid(cbdata);
-}
-
-// should not be used
-Adaptation::InitiatorHolder &
-Adaptation::InitiatorHolder::operator =(const InitiatorHolder &anInitiator)
-{
- assert(false);
- return *this;
-}
#ifndef SQUID_ADAPTATION__INITIATE_H
#define SQUID_ADAPTATION__INITIATE_H
-#include "base/AsyncCall.h"
#include "base/AsyncJob.h"
+#include "base/CbcPointer.h"
#include "adaptation/forward.h"
class HttpMsg;
namespace Adaptation
{
-/* Initiator holder associtates an initiator with its cbdata. It is used as
- * a temporary hack to make cbdata work with multiple inheritance. We need
- * this hack because we cannot know whether the initiator pointer is still
- * valid without dereferencing it to call toCbdata()
- * TODO: JobDialer uses the same trick. Factor out or move this code. */
-class InitiatorHolder
-{
-public:
- InitiatorHolder(Initiator *anInitiator);
- InitiatorHolder(const InitiatorHolder &anInitiator);
- ~InitiatorHolder();
-
- void clear();
-
- // to make comparison with NULL possible
- operator void*() { return prime; }
- bool operator == (void *) const { return prime == NULL; }
- bool operator != (void *) const { return prime != NULL; }
- bool operator !() const { return !prime; }
-
- bool isThere(); // we have a valid initiator pointer
- Initiator *ptr(); // asserts isThere()
- void *theCbdata() { return cbdata;}
-
-private:
- InitiatorHolder &operator =(const InitiatorHolder &anInitiator);
-
- Initiator *prime;
- void *cbdata;
-};
-
/*
* The Initiate is a common base for queries or transactions
* initiated by an Initiator. This interface exists to allow an
{
public:
- Initiate(const char *aTypeName, Initiator *anInitiator);
+ Initiate(const char *aTypeName);
virtual ~Initiate();
+ void initiator(const CbcPointer<Initiator> &i); ///< sets initiator
+
// communication with the initiator
virtual void noteInitiatorAborted() = 0;
virtual const char *status() const; // for debugging
- InitiatorHolder theInitiator;
+ CbcPointer<Initiator> theInitiator;
private:
Initiate(const Initiate &); // no definition
#include "squid.h"
#include "adaptation/Initiate.h"
#include "adaptation/Initiator.h"
+#include "base/AsyncJobCalls.h"
-Adaptation::Initiate *
-Adaptation::Initiator::initiateAdaptation(Adaptation::Initiate *x)
+CbcPointer<Adaptation::Initiate>
+Adaptation::Initiator::initiateAdaptation(Initiate *x)
{
- if ((x = dynamic_cast<Initiate*>(Initiate::AsyncStart(x))))
- x = cbdataReference(x);
- return x;
+ CbcPointer<Initiate> i(x);
+ x->initiator(this);
+ Start(x);
+ return i;
}
void
-Adaptation::Initiator::clearAdaptation(Initiate *&x)
+Adaptation::Initiator::clearAdaptation(CbcPointer<Initiate> &x)
{
- assert(x);
- cbdataReferenceDone(x);
+ x.clear();
}
void
-Adaptation::Initiator::announceInitiatorAbort(Initiate *&x)
+Adaptation::Initiator::announceInitiatorAbort(CbcPointer<Initiate> &x)
{
- if (x) {
- CallJobHere(93, 5, x, Initiate::noteInitiatorAborted);
- clearAdaptation(x);
- }
+ CallJobHere(93, 5, x, Initiate, noteInitiatorAborted);
+ clearAdaptation(x);
}
#define SQUID_ADAPTATION__INITIATOR_H
#include "base/AsyncJob.h"
+#include "base/CbcPointer.h"
#include "adaptation/forward.h"
/*
virtual void noteAdaptationQueryAbort(bool final) = 0;
protected:
- Initiate *initiateAdaptation(Initiate *x); // locks and returns x
+ ///< starts freshly created initiate and returns a safe pointer to it
+ CbcPointer<Initiate> initiateAdaptation(Initiate *x);
- // done with x (and not calling announceInitiatorAbort)
- void clearAdaptation(Initiate *&x); // unlocks x
+ /// clears the pointer (does not call announceInitiatorAbort)
+ void clearAdaptation(CbcPointer<Initiate> &x);
- // inform the transaction about abnormal termination and clear it
- void announceInitiatorAbort(Initiate *&x); // unlocks x
+ /// inform the transaction about abnormal termination and clear the pointer
+ void announceInitiatorAbort(CbcPointer<Initiate> &x);
+
+ /// Must(initiated(initiate)) instead of Must(initiate.set()), for clarity
+ bool initiated(const CbcPointer<AsyncJob> &job) const { return job.set(); }
};
} // namespace Adaptation
#include "HttpMsg.h"
-Adaptation::Iterator::Iterator(Adaptation::Initiator *anInitiator,
- HttpMsg *aMsg, HttpRequest *aCause,
- const ServiceGroupPointer &aGroup):
+Adaptation::Iterator::Iterator(
+ HttpMsg *aMsg, HttpRequest *aCause,
+ const ServiceGroupPointer &aGroup):
AsyncJob("Iterator"),
- Adaptation::Initiate("Iterator", anInitiator),
+ Adaptation::Initiate("Iterator"),
theGroup(aGroup),
theMsg(HTTPMSGLOCK(aMsg)),
theCause(aCause ? HTTPMSGLOCK(aCause) : NULL),
debugs(93,5, HERE << "using adaptation service: " << service->cfg().key);
theLauncher = initiateAdaptation(
- service->makeXactLauncher(this, theMsg, theCause));
- Must(theLauncher);
+ service->makeXactLauncher(theMsg, theCause));
+ Must(initiated(theLauncher));
Must(!done());
}
void Adaptation::Iterator::swanSong()
{
- if (theInitiator)
+ if (theInitiator.set())
tellQueryAborted(true); // abnormal condition that should not happen
- if (theLauncher)
+ if (initiated(theLauncher))
clearAdaptation(theLauncher);
Adaptation::Initiate::swanSong();
class Iterator: public Initiate, public Initiator
{
public:
- Iterator(Adaptation::Initiator *anInitiator,
- HttpMsg *virginHeader, HttpRequest *virginCause,
+ Iterator(HttpMsg *virginHeader, HttpRequest *virginCause,
const Adaptation::ServiceGroupPointer &aGroup);
virtual ~Iterator();
ServicePlan thePlan; ///< which services to use and in what order
HttpMsg *theMsg; ///< the message being adapted (virgin for each step)
HttpRequest *theCause; ///< the cause of the original virgin message
- Adaptation::Initiate *theLauncher; ///< current transaction launcher
+ CbcPointer<Adaptation::Initiate> theLauncher; ///< current transaction launcher
int iterations; ///< number of steps initiated
bool adapted; ///< whether the virgin message has been replaced
SUBDIRS += ecap
endif
-if USE_LOADABLE_MODULES
-## LTDL headers require their local include path...
-INCLUDES += $(INCLTDL)
-endif
-
noinst_LTLIBRARIES = libadaptation.la
## start with the code shared among all adaptation schemes
virtual bool broken() const;
virtual bool up() const = 0; // see comments above
- virtual Initiate *makeXactLauncher(Initiator *, HttpMsg *virginHeader, HttpRequest *virginCause) = 0;
+ virtual Initiate *makeXactLauncher(HttpMsg *virginHeader, HttpRequest *virginCause) = 0;
bool wants(const ServiceFilter &filter) const;
}
Adaptation::Initiate *
-Adaptation::Ecap::ServiceRep::makeXactLauncher(Adaptation::Initiator *initiator,
- HttpMsg *virgin, HttpRequest *cause)
+Adaptation::Ecap::ServiceRep::makeXactLauncher(HttpMsg *virgin,
+ HttpRequest *cause)
{
Must(up());
- XactionRep *rep = new XactionRep(initiator, virgin, cause, Pointer(this));
+ XactionRep *rep = new XactionRep(virgin, cause, Pointer(this));
XactionRep::AdapterXaction x(theService->makeXaction(rep));
rep->master(x);
return rep;
virtual bool probed() const;
virtual bool up() const;
- Adaptation::Initiate *makeXactLauncher(Adaptation::Initiator *, HttpMsg *virginHeader, HttpRequest *virginCause);
+ Adaptation::Initiate *makeXactLauncher(HttpMsg *virginHeader, HttpRequest *virginCause);
// the methods below can only be called on an up() service
virtual bool wantsUrl(const String &urlPath) const;
CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Ecap::XactionRep, XactionRep);
-Adaptation::Ecap::XactionRep::XactionRep(Adaptation::Initiator *anInitiator,
- HttpMsg *virginHeader, HttpRequest *virginCause,
- const Adaptation::ServicePointer &aService):
+Adaptation::Ecap::XactionRep::XactionRep(
+ HttpMsg *virginHeader, HttpRequest *virginCause,
+ const Adaptation::ServicePointer &aService):
AsyncJob("Adaptation::Ecap::XactionRep"),
- Adaptation::Initiate("Adaptation::Ecap::XactionRep", anInitiator),
+ Adaptation::Initiate("Adaptation::Ecap::XactionRep"),
theService(aService),
theVirginRep(virginHeader), theCauseRep(NULL),
proxyingVb(opUndecided), proxyingAb(opUndecided),
public BodyConsumer, public BodyProducer
{
public:
- XactionRep(Adaptation::Initiator *anInitiator, HttpMsg *virginHeader, HttpRequest *virginCause, const Adaptation::ServicePointer &service);
+ XactionRep(HttpMsg *virginHeader, HttpRequest *virginCause, const Adaptation::ServicePointer &service);
virtual ~XactionRep();
typedef libecap::shared_ptr<libecap::adapter::Xaction> AdapterXaction;
Adaptation::Icap::Launcher::Launcher(const char *aTypeName,
- Adaptation::Initiator *anInitiator, Adaptation::ServicePointer &aService):
+ Adaptation::ServicePointer &aService):
AsyncJob(aTypeName),
- Adaptation::Initiate(aTypeName, anInitiator),
+ Adaptation::Initiate(aTypeName),
theService(aService), theXaction(0), theLaunches(0)
{
}
{
Adaptation::Initiate::start();
- Must(theInitiator);
+ Must(theInitiator.set());
launchXaction("first");
}
if (theLaunches >= TheConfig.repeat_limit)
x->disableRepeats("over icap_retry_limit");
theXaction = initiateAdaptation(x);
- Must(theXaction);
+ Must(initiated(theXaction));
}
void Adaptation::Icap::Launcher::noteAdaptationAnswer(HttpMsg *message)
Must(done()); // swanSong will notify the initiator
}
-void Adaptation::Icap::Launcher::noteXactAbort(XactAbortInfo &info)
+void Adaptation::Icap::Launcher::noteXactAbort(XactAbortInfo info)
{
debugs(93,5, HERE << "theXaction:" << theXaction << " launches: " << theLaunches);
void Adaptation::Icap::Launcher::swanSong()
{
- if (theInitiator)
+ if (theInitiator.set())
tellQueryAborted(true); // always final here because abnormal
- if (theXaction)
+ if (theXaction.set())
clearAdaptation(theXaction);
Adaptation::Initiate::swanSong();
class Launcher: public Adaptation::Initiate, public Adaptation::Initiator
{
public:
- Launcher(const char *aTypeName, Adaptation::Initiator *anInitiator, Adaptation::ServicePointer &aService);
+ Launcher(const char *aTypeName, Adaptation::ServicePointer &aService);
virtual ~Launcher();
// Adaptation::Initiate: asynchronous communication with the initiator
// Adaptation::Initiator: asynchronous communication with the current transaction
virtual void noteAdaptationAnswer(HttpMsg *message);
- virtual void noteXactAbort(XactAbortInfo &info);
+ virtual void noteXactAbort(XactAbortInfo info);
private:
bool canRetry(XactAbortInfo &info) const; //< true if can retry in the case of persistent connection failures
void launchXaction(const char *xkind);
Adaptation::ServicePointer theService; ///< ICAP service for all launches
- Adaptation::Initiate *theXaction; ///< current ICAP transaction
+ CbcPointer<Initiate> theXaction; ///< current ICAP transaction
int theLaunches; // the number of transaction launches
};
XactAbortInfo(const XactAbortInfo &);
~XactAbortInfo();
+ std::ostream &print(std::ostream &os) const {
+ return os << isRetriable << ',' << isRepeatable;
+ }
+
HttpRequest *icapRequest;
HttpReply *icapReply;
bool isRetriable;
XactAbortInfo &operator =(const XactAbortInfo &); // undefined
};
-/* required by UnaryMemFunT */
-inline std::ostream &operator << (std::ostream &os, Adaptation::Icap::XactAbortInfo info)
+inline
+std::ostream &
+operator <<(std::ostream &os, const XactAbortInfo &xai)
{
- // Nothing, it is unused
- return os;
+ return xai.print(os);
}
-/// A Dialer class used to schedule the Adaptation::Icap::Launcher::noteXactAbort call
-class XactAbortCall: public UnaryMemFunT<Adaptation::Icap::Launcher, Adaptation::Icap::XactAbortInfo>
-{
-public:
- typedef void (Adaptation::Icap::Launcher::*DialMethod)(Adaptation::Icap::XactAbortInfo &);
- XactAbortCall(Adaptation::Icap::Launcher *launcer, DialMethod aMethod,
- const Adaptation::Icap::XactAbortInfo &info):
- UnaryMemFunT<Adaptation::Icap::Launcher, Adaptation::Icap::XactAbortInfo>(launcer, NULL, info),
- dialMethod(aMethod) {}
- virtual void print(std::ostream &os) const { os << '(' << "retriable:" << arg1.isRetriable << ", repeatable:" << arg1.isRepeatable << ')'; }
-
-public:
- DialMethod dialMethod;
-
-protected:
- virtual void doDial() { (object->*dialMethod)(arg1); }
-};
-
} // namespace Icap
} // namespace Adaptation
memset(this, 0, sizeof(*this));
}
-Adaptation::Icap::ModXact::ModXact(Adaptation::Initiator *anInitiator, HttpMsg *virginHeader,
+Adaptation::Icap::ModXact::ModXact(HttpMsg *virginHeader,
HttpRequest *virginCause, Adaptation::Icap::ServiceRep::Pointer &aService):
AsyncJob("Adaptation::Icap::ModXact"),
- Adaptation::Icap::Xaction("Adaptation::Icap::ModXact", anInitiator, aService),
+ Adaptation::Icap::Xaction("Adaptation::Icap::ModXact", aService),
virginConsumed(0),
bodyParser(NULL),
canStartBypass(false), // too early
Must(!state.serviceWaiting);
debugs(93, 7, HERE << "will wait for the ICAP service" << status());
state.serviceWaiting = true;
- AsyncCall::Pointer call = asyncCall(93,5, "Adaptation::Icap::ModXact::noteServiceReady",
- MemFun(this, &Adaptation::Icap::ModXact::noteServiceReady));
+ typedef NullaryMemFunT<ModXact> Dialer;
+ AsyncCall::Pointer call = JobCallback(93,5,
+ Dialer, this, Adaptation::Icap::ModXact::noteServiceReady);
service().callWhenReady(call);
}
/* Adaptation::Icap::ModXactLauncher */
-Adaptation::Icap::ModXactLauncher::ModXactLauncher(Adaptation::Initiator *anInitiator, HttpMsg *virginHeader, HttpRequest *virginCause, Adaptation::ServicePointer aService):
+Adaptation::Icap::ModXactLauncher::ModXactLauncher(HttpMsg *virginHeader, HttpRequest *virginCause, Adaptation::ServicePointer aService):
AsyncJob("Adaptation::Icap::ModXactLauncher"),
- Adaptation::Icap::Launcher("Adaptation::Icap::ModXactLauncher", anInitiator, aService)
+ Adaptation::Icap::Launcher("Adaptation::Icap::ModXactLauncher", aService)
{
virgin.setHeader(virginHeader);
virgin.setCause(virginCause);
Adaptation::Icap::ServiceRep::Pointer s =
dynamic_cast<Adaptation::Icap::ServiceRep*>(theService.getRaw());
Must(s != NULL);
- return new Adaptation::Icap::ModXact(this, virgin.header, virgin.cause, s);
+ return new Adaptation::Icap::ModXact(virgin.header, virgin.cause, s);
}
void Adaptation::Icap::ModXactLauncher::swanSong()
{
public:
- ModXact(Adaptation::Initiator *anInitiator, HttpMsg *virginHeader, HttpRequest *virginCause, ServiceRep::Pointer &s);
+ ModXact(HttpMsg *virginHeader, HttpRequest *virginCause, ServiceRep::Pointer &s);
// BodyProducer methods
virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer);
InOut virgin;
InOut adapted;
-protected:
// bypasses exceptions if needed and possible
virtual void callException(const std::exception &e);
class ModXactLauncher: public Launcher
{
public:
- ModXactLauncher(Adaptation::Initiator *anInitiator, HttpMsg *virginHeader, HttpRequest *virginCause, Adaptation::ServicePointer s);
+ ModXactLauncher(HttpMsg *virginHeader, HttpRequest *virginCause, Adaptation::ServicePointer s);
protected:
virtual Xaction *createXaction();
CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Icap, OptXactLauncher);
-Adaptation::Icap::OptXact::OptXact(Adaptation::Initiator *anInitiator, Adaptation::Icap::ServiceRep::Pointer &aService):
+Adaptation::Icap::OptXact::OptXact(Adaptation::Icap::ServiceRep::Pointer &aService):
AsyncJob("Adaptation::Icap::OptXact"),
- Adaptation::Icap::Xaction("Adaptation::Icap::OptXact", anInitiator, aService)
+ Adaptation::Icap::Xaction("Adaptation::Icap::OptXact", aService)
{
}
/* Adaptation::Icap::OptXactLauncher */
-Adaptation::Icap::OptXactLauncher::OptXactLauncher(Adaptation::Initiator *anInitiator, Adaptation::ServicePointer aService):
+Adaptation::Icap::OptXactLauncher::OptXactLauncher(Adaptation::ServicePointer aService):
AsyncJob("Adaptation::Icap::OptXactLauncher"),
- Adaptation::Icap::Launcher("Adaptation::Icap::OptXactLauncher", anInitiator, aService)
+ Adaptation::Icap::Launcher("Adaptation::Icap::OptXactLauncher", aService)
{
}
Adaptation::Icap::ServiceRep::Pointer s =
dynamic_cast<Adaptation::Icap::ServiceRep*>(theService.getRaw());
Must(s != NULL);
- return new Adaptation::Icap::OptXact(this, s);
+ return new Adaptation::Icap::OptXact(s);
}
{
public:
- OptXact(Adaptation::Initiator *anInitiator, ServiceRep::Pointer &aService);
+ OptXact(ServiceRep::Pointer &aService);
protected:
virtual void start();
class OptXactLauncher: public Launcher
{
public:
- OptXactLauncher(Adaptation::Initiator *anInitiator, Adaptation::ServicePointer aService);
+ OptXactLauncher(Adaptation::ServicePointer aService);
protected:
virtual Xaction *createXaction();
if (!detached())
updateScheduled = false;
- if (detached() || theOptionsFetcher) {
+ if (detached() || theOptionsFetcher.set()) {
debugs(93,5, HERE << "ignores options update " << status());
return;
}
i.callback = cb;
theClients.push_back(i);
- if (theOptionsFetcher || notifying)
+ if (theOptionsFetcher.set() || notifying)
return; // do nothing, we will be picked up in noteTimeToNotify()
if (needNewOptions())
void Adaptation::Icap::ServiceRep::scheduleNotification()
{
debugs(93,7, HERE << "will notify " << theClients.size() << " clients");
- CallJobHere(93, 5, this, Adaptation::Icap::ServiceRep::noteTimeToNotify);
+ CallJobHere(93, 5, this, Adaptation::Icap::ServiceRep, noteTimeToNotify);
}
bool Adaptation::Icap::ServiceRep::needNewOptions() const
// we are receiving ICAP OPTIONS response headers here or NULL on failures
void Adaptation::Icap::ServiceRep::noteAdaptationAnswer(HttpMsg *msg)
{
- Must(theOptionsFetcher);
+ Must(initiated(theOptionsFetcher));
clearAdaptation(theOptionsFetcher);
Must(msg);
void Adaptation::Icap::ServiceRep::noteAdaptationQueryAbort(bool)
{
- Must(theOptionsFetcher);
+ Must(initiated(theOptionsFetcher));
clearAdaptation(theOptionsFetcher);
debugs(93,3, HERE << "failed to fetch options " << status());
handleNewOptions(0);
}
+// we (a) must keep trying to get OPTIONS and (b) are RefCounted so we
+// must keep our job alive (XXX: until nobody needs us)
+void Adaptation::Icap::ServiceRep::callException(const std::exception &e)
+{
+ clearAdaptation(theOptionsFetcher);
+ debugs(93,2, "ICAP probably failed to fetch options (" << e.what() <<
+ ")" << status());
+ handleNewOptions(0);
+}
+
void Adaptation::Icap::ServiceRep::handleNewOptions(Adaptation::Icap::Options *newOptions)
{
// new options may be NULL
Must(!theOptionsFetcher);
debugs(93,6, HERE << "will get new options " << status());
- // XXX: second "this" is "self"; this works but may stop if API changes
- theOptionsFetcher = initiateAdaptation(new Adaptation::Icap::OptXactLauncher(this, this));
- Must(theOptionsFetcher);
+ // XXX: "this" here is "self"; works until refcounting API changes
+ theOptionsFetcher = initiateAdaptation(
+ new Adaptation::Icap::OptXactLauncher(this));
// TODO: timeout in case Adaptation::Icap::OptXact never calls us back?
// Such a timeout should probably be a generic AsyncStart feature.
}
}
Adaptation::Initiate *
-Adaptation::Icap::ServiceRep::makeXactLauncher(Adaptation::Initiator *initiator,
- HttpMsg *virgin, HttpRequest *cause)
+Adaptation::Icap::ServiceRep::makeXactLauncher(HttpMsg *virgin,
+ HttpRequest *cause)
{
- return new Adaptation::Icap::ModXactLauncher(initiator, virgin, cause, this);
+ return new Adaptation::Icap::ModXactLauncher(virgin, cause, this);
}
// returns a temporary string depicting service status, for debugging
if (detached())
buf.append(",detached", 9);
- if (theOptionsFetcher)
+ if (theOptionsFetcher.set())
buf.append(",fetch", 6);
if (notifying)
virtual bool probed() const; // see comments above
virtual bool up() const; // see comments above
- virtual Adaptation::Initiate *makeXactLauncher(Adaptation::Initiator *, HttpMsg *virginHeader, HttpRequest *virginCause);
+ virtual Initiate *makeXactLauncher(HttpMsg *virginHeader, HttpRequest *virginCause);
void callWhenReady(AsyncCall::Pointer &cb);
//AsyncJob virtual methods
virtual bool doneAll() const { return Adaptation::Initiator::doneAll() && false;}
+ virtual void callException(const std::exception &e);
virtual void detach();
virtual bool detached() const;
Clients theClients; // all clients waiting for a call back
Options *theOptions;
- Adaptation::Initiate *theOptionsFetcher; // pending ICAP OPTIONS transaction
+ CbcPointer<Adaptation::Initiate> theOptionsFetcher; // pending ICAP OPTIONS transaction
time_t theLastUpdate; // time the options were last updated
FadingCounter theSessionFailures;
//CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Icap, Xaction);
-Adaptation::Icap::Xaction::Xaction(const char *aTypeName, Adaptation::Initiator *anInitiator, Adaptation::Icap::ServiceRep::Pointer &aService):
+Adaptation::Icap::Xaction::Xaction(const char *aTypeName, Adaptation::Icap::ServiceRep::Pointer &aService):
AsyncJob(aTypeName),
- Adaptation::Initiate(aTypeName, anInitiator),
+ Adaptation::Initiate(aTypeName),
icapRequest(NULL),
icapReply(NULL),
attempts(0),
// fake the connect callback
// TODO: can we sync call Adaptation::Icap::Xaction::noteCommConnected here instead?
typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommConnectCbParams> Dialer;
- Dialer dialer(this, &Adaptation::Icap::Xaction::noteCommConnected);
+ CbcPointer<Xaction> self(this);
+ Dialer dialer(self, &Adaptation::Icap::Xaction::noteCommConnected);
dialer.params.fd = connection->fd;
dialer.params.flag = COMM_OK;
// fake other parameters by copying from the existing connection
disableRetries(); // we only retry pconn failures
typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommConnectCbParams> ConnectDialer;
- connector = asyncCall(93,3, "Adaptation::Icap::Xaction::noteCommConnected",
- ConnectDialer(this, &Adaptation::Icap::Xaction::noteCommConnected));
-
+ connector = JobCallback(93,3, ConnectDialer, this, Adaptation::Icap::Xaction::noteCommConnected);
Comm::ConnOpener *cs = new Comm::ConnOpener(connection, connector, TheConfig.connect_timeout(service().cfg().bypass));
cs->setHost(s.cfg().host.termedBuf());
AsyncJob::AsyncStart(cs);
// comm module will free the buffer
typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommIoCbParams> Dialer;
- writer = asyncCall(93,3, "Adaptation::Icap::Xaction::noteCommWrote",
- Dialer(this, &Adaptation::Icap::Xaction::noteCommWrote));
-
+ writer = JobCallback(93, 3, Dialer, this, Adaptation::Icap::Xaction::noteCommWrote);
comm_write_mbuf(connection->fd, &buf, writer);
updateTimeout();
}
// XXX: why does Config.Timeout lacks a write timeout?
// TODO: service bypass status may differ from that of a transaction
typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer call = asyncCall(93, 5, "Adaptation::Icap::Xaction::noteCommTimedout",
- TimeoutDialer(this,&Adaptation::Icap::Xaction::noteCommTimedout));
-
- commSetTimeout(connection->fd,
- TheConfig.io_timeout(service().cfg().bypass), call);
+ AsyncCall::Pointer call = JobCallback(93, 5, TimeoutDialer, this, Adaptation::Icap::Xaction::noteCommTimedout);
+ commSetTimeout(connection->fd, TheConfig.io_timeout(service().cfg().bypass), call);
} else {
// clear timeout when there is no I/O
// Do we need a lifetime timeout?
* here instead of reading directly into readBuf.buf.
*/
typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommIoCbParams> Dialer;
- reader = asyncCall(93,3, "Adaptation::Icap::Xaction::noteCommRead",
- Dialer(this, &Adaptation::Icap::Xaction::noteCommRead));
-
+ reader = JobCallback(93, 3, Dialer, this, Adaptation::Icap::Xaction::noteCommRead);
comm_read(connection->fd, commBuf, readBuf.spaceSize(), reader);
updateTimeout();
}
void Adaptation::Icap::Xaction::noteInitiatorAborted()
{
- if (theInitiator) {
+ if (theInitiator.set()) {
clearInitiator();
mustStop("initiator aborted");
}
if (commBuf)
memFreeBuf(commBufSize, commBuf);
- if (theInitiator)
- tellQueryAborted();
+ tellQueryAborted();
maybeLog();
void Adaptation::Icap::Xaction::tellQueryAborted()
{
- Adaptation::Icap::Launcher *l = dynamic_cast<Adaptation::Icap::Launcher*>(theInitiator.ptr());
- Adaptation::Icap::XactAbortInfo abortInfo(icapRequest, icapReply, retriable(), repeatable());
- CallJob(91, 5, __FILE__, __LINE__,
- "Adaptation::Icap::Launcher::noteXactAbort",
- XactAbortCall(l, &Adaptation::Icap::Launcher::noteXactAbort, abortInfo) );
- clearInitiator();
+ if (theInitiator.set()) {
+ Adaptation::Icap::XactAbortInfo abortInfo(icapRequest, icapReply,
+ retriable(), repeatable());
+ Launcher *launcher = dynamic_cast<Launcher*>(theInitiator.get());
+ // launcher may be nil if initiator is invalid
+ CallJobHere1(91,5, CbcPointer<Launcher>(launcher),
+ Launcher, noteXactAbort, abortInfo);
+ clearInitiator();
+ }
}
{
public:
- Xaction(const char *aTypeName, Adaptation::Initiator *anInitiator, ServiceRep::Pointer &aService);
+ Xaction(const char *aTypeName, ServiceRep::Pointer &aService);
virtual ~Xaction();
void disableRetries();
// useful for debugging
virtual bool fillVirginHttpHeader(MemBuf&) const;
+public:
// custom exception handling and end-of-call checks
virtual void callException(const std::exception &e);
virtual void callEnd();
+protected:
// logging
void setOutcome(const XactOutcome &xo);
virtual void finalizeLogInfo();
## Special Universal .h dependency test script
## aborts if error encountered
testHeaders: $(top_srcdir)/src/auth/*.h $(top_srcdir)/src/auth/basic/*.h $(top_srcdir)/src/auth/digest/*.h $(top_srcdir)/src/auth/ntlm/*.h $(top_srcdir)/src/auth/negotiate/*.h
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(top_srcdir)/src/auth/" || exit 1
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(top_srcdir)/src/auth/basic" || exit 1
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(top_srcdir)/src/auth/digest" || exit 1
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(top_srcdir)/src/auth/ntlm" || exit 1
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(top_srcdir)/src/auth/negotiate" || exit 1
+ $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" $^ || exit 1
CLEANFILES += testHeaders
.PHONY: testHeaders
#include "squid.h"
#include "base/AsyncCall.h"
#include "base/AsyncJob.h"
+#include "base/AsyncJobCalls.h"
#include "base/TextException.h"
#include "cbdata.h"
#include "MemBuf.h"
unsigned int AsyncJob::TheLastId = 0;
-AsyncJob *AsyncJob::AsyncStart(AsyncJob *job)
+AsyncJob::Pointer AsyncJob::Start(AsyncJob *j)
{
- assert(job);
- CallJobHere(93, 5, job, AsyncJob::noteStart);
+ AsyncJob::Pointer job(j);
+ CallJobHere(93, 5, job, AsyncJob, start);
return job;
}
" [async" << id << ']');
}
-void AsyncJob::noteStart()
-{
- start();
-}
-
void AsyncJob::start()
{
}
// there is no call wrapper waiting for our return, so we fake it
debugs(93, 5, typeName << " will delete this, reason: " << stopReason);
+ CbcPointer<AsyncJob> self(this);
AsyncCall::Pointer fakeCall = asyncCall(93,4, "FAKE-deleteThis",
- MemFun(this, &AsyncJob::deleteThis, aReason));
+ JobMemFun(self, &AsyncJob::deleteThis, aReason));
inCall = fakeCall;
callEnd();
// delete fakeCall;
}
-/* JobDialer */
-
-JobDialer::JobDialer(AsyncJob *aJob): job(NULL), lock(NULL)
-{
- if (aJob) {
- lock = cbdataReference(aJob->toCbdata());
- job = aJob;
- }
-}
-
-JobDialer::JobDialer(const JobDialer &d): CallDialer(d),
- job(NULL), lock(NULL)
-{
- if (d.lock && cbdataReferenceValid(d.lock)) {
- lock = cbdataReference(d.lock);
- Must(d.job);
- job = d.job;
- }
-}
-
-JobDialer::~JobDialer()
-{
- cbdataReferenceDone(lock); // lock may be NULL
-}
-
-
-bool
-JobDialer::canDial(AsyncCall &call)
-{
- if (!lock)
- return call.cancel("job was gone before the call");
-
- if (!cbdataReferenceValid(lock))
- return call.cancel("job gone after the call");
-
- Must(job);
- return job->canBeCalled(call);
-}
-
-void
-JobDialer::dial(AsyncCall &call)
-{
- Must(lock && cbdataReferenceValid(lock)); // canDial() checks for this
- Must(job);
-
- job->callStart(call);
-
- try {
- doDial();
- } catch (const std::exception &e) {
- debugs(call.debugSection, 3,
- HERE << call.name << " threw exception: " << e.what());
- job->callException(e);
- }
-
- job->callEnd(); // may delete job
-}
#include "base/AsyncCall.h"
+template <class Cbc>
+class CbcPointer;
+
/**
\defgroup AsyncJobAPI Async-Jobs API
\par
// See AsyncJobs.dox for details.
/// \ingroup AsyncJobAPI
+/// Base class for all asynchronous jobs
class AsyncJob
{
-
public:
- /// starts the job (i.e., makes the job asynchronous)
- static AsyncJob *AsyncStart(AsyncJob *job);
+ typedef CbcPointer<AsyncJob> Pointer;
+public:
AsyncJob(const char *aTypeName);
virtual ~AsyncJob();
virtual void *toCbdata() = 0;
- void noteStart(); // calls virtual start
+
+ /// starts a freshly created job (i.e., makes the job asynchronous)
+ static Pointer Start(AsyncJob *job);
protected:
// XXX: temporary method to replace "delete this" in jobs-in-transition.
static unsigned int TheLastId; ///< makes job IDs unique until it wraps
};
-
-/**
- \ingroup AsyncJobAPI
- * This is a base class for all job call dialers. It does all the job
- * dialing logic (debugging, handling exceptions, etc.) except for calling
- * the job method. The latter is not possible without templates and we
- * want to keep this class simple and template-free. Thus, we add a dial()
- * virtual method that the JobCallT template below will implement for us,
- * calling the job.
- */
-class JobDialer: public CallDialer
-{
-public:
- JobDialer(AsyncJob *aJob);
- JobDialer(const JobDialer &d);
- virtual ~JobDialer();
-
- virtual bool canDial(AsyncCall &call);
- void dial(AsyncCall &call);
-
- AsyncJob *job;
- void *lock; // job's cbdata
-
-protected:
- virtual void doDial() = 0; // actually calls the job method
-
-private:
- // not implemented and should not be needed
- JobDialer &operator =(const JobDialer &);
-};
-
-#include "base/AsyncJobCalls.h"
-
-template <class Dialer>
-bool
-CallJob(int debugSection, int debugLevel, const char *fileName, int fileLine,
- const char *callName, const Dialer &dialer)
-{
- AsyncCall::Pointer call = asyncCall(debugSection, debugLevel, callName, dialer);
- return ScheduleCall(fileName, fileLine, call);
-}
-
-
-#define CallJobHere(debugSection, debugLevel, job, method) \
- CallJob((debugSection), (debugLevel), __FILE__, __LINE__, #method, \
- MemFun((job), &method))
-
-#define CallJobHere1(debugSection, debugLevel, job, method, arg1) \
- CallJob((debugSection), (debugLevel), __FILE__, __LINE__, #method, \
- MemFun((job), &method, (arg1)))
-
-
#endif /* SQUID_ASYNC_JOB_H */
#define SQUID_ASYNCJOBCALLS_H
#include "base/AsyncJob.h"
+#include "base/CbcPointer.h"
+
+/**
+ \ingroup AsyncJobAPI
+ * This is a base class for all job call dialers. It does all the job
+ * dialing logic (debugging, handling exceptions, etc.) except for calling
+ * the job method. The latter requires knowing the number and type of method
+ * parameters. Thus, we add a dial() virtual method that the MemFunT templates
+ * below implement for us, calling the job's method with the right params.
+ */
+template <class Job>
+class JobDialer: public CallDialer
+{
+public:
+ typedef Job DestClass;
+ typedef CbcPointer<Job> JobPointer;
+
+ JobDialer(const JobPointer &aJob);
+ JobDialer(const JobDialer &d);
+
+ virtual bool canDial(AsyncCall &call);
+ void dial(AsyncCall &call);
+
+ JobPointer job;
+
+protected:
+ virtual void doDial() = 0; // actually calls the job method
+
+private:
+ // not implemented and should not be needed
+ JobDialer &operator =(const JobDialer &);
+};
+
+/// schedule an async job call using a dialer; use CallJobHere macros instead
+template <class Dialer>
+bool
+CallJob(int debugSection, int debugLevel, const char *fileName, int fileLine,
+ const char *callName, const Dialer &dialer)
+{
+ AsyncCall::Pointer call = asyncCall(debugSection, debugLevel, callName, dialer);
+ return ScheduleCall(fileName, fileLine, call);
+}
+
+
+#define CallJobHere(debugSection, debugLevel, job, Class, method) \
+ CallJob((debugSection), (debugLevel), __FILE__, __LINE__, \
+ (#Class "::" #method), \
+ JobMemFun<Class>((job), &Class::method))
+
+#define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1) \
+ CallJob((debugSection), (debugLevel), __FILE__, __LINE__, \
+ (#Class "::" #method), \
+ JobMemFun((job), &Class::method, (arg1)))
+
+
+/// Convenience macro to create a Dialer-based job callback
+#define JobCallback(dbgSection, dbgLevel, Dialer, job, method) \
+ asyncCall((dbgSection), (dbgLevel), #method, \
+ Dialer(CbcPointer<Dialer::DestClass>(job), &method))
+
/*
* *MemFunT are member function (i.e., class method) wrappers. They store
// Arity names are from http://en.wikipedia.org/wiki/Arity
-template <class C>
-class NullaryMemFunT: public JobDialer
+template <class Job>
+class NullaryMemFunT: public JobDialer<Job>
{
public:
- typedef void (C::*Method)();
- explicit NullaryMemFunT(C *anObject, Method aMethod):
- JobDialer(anObject), object(anObject), method(aMethod) {}
+ typedef void (Job::*Method)();
+ explicit NullaryMemFunT(const CbcPointer<Job> &aJob, Method aMethod):
+ JobDialer<Job>(aJob), method(aMethod) {}
virtual void print(std::ostream &os) const { os << "()"; }
public:
- C *object;
Method method;
protected:
- virtual void doDial() { (object->*method)(); }
+ virtual void doDial() { ((&(*this->job))->*method)(); }
};
-template <class C, class Argument1>
-class UnaryMemFunT: public JobDialer
+template <class Job, class Argument1>
+class UnaryMemFunT: public JobDialer<Job>
{
public:
- typedef void (C::*Method)(Argument1);
- explicit UnaryMemFunT(C *anObject, Method aMethod, const Argument1 &anArg1):
- JobDialer(anObject),
- object(anObject), method(aMethod), arg1(anArg1) {}
+ typedef void (Job::*Method)(Argument1);
+ explicit UnaryMemFunT(const CbcPointer<Job> &aJob, Method aMethod,
+ const Argument1 &anArg1): JobDialer<Job>(aJob),
+ method(aMethod), arg1(anArg1) {}
virtual void print(std::ostream &os) const { os << '(' << arg1 << ')'; }
public:
- C *object;
Method method;
Argument1 arg1;
protected:
- virtual void doDial() { (object->*method)(arg1); }
+ virtual void doDial() { ((&(*this->job))->*method)(arg1); }
};
// ... add more as needed
template <class C>
NullaryMemFunT<C>
-MemFun(C *object, typename NullaryMemFunT<C>::Method method)
+JobMemFun(const CbcPointer<C> &job, typename NullaryMemFunT<C>::Method method)
{
- return NullaryMemFunT<C>(object, method);
+ return NullaryMemFunT<C>(job, method);
}
template <class C, class Argument1>
UnaryMemFunT<C, Argument1>
-MemFun(C *object, typename UnaryMemFunT<C, Argument1>::Method method,
- Argument1 arg1)
+JobMemFun(const CbcPointer<C> &job, typename UnaryMemFunT<C, Argument1>::Method method,
+ Argument1 arg1)
+{
+ return UnaryMemFunT<C, Argument1>(job, method, arg1);
+}
+
+
+// inlined methods
+
+template<class Job>
+JobDialer<Job>::JobDialer(const JobPointer &aJob): job(aJob)
+{
+}
+
+template<class Job>
+JobDialer<Job>::JobDialer(const JobDialer<Job> &d): CallDialer(d), job(d.job)
{
- return UnaryMemFunT<C, Argument1>(object, method, arg1);
+}
+
+template<class Job>
+bool
+JobDialer<Job>::canDial(AsyncCall &call)
+{
+ if (!job)
+ return call.cancel("job gone");
+
+ return job->canBeCalled(call);
+}
+
+template<class Job>
+void
+JobDialer<Job>::dial(AsyncCall &call)
+{
+ job->callStart(call);
+
+ try {
+ doDial();
+ } catch (const std::exception &e) {
+ debugs(call.debugSection, 3,
+ HERE << call.name << " threw exception: " << e.what());
+ job->callException(e);
+ }
+
+ job->callEnd(); // may delete job
}
#endif /* SQUID_ASYNCJOBCALLS_H */
- \b Job: an AsyncJob object.
- \b Creator: the code creating the job. Usually the Initiator.
-- \b Start: the act of calling AsyncStart with a job pointer.
+- \b Start: the act of calling AsyncJob::Start with a job pointer.
- \b Initiator: the code starting the job. Usually the Creator.
\section Life Typical life cycle
-# Creator creates and initializes a job.
--# Initiator starts the job. If Initiator expects
-to communicate with the started job, then it stores the job pointer
-returned by AsyncStart.
+-# If Initiator expects to communicate with the job after start,
+ then it stores the job pointer
+-# Initiator starts the job by calling AsyncJob::Start.
-# The job's start() method is called. The method usually schedules
some I/O or registers to receive some other callbacks.
-# The job runs and does what it is supposed to do. This usually involves
If you want to do something before starting the job, do it in the constructor
or some custom method that the job creator will call _before_ calling
-AsyncStart():
+AsyncJob::Start():
std::auto_ptr<MyJob> job(new MyJob(...)); // sync/blocking
job->prepare(...); // sync/blocking
If you do not need complex preparations, it is better to do this instead:
- AsyncStart(new MyJob(...));
+ AsyncJob::Start(new MyJob(...));
Keep in mind that you have no async debugging, cleanup, and protections until
-you call AsyncStart with a job pointer.
+you call AsyncJob::Start with a job pointer.
\section Rules Basic rules
-- To start a job, use AsyncStart. Do not start the same job more than once.
+- To start a job, use AsyncJob::Start.
+ Do not start the same job more than once.
- Never call start() directly. Treat this method as main() in C/C++.
--- /dev/null
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_CBC_POINTER_H
+#define SQUID_CBC_POINTER_H
+
+#include "base/TextException.h"
+#include "cbdata.h"
+
+/**
+ \ingroup CBDATAAPI
+ *
+ * Safely points to a cbdata-protected class (cbc), such as an AsyncJob.
+ * When a cbc we communicate with disappears without
+ * notice or a notice has not reached us yet, this class prevents
+ * dereferencing the pointer to the gone cbc object.
+ */
+template<class Cbc>
+class CbcPointer
+{
+public:
+ CbcPointer(); // a nil pointer
+ CbcPointer(Cbc *aCbc);
+ CbcPointer(const CbcPointer &p);
+ ~CbcPointer();
+
+ Cbc *raw() const; ///< a temporary raw Cbc pointer; may be invalid
+ Cbc *get() const; ///< a temporary valid raw Cbc pointer or NULL
+ Cbc &operator *() const; ///< a valid Cbc reference or exception
+ Cbc *operator ->() const; ///< a valid Cbc pointer or exception
+
+ // no bool operator because set() != valid()
+ bool set() const { return cbc != NULL; } ///< was set but may be invalid
+ Cbc *valid() const { return get(); } ///< was set and is valid
+ bool operator !() const { return !valid(); } ///< invalid or was not set
+ bool operator ==(const CbcPointer<Cbc> &o) const { return lock == o.lock; }
+
+ CbcPointer &operator =(const CbcPointer &p);
+
+ /// support converting a child cbc pointer into a parent cbc pointer
+ template <typename Other>
+ CbcPointer(const CbcPointer<Other> &o): cbc(o.raw()), lock(NULL) {
+ if (o.valid())
+ lock = cbdataReference(o->toCbdata());
+ }
+
+ /// support assigning a child cbc pointer to a parent cbc pointer
+ template <typename Other>
+ CbcPointer &operator =(const CbcPointer<Other> &o) {
+ clear();
+ cbc = o.raw(); // so that set() is accurate
+ if (o.valid())
+ lock = cbdataReference(o->toCbdata());
+ return *this;
+ }
+
+ void clear(); ///< make pointer not set; does not invalidate cbdata
+
+ std::ostream &print(std::ostream &os) const;
+
+private:
+ Cbc *cbc; // a possibly invalid pointer to a cbdata class
+ void *lock; // a valid pointer to cbc's cbdata or nil
+};
+
+template <class Cbc>
+inline
+std::ostream &operator <<(std::ostream &os, const CbcPointer<Cbc> &p)
+{
+ return p.print(os);
+}
+
+// inlined methods
+
+template<class Cbc>
+CbcPointer<Cbc>::CbcPointer(): cbc(NULL), lock(NULL)
+{
+}
+
+template<class Cbc>
+CbcPointer<Cbc>::CbcPointer(Cbc *aCbc): cbc(aCbc), lock(NULL)
+{
+ if (cbc)
+ lock = cbdataReference(cbc->toCbdata());
+}
+
+template<class Cbc>
+CbcPointer<Cbc>::CbcPointer(const CbcPointer &d): cbc(d.cbc), lock(NULL)
+{
+ if (d.lock && cbdataReferenceValid(d.lock))
+ lock = cbdataReference(d.lock);
+}
+
+template<class Cbc>
+CbcPointer<Cbc>::~CbcPointer()
+{
+ clear();
+}
+
+template<class Cbc>
+CbcPointer<Cbc> &CbcPointer<Cbc>::operator =(const CbcPointer &d)
+{
+ clear();
+ cbc = d.cbc;
+ if (d.lock && cbdataReferenceValid(d.lock))
+ lock = cbdataReference(d.lock);
+ return *this;
+}
+
+template<class Cbc>
+void
+CbcPointer<Cbc>::clear()
+{
+ cbdataReferenceDone(lock); // lock may be nil before and will be nil after
+ cbc = NULL;
+}
+
+template<class Cbc>
+Cbc *
+CbcPointer<Cbc>::raw() const
+{
+ return cbc;
+}
+
+template<class Cbc>
+Cbc *
+CbcPointer<Cbc>::get() const
+{
+ return (lock && cbdataReferenceValid(lock)) ? cbc : NULL;
+}
+
+template<class Cbc>
+Cbc &
+CbcPointer<Cbc>::operator *() const
+{
+ Cbc *c = get();
+ Must(c);
+ return *c;
+}
+
+template<class Cbc>
+Cbc *
+CbcPointer<Cbc>::operator ->() const
+{
+ Cbc *c = get();
+ Must(c);
+ return c;
+}
+
+template <class Cbc>
+std::ostream &CbcPointer<Cbc>::print(std::ostream &os) const
+{
+ return os << cbc << '/' << lock;
+}
+
+
+#endif /* SQUID_CBC_POINTER_H */
AsyncJobCalls.h \
AsyncCallQueue.cc \
AsyncCallQueue.h \
+ CbcPointer.h \
TextException.cc \
TextException.h
} else if (!strcasecmp(token, "weighted-round-robin")) {
p->options.weighted_roundrobin = 1;
#if USE_HTCP
-
} else if (!strcasecmp(token, "htcp")) {
p->options.htcp = 1;
- } else if (!strcasecmp(token, "htcp-oldsquid")) {
- p->options.htcp = 1;
- p->options.htcp_oldsquid = 1;
- } else if (!strcasecmp(token, "htcp-no-clr")) {
- if (p->options.htcp_only_clr)
- fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
- p->options.htcp = 1;
- p->options.htcp_no_clr = 1;
- } else if (!strcasecmp(token, "htcp-no-purge-clr")) {
- p->options.htcp = 1;
- p->options.htcp_no_purge_clr = 1;
- } else if (!strcasecmp(token, "htcp-only-clr")) {
- if (p->options.htcp_no_clr)
- fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
+ } else if (!strncasecmp(token, "htcp=", 5) || !strncasecmp(token, "htcp-", 5)) {
+ /* Note: The htcp- form is deprecated, replaced by htcp= */
p->options.htcp = 1;
- p->options.htcp_only_clr = 1;
- } else if (!strcasecmp(token, "htcp-forward-clr")) {
- p->options.htcp = 1;
- p->options.htcp_forward_clr = 1;
+ char *tmp = xstrdup(token+5);
+ char *mode, *nextmode;
+ for (mode = nextmode = tmp; mode; mode = nextmode) {
+ nextmode = strchr(mode, ',');
+ if (nextmode)
+ *nextmode++ = '\0';
+ if (!strcasecmp(mode, "no-clr")) {
+ if (p->options.htcp_only_clr)
+ fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
+ p->options.htcp_no_clr = 1;
+ } else if (!strcasecmp(mode, "no-purge-clr")) {
+ p->options.htcp_no_purge_clr = 1;
+ } else if (!strcasecmp(mode, "only-clr")) {
+ if (p->options.htcp_no_clr)
+ fatalf("parse_peer: can't set htcp no-clr and only-clr simultaneously");
+ p->options.htcp_only_clr = 1;
+ } else if (!strcasecmp(mode, "forward-clr")) {
+ p->options.htcp_forward_clr = 1;
+ } else if (!strcasecmp(mode, "oldsquid")) {
+ p->options.htcp_oldsquid = 1;
+ } else {
+ fatalf("invalid HTCP mode '%s'", mode);
+ }
+ }
+ safe_free(tmp);
#endif
-
} else if (!strcasecmp(token, "no-netdb-exchange")) {
p->options.no_netdb_exchange = 1;
i = GetInteger(); /* token: min */
+ /* catch negative and insanely huge values close to 32-bit wrap */
+ if (i < 0) {
+ debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern minimum age negative. Cropped back to zero.");
+ i = 0;
+ }
+ if (i > 60*24*365) {
+ debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern minimum age too high. Cropped back to 1 year.");
+ i = 60*24*365;
+ }
+
min = (time_t) (i * 60); /* convert minutes to seconds */
i = GetInteger(); /* token: pct */
i = GetInteger(); /* token: max */
+ /* catch negative and insanely huge values close to 32-bit wrap */
+ if (i < 0) {
+ debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern maximum age negative. Cropped back to zero.");
+ i = 0;
+ }
+ if (i > 60*24*365) {
+ debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern maximum age too high. Cropped back to 1 year.");
+ i = 60*24*365;
+ }
+
max = (time_t) (i * 60); /* convert minutes to seconds */
/* Options */
t = strchr(t, ',');
}
#if USE_SSL
- } else if (strcmp(token, "sslBump") == 0) {
+ } else if (strcasecmp(token, "sslBump") == 0) {
+ debugs(3, DBG_CRITICAL, "WARNING: '" << token << "' is deprecated " <<
+ "in http_port. Use 'ssl-bump' instead.");
+ s->sslBump = 1; // accelerated when bumped, otherwise not
+ } else if (strcmp(token, "ssl-bump") == 0) {
s->sslBump = 1; // accelerated when bumped, otherwise not
} else if (strncmp(token, "cert=", 5) == 0) {
safe_free(s->cert);
#include "wordlist.h"
#include "Debug.h"
+// for rotate_logs()
+#include "protos.h"
+
/// \ingroup CacheManagerInternal
#define MGR_PASSWD_SZ 128
registerAction(new OfflineToggleAction);
registerAction(new ShutdownAction);
registerAction(new ReconfigureAction);
+ registerAction(new RotateAction);
registerAction(new MenuAction(this));
}
/// \ingroup CacheManagerInternal
CacheManager::ReconfigureAction::ReconfigureAction() : CacheManagerAction("reconfigure","Reconfigure Squid", 1, 1) { }
+/// \ingroup CacheManagerInternal
+void
+CacheManager::RotateAction::run(StoreEntry * sentry)
+{
+ debugs(16, DBG_IMPORTANT, "Rotate Logs by Cache Manager command.");
+ storeAppendPrintf(sentry, "Rotating Squid Process Logs ....");
+#ifdef _SQUID_LINUX_THREADS_
+ rotate_logs(SIGQUIT);
+#else
+ rotate_logs(SIGUSR1);
+#endif
+}
+/// \ingroup CacheManagerInternal
+CacheManager::RotateAction::RotateAction() : CacheManagerAction("rotate","Rotate Squid Logs", 1, 1) { }
+
/// \ingroup CacheManagerInternal
void
CacheManager::OfflineToggleAction::run(StoreEntry * sentry)
NOTE: The default if no htcp_access lines are present is to
deny all traffic. This default may cause problems with peers
- using the htcp or htcp-oldsquid options.
+ using the htcp option.
This clause only supports fast acl types.
See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details.
accel Accelerator mode. Also needs at least one of
vhost / vport / defaultsite.
- sslbump Intercept each CONNECT request matching ssl_bump ACL,
+ ssl-bump Intercept each CONNECT request matching ssl_bump ACL,
establish secure connection with the client and with
the server, decrypt HTTP messages as they pass through
Squid, and treat them as unencrypted HTTP messages,
htcp Send HTCP, instead of ICP, queries to the neighbor.
You probably also want to set the "icp-port" to 4827
- instead of 3130.
+ instead of 3130. This directive accepts a comma separated
+ list of options described below.
- htcp-oldsquid Send HTCP to old Squid versions.
+ htcp=oldsquid Send HTCP to old Squid versions (2.5 or earlier).
- htcp-no-clr Send HTCP to the neighbor but without
+ htcp=no-clr Send HTCP to the neighbor but without
sending any CLR requests. This cannot be used with
- htcp-only-clr.
+ only-clr.
- htcp-only-clr Send HTCP to the neighbor but ONLY CLR requests.
- This cannot be used with htcp-no-clr.
+ htcp=only-clr Send HTCP to the neighbor but ONLY CLR requests.
+ This cannot be used with no-clr.
- htcp-no-purge-clr
+ htcp=no-purge-clr
Send HTCP to the neighbor including CLRs but only when
they do not result from PURGE requests.
- htcp-forward-clr
+ htcp=forward-clr
Forward any HTCP CLR requests this proxy receives to the peer.
request_header_access Retry-After allow all
request_header_access Title allow all
request_header_access Connection allow all
- request_header_access Proxy-Connection allow all
request_header_access All deny all
although many of those are HTTP reply headers, and so should be
reply_header_access Retry-After allow all
reply_header_access Title allow all
reply_header_access Connection allow all
- reply_header_access Proxy-Connection allow all
reply_header_access All deny all
although the HTTP request headers won't be usefully controlled
makeSpaceAvailable();
typedef CommCbMemFunT<ConnStateData, CommIoCbParams> Dialer;
- reader = asyncCall(33, 5, "ConnStateData::clientReadRequest",
- Dialer(this, &ConnStateData::clientReadRequest));
+ reader = JobCallback(33, 5, Dialer, this, ConnStateData::clientReadRequest);
comm_read(clientConn->fd, in.addressToReadInto(), getAvailableBufferLength(), reader);
}
clientSetKeepaliveFlag(ClientHttpRequest * http)
{
HttpRequest *request = http->request;
- const HttpHeader *req_hdr = &request->header;
debugs(33, 3, "clientSetKeepaliveFlag: http_ver = " <<
request->http_ver.major << "." << request->http_ver.minor);
debugs(33, 3, "clientSetKeepaliveFlag: method = " <<
RequestMethodStr(request->method));
- /* We are HTTP/1.1 facing clients now*/
- HttpVersion http_ver(1,1);
-
- if (httpMsgIsPersistent(http_ver, req_hdr))
- request->flags.proxy_keepalive = 1;
+ // TODO: move to HttpRequest::hdrCacheInit, just like HttpReply.
+ request->flags.proxy_keepalive = request->persistent() ? 1 : 0;
}
static int
{
assert(rep == NULL);
- if (!multipartRangeRequest()) {
+ if (!multipartRangeRequest() && !http->request->flags.chunked_reply) {
size_t length = lengthToSend(bodyData.range());
noteSentBodyBytes (length);
AsyncCall::Pointer call = commCbCall(33, 5, "clientWriteBodyComplete",
MemBuf mb;
mb.init();
- packRange(bodyData, &mb);
+ if (multipartRangeRequest())
+ packRange(bodyData, &mb);
+ else
+ packChunk(bodyData, mb);
if (mb.contentSize()) {
/* write */
writeComplete(fd(), NULL, 0, COMM_OK);
}
+/**
+ * Packs bodyData into mb using chunked encoding. Packs the last-chunk
+ * if bodyData is empty.
+ */
+void
+ClientSocketContext::packChunk(const StoreIOBuffer &bodyData, MemBuf &mb)
+{
+ const uint64_t length =
+ static_cast<uint64_t>(lengthToSend(bodyData.range()));
+ noteSentBodyBytes(length);
+
+ mb.Printf("%"PRIX64"\r\n", length);
+ mb.append(bodyData.data, length);
+ mb.Printf("\r\n");
+}
+
/** put terminating boundary for multiparts */
static void
clientPackTermBound(String boundary, MemBuf * mb)
#endif
if (bodyData.data && bodyData.length) {
- if (!multipartRangeRequest()) {
+ if (multipartRangeRequest())
+ packRange(bodyData, mb);
+ else if (http->request->flags.chunked_reply) {
+ packChunk(bodyData, *mb);
+ } else {
size_t length = lengthToSend(bodyData.range());
noteSentBodyBytes (length);
mb->append(bodyData.data, length);
- } else {
- packRange(bodyData, mb);
}
}
return;
}
- if (responseFinishedOrFailed(rep, receivedData)) {
+ // After sending Transfer-Encoding: chunked (at least), always send
+ // the last-chunk if there was no error, ignoring responseFinishedOrFailed.
+ const bool mustSendLastChunk = http->request->flags.chunked_reply &&
+ !http->request->flags.stream_error && !context->startOfOutput();
+ if (responseFinishedOrFailed(rep, receivedData) && !mustSendLastChunk) {
context->writeComplete(fd, NULL, 0, COMM_OK);
PROF_stop(clientSocketRecipient);
return;
* Set the timeout BEFORE calling clientReadRequest().
*/
typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer timeoutCall = asyncCall(33, 5, "ConnStateData::requestTimeout",
- TimeoutDialer(this, &ConnStateData::requestTimeout));
+ AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
+ TimeoutDialer, this, ConnStateData::requestTimeout);
commSetTimeout(clientConn->fd, Config.Timeout.persistent_request, timeoutCall);
readSomeData();
if (!request.parseHeader(HttpParserHdrBuf(hp), HttpParserHdrSz(hp)))
return false;
- return request.header.has(HDR_TRANSFER_ENCODING) &&
- request.header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ',');
+ return request.header.chunked();
}
bool notedUseOfBuffer = false;
bool tePresent = false;
bool deChunked = false;
+ bool mustReplyToOptions = false;
bool unsupportedTe = false;
/* We have an initial client stream in place should it be needed */
} else
conn->cleanDechunkingRequest();
+ if (method == METHOD_TRACE || method == METHOD_OPTIONS)
+ request->max_forwards = request->header.getInt64(HDR_MAX_FORWARDS);
+
+ mustReplyToOptions = (method == METHOD_OPTIONS) && (request->max_forwards == 0);
unsupportedTe = tePresent && !deChunked;
- if (!urlCheckRequest(request) || unsupportedTe) {
+ if (!urlCheckRequest(request) || mustReplyToOptions || unsupportedTe) {
clientStreamNode *node = context->getClientReplyContext();
clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
assert (repContext);
* if we don't close() here, we still need a timeout handler!
*/
typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer timeoutCall = asyncCall(33, 5, "ConnStateData::requestTimeout",
- TimeoutDialer(this,&ConnStateData::requestTimeout));
+ AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
+ TimeoutDialer, this, ConnStateData::requestTimeout);
commSetTimeout(io.fd, 30, timeoutCall);
/*
connState = connStateCreate(details, s);
typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
- AsyncCall::Pointer call = asyncCall(33, 5, "ConnStateData::connStateClosed",
- Dialer(connState, &ConnStateData::connStateClosed));
+ AsyncCall::Pointer call = JobCallback(33, 5, Dialer, connState, ConnStateData::connStateClosed);
comm_add_close_handler(details->fd, call);
if (Config.onoff.log_fqdn)
fqdncache_gethostbyaddr(details->remote, FQDN_LOOKUP_IF_MISS);
typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer timeoutCall = asyncCall(33, 5, "ConnStateData::requestTimeout",
- TimeoutDialer(connState,&ConnStateData::requestTimeout));
+ AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
+ TimeoutDialer, connState, ConnStateData::requestTimeout);
commSetTimeout(details->fd, Config.Timeout.read, timeoutCall);
#if USE_IDENT
fd_note(details->fd, "client https connect");
ConnStateData *connState = connStateCreate(details, &s->http);
typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
- AsyncCall::Pointer call = asyncCall(33, 5, "ConnStateData::connStateClosed",
- Dialer(connState, &ConnStateData::connStateClosed));
+ AsyncCall::Pointer call = JobCallback(33, 5, Dialer, connState, ConnStateData::connStateClosed);
comm_add_close_handler(details->fd, call);
if (Config.onoff.log_fqdn)
fqdncache_gethostbyaddr(details->remote, FQDN_LOOKUP_IF_MISS);
typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer timeoutCall = asyncCall(33, 5, "ConnStateData::requestTimeout",
- TimeoutDialer(connState,&ConnStateData::requestTimeout));
+ AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
+ TimeoutDialer, connState, ConnStateData::requestTimeout);
commSetTimeout(details->fd, Config.Timeout.request, timeoutCall);
#if USE_IDENT
fd_note(pinning_fd, desc);
typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
- pinning.closeHandler = asyncCall(33, 5, "ConnStateData::clientPinnedConnectionClosed",
- Dialer(this, &ConnStateData::clientPinnedConnectionClosed));
+ pinning.closeHandler = JobCallback(33, 5,
+ Dialer, this, ConnStateData::clientPinnedConnectionClosed);
comm_add_close_handler(pinning_fd, pinning.closeHandler);
}
private:
CBDATA_CLASS(ClientSocketContext);
void prepareReply(HttpReply * rep);
+ void packChunk(const StoreIOBuffer &bodyData, MemBuf &mb);
void packRange(StoreIOBuffer const &, MemBuf * mb);
void deRegisterWithConn();
void doClose();
if (http->flags.done_copying)
return 1;
+ if (http->request->flags.chunked_reply && !flags.complete) {
+ // last-chunk was not sent
+ return 0;
+ }
+
/*
* Handle STORE_OK objects.
* objectLen(entry) will be set proprely.
debugs(88, 5, "clientReplyStatus: transfer is DONE");
/* Ok we're finished, but how? */
- if (http->storeEntry()->getReply()->bodySize(http->request->method) < 0) {
+ const int64_t expectedBodySize =
+ http->storeEntry()->getReply()->bodySize(http->request->method);
+ if (!http->request->flags.proxy_keepalive && expectedBodySize < 0) {
debugs(88, 5, "clientReplyStatus: closing, content_length < 0");
return STREAM_FAILED;
}
return STREAM_FAILED;
}
- if (!http->gotEnough()) {
+ if (expectedBodySize >= 0 && !http->gotEnough()) {
debugs(88, 5, "clientReplyStatus: client didn't get all it expected");
return STREAM_UNPLANNED_COMPLETE;
}
#endif
+ const bool maySendChunkedReply = !request->multipartRangeRequest() &&
+ (request->http_ver >= HttpVersion(1, 1));
+
/* Check whether we should send keep-alive */
if (!Config.onoff.error_pconns && reply->sline.status >= 400 && !request->flags.must_keepalive) {
debugs(33, 3, "clientBuildReplyHeader: Error, don't keep-alive");
} else if (request->flags.connection_auth && !reply->keep_alive) {
debugs(33, 2, "clientBuildReplyHeader: Connection oriented auth but server side non-persistent");
request->flags.proxy_keepalive = 0;
- } else if (reply->bodySize(request->method) < 0) {
+ } else if (reply->bodySize(request->method) < 0 && !maySendChunkedReply) {
debugs(88, 3, "clientBuildReplyHeader: can't keep-alive, unknown body size" );
request->flags.proxy_keepalive = 0;
} else if (fdUsageHigh()&& !request->flags.must_keepalive) {
debugs(88, 3, "clientBuildReplyHeader: Not many unused FDs, can't keep-alive");
request->flags.proxy_keepalive = 0;
- } else if (request->http_ver.major == 1 && request->http_ver.minor == 1) {
- debugs(88, 3, "clientBuildReplyHeader: Client is HTTP/1.1, send keep-alive, no overriding reasons not to");
- request->flags.proxy_keepalive = 1;
}
+ // Decide if we send chunked reply
+ if (maySendChunkedReply &&
+ request->flags.proxy_keepalive &&
+ reply->bodySize(request->method) < 0) {
+ debugs(88, 3, "clientBuildReplyHeader: chunked reply");
+ request->flags.chunked_reply = 1;
+ hdr->putStr(HDR_TRANSFER_ENCODING, "chunked");
+ }
/* Append VIA */
if (Config.onoff.via) {
hdr->delById(HDR_VIA);
hdr->putStr(HDR_VIA, strVia.termedBuf());
}
- /* Signal keep-alive if needed */
- hdr->putStr( (http->flags.accel || http->flags.intercepted)? HDR_CONNECTION : HDR_PROXY_CONNECTION,
- request->flags.proxy_keepalive ? "keep-alive" : "close");
+ /* Signal keep-alive or close explicitly */
+ hdr->putStr(HDR_CONNECTION, request->flags.proxy_keepalive ? "keep-alive" : "close");
#if ADD_X_REQUEST_URI
/*
return;
}
- /* TODO: handle OPTIONS request on max_forwards == 0 as well */
+ // OPTIONS with Max-Forwards:0 handled in clientProcessRequest()
if (context->http->request->method == METHOD_TRACE) {
if (context->http->request->max_forwards == 0) {
debugs(88, 5, "clientReplyContext::sendStreamError: A stream error has occured, marking as complete and sending no data.");
StoreIOBuffer localTempBuffer;
flags.complete = 1;
+ http->request->flags.stream_error = 1;
localTempBuffer.flags.error = result.flags.error;
clientStreamCallback((clientStreamNode*)http->client_stream.head->data, http, NULL,
localTempBuffer);
}
#endif
- if (request->method == METHOD_TRACE || request->method == METHOD_OPTIONS) {
- request->max_forwards = req_hdr->getInt64(HDR_MAX_FORWARDS);
- }
request->flags.cachable = http->request->cacheable();
assert(!virginHeadSource);
assert(!adaptedBodySource);
virginHeadSource = initiateAdaptation(
- new Adaptation::Iterator(this, request, NULL, g));
+ new Adaptation::Iterator(request, NULL, g));
// we could try to guess whether we can bypass this adaptation
// initiation failure, but it should not really happen
- assert(virginHeadSource != NULL); // Must, really
+ Must(initiated(virginHeadSource));
}
void
void endRequestSatisfaction();
private:
- Adaptation::Initiate *virginHeadSource;
+ CbcPointer<Adaptation::Initiate> virginHeadSource;
BodyPipe::Pointer adaptedBodySource;
bool request_satisfaction_mode;
if (writeTimedOut(fd)) {
// We have an active write callback and we are timed out
+ debugs(5, 5, "checkTimeouts: FD " << fd << " auto write timeout");
+ commSetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0);
commio_finish_callback(fd, COMMIO_FD_WRITECB(fd), COMM_ERROR, ETIMEDOUT);
} else if (AlreadyTimedOut(F))
continue;
(void) 0;
}
+/* hack needed on SunStudio to avoid linkage convention mismatch */
+static void cxx_xfree(void *ptr)
+{
+ xfree(ptr);
+}
+
/*
* opens a disk file specified by 'path'. This function always
* blocks! There is no callback.
wq->next = NULL;
- wq->free_func = xfree;
+ wq->free_func = cxx_xfree;
do {
q = fdd->write_q;
} else {
if (DnsSocketB >= 0 && nameservers[ns].S.IsIPv6())
y = comm_udp_sendto(DnsSocketB, nameservers[ns].S, q->buf, q->sz);
- else
+ else if (DnsSocketA)
x = comm_udp_sendto(DnsSocketA, nameservers[ns].S, q->buf, q->sz);
}
} while ( (x<0 && y<0) && q->nsends % nns != 0);
- if (y >= 0) {
+ if (y > 0) {
fd_bytes(DnsSocketB, y, FD_WRITE);
- commSetSelect(DnsSocketB, COMM_SELECT_READ, idnsRead, NULL, 0);
}
-
- if (x >= 0) {
+ if (x > 0) {
fd_bytes(DnsSocketA, x, FD_WRITE);
- commSetSelect(DnsSocketA, COMM_SELECT_READ, idnsRead, NULL, 0);
}
nameservers[ns].nqueries++;
debugs(78, 3, "idnsRead: starting with FD " << fd);
+ // Always keep reading. This stops (or at least makes harder) several
+ // attacks on the DNS client.
+ commSetSelect(fd, COMM_SELECT_READ, idnsRead, NULL, 0);
+
/* BUG (UNRESOLVED)
* two code lines after returning from comm_udprecvfrom()
* something overwrites the memory behind the from parameter.
if (ns >= 0) {
nameservers[ns].nreplies++;
- } else if (Config.onoff.ignore_unknown_nameservers) {
+ }
+
+ // Before unknown_nameservers check to avoid flooding cache.log on attacks,
+ // but after the ++ above to keep statistics right.
+ if (!lru_list.head)
+ continue; // Don't process replies if there is no pending query.
+
+ if (ns < 0 && Config.onoff.ignore_unknown_nameservers) {
static time_t last_warning = 0;
if (squid_curtime - last_warning > 60) {
idnsGrokReply(rbuf, len);
}
-
- if (lru_list.head) {
- commSetSelect(fd, COMM_SELECT_READ, idnsRead, NULL, 0);
- }
}
static void
return;
}
- vc->msg->size += len; // XXX should not access -> size directly
+ vc->msg->size += len; // XXX should not access -> size directly
if (vc->msg->contentSize() < vc->msglen) {
comm_read(fd, buf + len, vc->msglen - vc->msg->contentSize(), idnsReadVC, vc);
if (DnsSocketB >= 0) {
port = comm_local_port(DnsSocketB);
debugs(78, 1, "DNS Socket created at " << addrB << ", FD " << DnsSocketB);
+ commSetSelect(DnsSocketB, COMM_SELECT_READ, idnsRead, NULL, 0);
}
if (DnsSocketA >= 0) {
port = comm_local_port(DnsSocketA);
debugs(78, 1, "DNS Socket created at " << addrA << ", FD " << DnsSocketA);
+ commSetSelect(DnsSocketA, COMM_SELECT_READ, idnsRead, NULL, 0);
}
}
if (rep) {
if (rep->sline.status != HTTP_OK) {
rep = NULL;
- esiStream->include->fail (esiStream);
+ esiStream->include->includeFail (esiStream);
esiStream->finished = 1;
httpRequestFree (http);
return;
/* XXX when reviewing ESI this is the first place to look */
node->data = NULL;
esiStream->finished = 1;
- esiStream->include->fail (esiStream);
+ esiStream->include->includeFail (esiStream);
return;
};
case STREAM_FAILED:
debugs(86, 1, "ESI subrequest failed transfer");
- esiStream->include->fail (esiStream);
+ esiStream->include->includeFail (esiStream);
esiStream->finished = 1;
httpRequestFree (http);
return;
}
void
-ESIInclude::fail (ESIStreamContext::Pointer stream)
+ESIInclude::includeFail (ESIStreamContext::Pointer stream)
{
subRequestDone (stream, false);
}
ESISegment::Pointer altcontent;
ESIVarState *varState;
char *srcurl, *alturl;
- void fail(ESIStreamContext::Pointer);
+ void includeFail(ESIStreamContext::Pointer);
void finish();
private:
## Special Universal .h dependency test script
## aborts if error encountered
testHeaders: $(srcdir)/ufs/*.h $(srcdir)/coss/*.h
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(srcdir)/ufs" || exit 1
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(srcdir)/coss" || exit 1
+ $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" $^ || exit 1
## diskd/ has no .h files
## aufs/ has no .h files
## ./ has no .h files
flags.rest_supported = 1;
typedef CommCbMemFunT<FtpStateData, CommCloseCbParams> Dialer;
- AsyncCall::Pointer closer = asyncCall(9, 5, "FtpStateData::ctrlClosed",
- Dialer(this, &FtpStateData::ctrlClosed));
+ AsyncCall::Pointer closer = JobCallback(9, 5, Dialer, this, FtpStateData::ctrlClosed);
ctrl.opened(conn, closer);
if (request->method == METHOD_PUT)
commSetTimeout(ctrl.conn->fd, -1, nullCall);
typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer timeoutCall = asyncCall(9, 5, "FtpStateData::ftpTimeout",
- TimeoutDialer(this, &FtpStateData::ftpTimeout));
+ AsyncCall::Pointer timeoutCall = JobCallback(9, 5, TimeoutDialer, this, FtpStateData::ftpTimeout);
commSetTimeout(data.conn->fd, Config.Timeout.read, timeoutCall);
}
data.read_pending = true;
typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer timeoutCall = asyncCall(9, 5, "FtpStateData::ftpTimeout",
- TimeoutDialer(this,&FtpStateData::ftpTimeout));
+ AsyncCall::Pointer timeoutCall = JobCallback(9, 5,
+ TimeoutDialer, this, FtpStateData::ftpTimeout);
commSetTimeout(data.conn->fd, Config.Timeout.read, timeoutCall);
debugs(9,5,HERE << "queueing read on FD " << data.conn->fd);
typedef CommCbMemFunT<FtpStateData, CommIoCbParams> Dialer;
entry->delayAwareRead(data.conn->fd, data.readBuf->space(), read_sz,
- asyncCall(9, 5, "FtpStateData::dataRead",
- Dialer(this, &FtpStateData::dataRead)));
+ JobCallback(9, 5, Dialer, this, FtpStateData::dataRead));
}
void
if (ignoreErrno(io.xerrno)) {
typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer timeoutCall = asyncCall(9, 5, "FtpStateData::ftpTimeout",
- TimeoutDialer(this,&FtpStateData::ftpTimeout));
+ AsyncCall::Pointer timeoutCall = JobCallback(9, 5,
+ TimeoutDialer, this, FtpStateData::ftpTimeout);
commSetTimeout(io.fd, Config.Timeout.read, timeoutCall);
maybeReadVirginBody();
}
typedef CommCbMemFunT<FtpStateData, CommIoCbParams> Dialer;
- AsyncCall::Pointer call = asyncCall(9, 5, "FtpStateData::ftpWriteCommandCallback",
- Dialer(this, &FtpStateData::ftpWriteCommandCallback));
+ AsyncCall::Pointer call = JobCallback(9, 5, Dialer, this, FtpStateData::ftpWriteCommandCallback);
comm_write(ctrl.conn->fd,
ctrl.last_command,
strlen(ctrl.last_command),
}
typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer timeoutCall = asyncCall(9, 5, "FtpStateData::ftpTimeout",
- TimeoutDialer(this,&FtpStateData::ftpTimeout));
-
+ AsyncCall::Pointer timeoutCall = JobCallback(9, 5, TimeoutDialer, this, FtpStateData::ftpTimeout);
commSetTimeout(ctrl.conn->fd, Config.Timeout.read, timeoutCall);
typedef CommCbMemFunT<FtpStateData, CommIoCbParams> Dialer;
- AsyncCall::Pointer reader=asyncCall(9, 5, "FtpStateData::ftpReadControlReply",
- Dialer(this, &FtpStateData::ftpReadControlReply));
+ AsyncCall::Pointer reader = JobCallback(9, 5, Dialer, this, FtpStateData::ftpReadControlReply);
comm_read(ctrl.conn->fd, ctrl.buf + ctrl.offset, ctrl.size - ctrl.offset, reader);
}
}
* dont acknowledge PASV commands. Use connect timeout to be faster then read timeout (minutes).
*/
typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer timeoutCall = asyncCall(9, 5, "FtpStateData::ftpTimeout",
- TimeoutDialer(ftpState,&FtpStateData::ftpTimeout));
+ AsyncCall::Pointer timeoutCall = JobCallback(9, 5,
+ TimeoutDialer, ftpState, FtpStateData::ftpTimeout);
commSetTimeout(ftpState->ctrl.conn->fd, Config.Timeout.connect, timeoutCall);
}
}
typedef CommCbMemFunT<FtpStateData, CommAcceptCbParams> acceptDialer;
- AsyncCall::Pointer acceptCall = asyncCall(11, 5, "FtpStateData::ftpAcceptDataConnection",
- acceptDialer(ftpState, &FtpStateData::ftpAcceptDataConnection));
+ AsyncCall::Pointer acceptCall = JobCallback(11, 5, acceptDialer, ftpState, FtpStateData::ftpAcceptDataConnection);
ftpState->data.listener = new Comm::ConnAcceptor(conn, false, ftpState->entry->url());
ftpState->data.listener->subscribe(acceptCall);
/* we are ony accepting once, so need to reset the listener socket. */
typedef CommCbMemFunT<FtpStateData, CommAcceptCbParams> acceptDialer;
- AsyncCall::Pointer acceptCall = asyncCall(11, 5, "FtpStateData::ftpAcceptDataConnection",
- acceptDialer(this, &FtpStateData::ftpAcceptDataConnection));
+ AsyncCall::Pointer acceptCall = JobCallback(11, 5, acceptDialer, this, FtpStateData::ftpAcceptDataConnection);
data.listener = new Comm::ConnAcceptor(data.listen_conn, false, data.host);
data.listener->subscribe(acceptCall);
AsyncJob::AsyncStart(data.listener);
/* When client code is 150 with no data channel, Accept data channel. */
debugs(9, 3, "ftpReadStor: accepting data channel");
typedef CommCbMemFunT<FtpStateData, CommAcceptCbParams> acceptDialer;
- AsyncCall::Pointer acceptCall = asyncCall(11, 5, "FtpStateData::ftpAcceptDataConnection",
- acceptDialer(this, &FtpStateData::ftpAcceptDataConnection));
+ AsyncCall::Pointer acceptCall = JobCallback(11, 5,
+ acceptDialer, this, FtpStateData::ftpAcceptDataConnection);
data.listener = new Comm::ConnAcceptor(data.conn, false, data.host);
data.listener->subscribe(acceptCall);
/* Accept data channel */
typedef CommCbMemFunT<FtpStateData, CommAcceptCbParams> acceptDialer;
- AsyncCall::Pointer acceptCall = asyncCall(11, 5, "FtpStateData::ftpAcceptDataConnection",
- acceptDialer(ftpState, &FtpStateData::ftpAcceptDataConnection));
+ AsyncCall::Pointer acceptCall = JobCallback(11, 5,
+ acceptDialer, ftpState, FtpStateData::ftpAcceptDataConnection);
ftpState->data.listener = new Comm::ConnAcceptor(ftpState->data.conn, false, ftpState->data.host);
ftpState->data.listener->subscribe(acceptCall);
/* Accept data channel */
ftpState->switchTimeoutToDataChannel();
typedef CommCbMemFunT<FtpStateData, CommAcceptCbParams> acceptDialer;
- AsyncCall::Pointer acceptCall = asyncCall(11, 5, "FtpStateData::ftpAcceptDataConnection",
- acceptDialer(ftpState, &FtpStateData::ftpAcceptDataConnection));
+ AsyncCall::Pointer acceptCall = JobCallback(11, 5,
+ acceptDialer, ftpState, FtpStateData::ftpAcceptDataConnection);
ftpState->data.listener = new Comm::ConnAcceptor(ftpState->data.conn, false, ftpState->data.host);
ftpState->data.listener->subscribe(acceptCall);
AsyncJob::AsyncStart(ftpState->data.listener);
FtpStateData::dataCloser()
{
typedef CommCbMemFunT<FtpStateData, CommCloseCbParams> Dialer;
- return asyncCall(9, 5, "FtpStateData::dataClosed",
- Dialer(this, &FtpStateData::dataClosed));
+ return JobCallback(9, 5, Dialer, this, FtpStateData::dataClosed);
}
/// configures the channel with a descriptor and registers a close handler
* register the handler to free HTTP state data when the FD closes
*/
typedef CommCbMemFunT<HttpStateData, CommCloseCbParams> Dialer;
- closeHandler = asyncCall(9, 5, "httpStateData::httpStateConnClosed",
- Dialer(this,&HttpStateData::httpStateConnClosed));
+ closeHandler = JobCallback(9, 5, Dialer, this, HttpStateData::httpStateConnClosed);
comm_add_close_handler(serverConnection->fd, closeHandler);
}
}
flags.chunked = 0;
- if (newrep->sline.protocol == PROTO_HTTP && newrep->header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ',')) {
+ if (newrep->sline.protocol == PROTO_HTTP && newrep->header.chunked()) {
flags.chunked = 1;
httpChunkDecoder = new ChunkedCodingParser;
}
flags.do_next_read = 0;
typedef CommCbMemFunT<HttpStateData, CommIoCbParams> Dialer;
entry->delayAwareRead(serverConnection->fd, readBuf->space(read_size), read_size,
- asyncCall(11, 5, "HttpStateData::readReply",
- Dialer(this, &HttpStateData::readReply)));
+ JobCallback(11, 5, Dialer, this, HttpStateData::readReply));
}
}
* request bodies.
*/
typedef CommCbMemFunT<HttpStateData, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer timeoutCall = asyncCall(11, 5, "HttpStateData::httpTimeout",
- TimeoutDialer(this,&HttpStateData::httpTimeout));
+ AsyncCall::Pointer timeoutCall = JobCallback(11, 5,
+ TimeoutDialer, this, HttpStateData::httpTimeout);
commSetTimeout(serverConnection->fd, Config.Timeout.read, timeoutCall);
/* maybe append Connection: keep-alive */
if (flags.keepalive) {
- if (flags.proxying) {
- hdr_out->putStr(HDR_PROXY_CONNECTION, "keep-alive");
- } else {
- hdr_out->putStr(HDR_CONNECTION, "keep-alive");
- }
+ hdr_out->putStr(HDR_CONNECTION, "keep-alive");
}
/* append Front-End-Https */
case HDR_TE: /** \par TE: */
case HDR_KEEP_ALIVE: /** \par Keep-Alive: */
case HDR_PROXY_AUTHENTICATE: /** \par Proxy-Authenticate: */
- case HDR_TRAILERS: /** \par Trailers: */
+ case HDR_TRAILER: /** \par Trailer: */
case HDR_UPGRADE: /** \par Upgrade: */
case HDR_TRANSFER_ENCODING: /** \par Transfer-Encoding: */
break;
break;
- case HDR_PROXY_CONNECTION:
+ case HDR_PROXY_CONNECTION: // SHOULD ignore. But doing so breaks things.
+ break;
case HDR_X_FORWARDED_FOR:
case HDR_CACHE_CONTROL:
- /** \par Proxy-Connaction:, X-Forwarded-For:, Cache-Control:
+ /** \par X-Forwarded-For:, Cache-Control:
* handled specially by Squid, so leave off for now.
* append these after the loop if needed */
break;
}
typedef CommCbMemFunT<HttpStateData, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer timeoutCall = asyncCall(11, 5, "HttpStateData::httpTimeout",
- TimeoutDialer(this,&HttpStateData::httpTimeout));
- commSetTimeout(serverConnection->fd, Config.Timeout.lifetime, timeoutCall);
+ AsyncCall::Pointer timeoutCall = JobCallback(11, 5,
+ TimeoutDialer, this, HttpStateData::httpTimeout);
+ commSetTimeout(srverConnection->fd, Config.Timeout.lifetime, timeoutCall);
flags.do_next_read = 1;
maybeReadVirginBody();
if (!startRequestBodyFlow()) // register to receive body data
return false;
typedef CommCbMemFunT<HttpStateData, CommIoCbParams> Dialer;
- Dialer dialer(this, &HttpStateData::sentRequestBody);
- requestSender = asyncCall(11,5, "HttpStateData::sentRequestBody", dialer);
+ requestSender = JobCallback(11,5,
+ Dialer, this, HttpStateData::sentRequestBody);
} else {
assert(!requestBodySource);
typedef CommCbMemFunT<HttpStateData, CommIoCbParams> Dialer;
- Dialer dialer(this, &HttpStateData::sendComplete);
- requestSender = asyncCall(11,5, "HttpStateData::SendComplete", dialer);
+ requestSender = JobCallback(11,5,
+ Dialer, this, HttpStateData::sendComplete);
}
if (_peer != NULL) {
}
typedef CommCbMemFunT<HttpStateData, CommIoCbParams> Dialer;
- Dialer dialer(this, &HttpStateData::sendComplete);
- AsyncCall::Pointer call= asyncCall(11,5, "HttpStateData::SendComplete", dialer);
+ AsyncCall::Pointer call = JobCallback(11, 5, Dialer, this, HttpStateData::sendComplete);
comm_write(serverConnection->fd, "\r\n", 2, call);
}
return;
SQUIDCEXTERN void netdbHandlePingReply(const Ip::Address &from, int hops, int rtt);
SQUIDCEXTERN void netdbPingSite(const char *hostname);
-SQUIDCEXTERN void netdbDump(StoreEntry *);
+void netdbDump(StoreEntry *);
SQUIDCEXTERN void netdbFreeMemory(void);
SQUIDCEXTERN int netdbHostHops(const char *host);
{
debugs(54, 6, HERE);
buf.prepForReading();
- AsyncCall::Pointer readHandler = asyncCall(54, 6, "Ipc::Port::noteRead",
- CommCbMemFunT<Port, CommIoCbParams>(this, &Port::noteRead));
+ typedef CommCbMemFunT<Port, CommIoCbParams> Dialer;
+ AsyncCall::Pointer readHandler = JobCallback(54, 6,
+ Dialer, this, Port::noteRead);
comm_read(fd(), buf.raw(), buf.size(), readHandler);
}
void Ipc::UdsOp::setTimeout(int seconds, const char *handlerName)
{
+ typedef CommCbMemFunT<UdsOp, CommTimeoutCbParams> Dialer;
AsyncCall::Pointer handler = asyncCall(54,5, handlerName,
- CommCbMemFunT<UdsOp, CommTimeoutCbParams>(this,
- &UdsOp::noteTimeout));
+ Dialer(CbcPointer<UdsOp>(this), &UdsOp::noteTimeout));
commSetTimeout(fd(), seconds, handler);
}
void Ipc::UdsSender::write()
{
debugs(54, 5, HERE);
- AsyncCall::Pointer writeHandler = asyncCall(54, 5, "Ipc::UdsSender::wrote",
- CommCbMemFunT<UdsSender, CommIoCbParams>(this, &UdsSender::wrote));
+ typedef CommCbMemFunT<UdsSender, CommIoCbParams> Dialer;
+ AsyncCall::Pointer writeHandler = JobCallback(54, 5,
+ Dialer, this, UdsSender::wrote);
comm_write(fd(), message.raw(), message.size(), writeHandler);
writing = true;
}
void Ipc::SendMessage(const String& toAddress, const TypedMsgHdr &message)
{
- AsyncJob::AsyncStart(new UdsSender(toAddress, message));
+ AsyncJob::Start(new UdsSender(toAddress, message));
}
/// \ingroup IPCacheInternal
static dlink_list lru_list;
+// forward-decls
+static void stat_ipcache_get(StoreEntry *);
+
static FREE ipcacheFreeEntry;
#if USE_DNSSERVERS
static HLPCB ipcacheHandleReply;
mainLoop.setTimeService(&time_engine);
if (IamCoordinatorProcess())
- AsyncJob::AsyncStart(Ipc::Coordinator::Instance());
+ AsyncJob::Start(Ipc::Coordinator::Instance());
else if (UsingSmp() && IamWorkerProcess())
- AsyncJob::AsyncStart(new Ipc::Strand);
+ AsyncJob::Start(new Ipc::Strand);
/* at this point we are finished the synchronous startup. */
starting_up = 0;
memFree(p, MEM_64K_BUF);
}
+static void
+cxx_xfree(void * ptr)
+{
+ xfree(ptr);
+}
+
FREE *
memFreeBufFunc(size_t size)
{
default:
memMeterDec(HugeBufCountMeter);
memMeterDel(HugeBufVolumeMeter, size);
- return xfree;
+ return cxx_xfree;
}
}
#include "htcp.h"
#include "HttpRequest.h"
#include "ICP.h"
+#include "ip/tools.h"
#include "MemObject.h"
#include "PeerDigest.h"
#include "PeerSelectState.h"
storeAppendPrintf(sentry, " closest-only");
#if USE_HTCP
- if (p->options.htcp)
+ if (p->options.htcp) {
storeAppendPrintf(sentry, " htcp");
- if (p->options.htcp_oldsquid)
- storeAppendPrintf(sentry, " htcp-oldsquid");
- if (p->options.htcp_no_clr)
- storeAppendPrintf(sentry, " htcp-no-clr");
- if (p->options.htcp_no_purge_clr)
- storeAppendPrintf(sentry, " htcp-no-purge-clr");
- if (p->options.htcp_only_clr)
- storeAppendPrintf(sentry, " htcp-only-clr");
+ if (p->options.htcp_oldsquid || p->options.htcp_no_clr || p->options.htcp_no_purge_clr || p->options.htcp_only_clr) {
+ int doneopts=0;
+ if (p->options.htcp_oldsquid)
+ storeAppendPrintf(sentry, "%soldsquid",(doneopts++>0?",":"="));
+ if (p->options.htcp_no_clr)
+ storeAppendPrintf(sentry, "%sno-clr",(doneopts++>0?",":"="));
+ if (p->options.htcp_no_purge_clr)
+ storeAppendPrintf(sentry, "%sno-purge-clr",(doneopts++>0?",":"="));
+ if (p->options.htcp_only_clr)
+ storeAppendPrintf(sentry, "%sonly-clr",(doneopts++>0?",":"="));
+ }
+ }
#endif
if (p->options.no_netdb_exchange)
SQUIDCEXTERN const char *fqdncache_gethostbyaddr(const Ip::Address &, int flags);
SQUIDCEXTERN void fqdncache_init(void);
-SQUIDCEXTERN void fqdnStats(StoreEntry *);
+void fqdnStats(StoreEntry *);
SQUIDCEXTERN void fqdncacheReleaseInvalid(const char *);
SQUIDCEXTERN const char *fqdnFromAddr(const Ip::Address &);
SQUIDCEXTERN int fqdncacheQueueDrain(void);
SQUIDCEXTERN void fqdncacheFreeMemory(void);
SQUIDCEXTERN void fqdncache_restart(void);
-SQUIDCEXTERN void fqdncache_purgelru(void *);
+void fqdncache_purgelru(void *);
SQUIDCEXTERN void fqdncacheAddEntryFromHosts(char *addr, wordlist * hostnames);
class FwdState;
SQUIDCEXTERN void httpHdrCcSetMaxAge(HttpHdrCc * cc, int max_age);
SQUIDCEXTERN void httpHdrCcSetSMaxAge(HttpHdrCc * cc, int s_maxage);
SQUIDCEXTERN void httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist);
-SQUIDCEXTERN void httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count);
+void httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count);
/* Http Header Tools */
class HttpHeaderFieldInfo;
SQUIDCEXTERN void httpHeaderCleanModule(void);
/* store report about current header usage and other stats */
-SQUIDCEXTERN void httpHeaderStoreReport(StoreEntry * e);
+void httpHeaderStoreReport(StoreEntry * e);
SQUIDCEXTERN void httpHdrMangleList(HttpHeader *, HttpRequest *, int req_or_rep);
SQUIDCEXTERN int httpReqHdrManglersConfigured();
extern void wccp2ConnectionClose(void);
#endif /* USE_WCCPv2 */
+void ipcache_purgelru(void *);
SQUIDCEXTERN void ipcache_nbgethostbyname(const char *name,
IPH * handler,
void *handlerData);
-SQUIDCEXTERN void ipcache_purgelru(void *);
SQUIDCEXTERN const ipcache_addrs *ipcache_gethostbyname(const char *, int flags);
SQUIDCEXTERN void ipcacheInvalidate(const char *);
SQUIDCEXTERN void ipcacheInvalidateNegative(const char *);
SQUIDCEXTERN void ipcache_init(void);
-SQUIDCEXTERN void stat_ipcache_get(StoreEntry *);
SQUIDCEXTERN void ipcacheCycleAddr(const char *name, ipcache_addrs *);
SQUIDCEXTERN void ipcacheMarkBadAddr(const char *name, const Ip::Address &);
SQUIDCEXTERN void ipcacheMarkGoodAddr(const char *name, const Ip::Address &);
SQUIDCEXTERN const char *getMyHostname(void);
SQUIDCEXTERN const char *uniqueHostname(void);
SQUIDCEXTERN void safeunlink(const char *path, int quiet);
-SQUIDCEXTERN void death(int sig);
+void death(int sig);
SQUIDCEXTERN void fatal(const char *message);
SQUIDCEXTERN void fatalf(const char *fmt,...) PRINTF_FORMAT_ARG1;
SQUIDCEXTERN void fatal_dump(const char *message);
-SQUIDCEXTERN void sigusr2_handle(int sig);
-SQUIDCEXTERN void sig_child(int sig);
+void sigusr2_handle(int sig);
+void sig_child(int sig);
SQUIDCEXTERN void leave_suid(void);
SQUIDCEXTERN void enter_suid(void);
SQUIDCEXTERN void no_suid(void);
## Special Universal .h dependency test script
## aborts if error encountered
testHeaders: $(srcdir)/heap/*.h
- $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" "$(srcdir)/heap" || exit 1
+ $(SHELL) $(top_srcdir)/test-suite/testheaders.sh "$(CXXCOMPILE)" $^ || exit 1
## ./ has no .h files.
## ./lru/ has no .h files.
struct request_flags {
- request_flags(): range(0),nocache(0),ims(0),auth(0),cachable(0),hierarchical(0),loopdetect(0),proxy_keepalive(0),proxying(0),refresh(0),redirected(0),need_validation(0),accelerated(0),ignore_cc(0),intercepted(0),spoof_client_ip(0),internal(0),internalclient(0),must_keepalive(0),destinationIPLookedUp_(0) {
+ request_flags(): range(0),nocache(0),ims(0),auth(0),cachable(0),hierarchical(0),loopdetect(0),proxy_keepalive(0),proxying(0),refresh(0),redirected(0),need_validation(0),accelerated(0),ignore_cc(0),intercepted(0),spoof_client_ip(0),internal(0),internalclient(0),must_keepalive(0),chunked_reply(0),stream_error(0),destinationIPLookedUp_(0) {
#if USE_HTTP_VIOLATIONS
nocache_hack = 0;
#endif
unsigned int pinned:1; /* Request sent on a pinned connection */
unsigned int auth_sent:1; /* Authentication forwarded */
unsigned int no_direct:1; /* Deny direct forwarding unless overriden by always_direct. Used in accelerator mode */
+ unsigned int chunked_reply:1; /**< Reply with chunked transfer encoding */
+ unsigned int stream_error:1; /**< Whether stream error has occured */
// When adding new flags, please update cloneAdaptationImmune() as needed.
void
HttpReply::setHeaders(http_status status, const char *reason,
- const char *ctype, int64_t clen, time_t lmt, time_t expires)
+ const char *ctype, int64_t clen, time_t lmt, time_t expires_)
{
fatal ("Not implemented");
}
--- /dev/null
+/*
+ * $Id$
+ *
+ * AUTHOR: Francesco Chemolli
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ * Stubs for calls to stuff defined in main.cc
+ *
+ */
+
+void
+shut_down(int)
+{ /* stub */ }
+
+void
+reconfigure(int)
+{ /* stub */ }
+
+void
+rotate_logs(int)
+{ /* stub */ }
+
CPPUNIT_TEST_SUITE_REGISTRATION( testCacheManager );
-/* stub functions to link successfully */
-void
-shut_down(int)
-{}
-
-void
-reconfigure(int)
-{}
-
-/* end stubs */
-
/* init memory pools */
void testCacheManager::setUp()
CPPUNIT_TEST_SUITE_REGISTRATION( testEvent );
-/* stub functions to link successfully */
-void
-shut_down(int)
-{}
-
-void
-reconfigure(int)
-{}
-
-/* end stubs */
-
/* init legacy static-initialized modules */
void
CPPUNIT_TEST_SUITE_REGISTRATION( testEventLoop );
-/* stub functions to link successfully */
-void
-shut_down(int)
-{}
-
-void
-reconfigure(int)
-{}
-
-/* end stubs */
-
/* init legacy static-initialized modules */
void
bool doSanityCheckStartLine(MemBuf *b, const size_t h, http_status *e) { return sanityCheckStartLine(b,h,e); };
};
-/* stub functions to link successfully */
-void
-shut_down(int)
-{}
-
-void
-reconfigure(int)
-{}
-
-/* end stubs */
-
/* init memory pools */
void
CPPUNIT_TEST_SUITE_REGISTRATION( testURL );
-/* stub functions to link successfully */
-void
-shut_down(int)
-{}
-
-void
-reconfigure(int)
-{}
-
-/* end stubs */
-
/* init memory pools */
void
#include "acl/Checklist.h"
#endif
-/* Stub routines */
-void
-shut_down(int)
-{}
-
-void
-reconfigure(int)
-{}
-
SQUIDCEXTERN void httpHeaderPutStr(HttpHeader * hdr, http_hdr_type type, const char *str)
{
fatal ("dummy function\n");
statCounter.server.all.requests++;
statCounter.server.other.requests++;
+ request->hier.peer_local_port = comm_local_port(sock); // for %<lp logging
+
tunnelState = new TunnelStateData;
#if DELAY_POOLS
tunnelState->server.setDelayId(DelayId::DelayClient(http));
# This script should be run from the makefile with the directory path and ccflags
#
cc="${1}"
-
-if test "${2}" = ""; then
- dir="."
-else
- dir="${2}"
-fi
+shift
+for dir in /usr/bin /usr/local/bin /usr/gnu/bin
+do
+ test -x ${dir}/true && TRUE=${dir}/true
+done
+TRUE=${TRUE:-/bin/true}
exitCode=0
-for f in `cd ${dir} && ls -1 *.h 2>/dev/null`; do
- echo -n "Testing ${dir}/${f} ..."
- hdr=`echo "${f}" | sed s/.h//`
- if [ ! -e ./testHeaderDeps_${hdr}.o -o ${dir}/${f} -nt ./testHeaderDeps_${hdr}.o ]; then
- ( echo "/* This file is AUTOMATICALLY GENERATED. DO NOT ALTER IT */"
- echo "#include \"${dir}/${f}\" "
- echo "int main( int argc, char* argv[] ) { return 0; } "
- ) >./testHeaderDeps_${hdr}.cc
-
- # run compile test on the new file.
- # DEBUG: echo "TRY: ${cc} -o testHeaderDeps.o ./testHeaderDeps_${hdr}.cc"
- ${cc} -c -o testHeaderDeps_${hdr}.o ./testHeaderDeps_${hdr}.cc
- rm ./testHeaderDeps_${hdr}.cc
- fi
- if [ ! -f testHeaderDeps_${hdr}.o ]; then
- rm testHeaders
- exitCode=1
- else
- echo "OK."
- # unit-tests require an app to run.
- # our most-recent object suits this purpose.
- # let's link or some tests will fail
- ${cc} ./testHeaderDeps_${hdr}.o -o ./testHeaders
- fi
+for f in $@; do
+ echo -n "Testing ${f} ..."
+ t="testhdr_`basename ${f}`"
+ if [ ! -f "$t.o" -o $f -nt "$t.o" ]; then
+ echo >$t.cc <<EOF
+/* This file is AUTOMATICALLY GENERATED. DO NOT ALTER IT */
+#include "${f}"
+int main( int argc, char* argv[] ) { return 0; }
+EOF
+ if ${cc} -c -o $t.o $t.cc ; then
+ echo "Ok."
+ else
+ echo "Fail."
+ exitCode=1
+ fi
+ rm $t.cc $t.o
+ fi
+ test $exitCode -eq 0 || break
done
+#who ever said that the test program needs to be meaningful?
+test $exitCode -eq 0 && cp ${TRUE} testHeaders
exit $exitCode
## we need our local files too (but avoid -I. at all costs)
INCLUDES += -I$(srcdir)
-SUBDIRS =
+SUBDIRS = purge
EXTRA_DIST =
man_MANS =
DISTCLEANFILES =
$(top_builddir)/src/time.o \
$(top_builddir)/src/ip/libip.la \
$(COMPAT_LIB) \
+ $(KRB5LIBS) \
$(XTRA_LIBS)
include $(top_srcdir)/doc/manuals/Substitute.am
+++ /dev/null
-#
-# Makefile
-#
-# The Makefile is divided into three sections, the "generic section", the
-# "host section" and the "rules section". The generics section defines
-# defaults which you should not change. Changes should solely be made to
-# the rules section.
-#
-# You will need to select several parameters befitting your compiler/system:
-#
-# -DHAS_BOOL - set, if your C++ compiler knows about the 'bool' type.
-# -DHAS_PSIGNAL - set, if your libc supports psignal(int,const char*).
-# -fno-exceptions - may not be recognized by all variants of g++
-# -ffor-scope - the new ANSI C++ scoping of for() variables is used...
-#
-# === [1] ==================================================== generics section
-#
-CXX = g++ -ffor-scope -DHAS_BOOL -DHAS_PSIGNAL
-CC = gcc
-LD = $(CC) # yes, I do mean gcc and not g++
-CXXFLAGS = # -pg -g # -fprofile-arcs -ftest-coverage
-SYSTEM = $(shell uname -s | tr '[a-z]' '[A-Z]' | tr -d '_ -/')
-CPU = $(shell uname -p)
-VERSION = $(shell uname -r)
-HOST = $(shell uname -n)
-MAJOR = $(firstword $(subst ., ,$(VERSION)))
-MINOR = $(strip $(word 2,$(subst ., ,$(VERSION))))
-LOADLIBES =
-SOCKLEN = int # default except for glibc2?
-
-# optimization levels - Do *not* use levels above -O1 with g++,
-# if -fprofile-arcs or -ftest-coverage is selected! Set to different
-# values in the host specific section below.
-#
-# - OPT_NORM for normal level optimization, O2 is a good choice.
-#
-OPT_NORM = -O2
-
-# electric fence library, for test purposes only (helps w/ memory leaks)
-# (developers only)
-EFENCE = -L/usr/local/lib -lefence
-
-#
-# === [2] ======================================================= hosts section
-#
-
-ifeq (SUNOS,${SYSTEM})
-ifeq (5,${MAJOR})
-# use these for the SUN CC compiler (for STL, see below or above)
-# You must define this for Solaris 2.x: CXXFLAGS = -DSOLARIS
-CC = cc
-#CXX = CC -DHAS_BOOL -DHAS_PSIGNAL -DHAS_MUTABLE
-#CXXFLAGS = -DSOLARIS '-library=%none,Cstd,Crun'
-#CXXFLAGS += -dalign -ftrap=%none -fsimple -xlibmil
-#OPT_NORM = -xtarget=ultra2 -xO4
-#EXTRALIB += -lnsl -lsocket
-#LD = CC
-#
-## g++ settings for Solaris on Ultra Sparcs (comment out all of above):
-CXXFLAGS += -DSOLARIS # -ggdb
-OPT_NORM = -O2 # -mcpu=supersparc
-LD = $(CC)
-##
-#EXTRALIB += -lnsl -lsocket -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic
-else
-# old SunOS 4.1.x, not supported!
-CXXFLAGS += -DSUN
-endif
-endif
-
-ifeq (IRIX64,${SYSTEM})
-# The regular 64bit Irix stuff is just too slow, use n32!
-SYSTEM := IRIX
-endif
-
-ifeq (FREEBSD,${SYSTEM})
-SOCKLEN = socklen_t
-endif
-
-ifeq (IRIX,${SYSTEM})
-CXX = CC -n32 -mips3 -r4000 -DEFAULT:abi=n32:isa=mips3:proc=r4k
-CXX += -LANG:ansi-for-init-scope=on -LANG:bool=on
-CXX += -LANG:exceptions=off -LANG:explicit=off -LANG:wchar_t=off
-CXX += -LANG:mutable=on -LANG:namespaces=on -LANG:std
-CC = cc -n32 -mips3 -r4000
-CXXFLAGS = -woff 1174 -LANG:exceptions=off -DHAS_BOOL -DHAS_PSIGNAL
-LD = $(CXX)
-OPT_NORM = -O3 -IPA -LNO:opt=1
-# for g++
-#CXXFLAGS += -mips3 -mcpu=r4000
-endif
-
-ifeq (AIX,${SYSTEM})
-ifeq (,${MINOR})
-MINOR := ${MAJOR}
-MAJOR = 4
-endif
-CXX = xlC -UHAS_BOOL -UHAS_PSIGNAL
-CC = xlc
-CXXFLAGS = -qtune=pwr # -qdbxextra -g
-#CXX = g++ -ffor-scope -DHAS_BOOL -UHAS_PSIGNAL
-SOCKLEN = size_t
-LD = $(CXX)
-endif
-
-ifeq (LINUX,${SYSTEM})
-# determine highest version of all installed libc's.
-LIBCVER = $(shell /bin/ls /lib/libc.so.? | \
- awk -F'.' '{ if (m<$$3) m=$$3;} END { print m} ')
-ifeq (6,${LIBCVER})
-SOCKLEN = socklen_t
-endif
-CXXFLAGS += -DHAS_PSIGNAL -DLIBCVERSION=$(LIBCVER) -pipe # -Wall -pedantic
-OPT_NORM = -O2
-# if your g++ balks (e.g. SuSE still uses 2.7.2.3)
-#CXXFLAGS += -DHAS_PSIGNAL -DLIBCVERSION=$(LIBCVER) -m486
-LD = $(CC)
-EXTRALIB = -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic
-endif
-
-#
-# === [3] ======================================================= rules section
-# There is no need to change things below this line.
-CXXFLAGS += -D${SYSTEM} -DMAJOR=${MAJOR} -DMINOR=${MINOR} -DSOCKLEN=${SOCKLEN}
-CFLAGS = $(CXXFLAGS)
-LDFLAGS += $(OPT_NORM)
-
-%.o:%.cc
- $(CXX) $(CXXFLAGS) $(OPT_NORM) -c $< -o $@
-
-OBJS = convert.o socket.o signal.o squid-tlv.o copyout.o conffile.o
-SRCS = $(OBJS:.o=.cc)
-HDRS = $(OBJS:.o=.hh)
-FILES = $(SRCS) $(HDRS) Makefile purge.cc hexd.c
-DIST = $(addprefix purge/,$(FILES) README)
-
-all: purge
-
-purge: $(OBJS) purge.o
- $(LD) $(OPT_NORM) $(LDFLAGS) $^ -o $@ $(LOADLIBES) $(EXTRALIB)
-hexd: hexd.o
- $(CC) $(OPT_NORM) $(LDFLAGS) $^ -o $@ $(LOADLIBES)
-#
-# object file rules, generated with "g++ -MM -E *.cc"
-#
-purge.o: purge.cc $(HDRS)
- $(CXX) $(CXXFLAGS) $(OPT_NORM) -c $< -o $@
-convert.o: convert.cc convert.hh
-conffile.o: conffile.cc conffile.hh
-signal.o: signal.cc signal.hh
-socket.o: socket.cc socket.hh convert.hh
-squid-tlv.o: squid-tlv.cc squid-tlv.hh
-copyout.o: copyout.cc copyout.hh
-hexd.o: hexd.c
-
-clean:
- $(RM) *.o
- if [ "${SYSTEM}" = "IRIX" ]; then rm -rf ii_files; fi
- if [ "${SYSTEM}" = "SUNOS" ]; then rm -rf Templates.DB; fi
- if [ "${SYSTEM}" = "SUNOS" ]; then rm -rf SunWS_cache; fi
-
-distclean: clean
- $(RM) purge hexd
-
-realclean: distclean
-clobber: distclean
-
-co-all: $(FILES)
- echo all checked out
-co-all-lock:
- co -l $(FILES)
-ci-all:
- for i in $(FILES); do \
- test -w $$i && ci $$i; \
- rm -f $$i; \
- done
-
-dist: distclean co-all
- ( cd .. ; gtar cvzf purge-`date +"%Y%m%d"`-src.tar.gz $(DIST) )
-tar: distclean ci-all
- ( cd .. ; gtar cvzf purge-`date +"%Y%m%d"`-all.tar.gz purge )
--- /dev/null
+include $(top_srcdir)/src/Common.am
+
+bin_PROGRAMS = purge
+
+purge_SOURCES = \
+ convert.cc \
+ convert.hh \
+ socket.cc \
+ socket.hh \
+ signal.cc \
+ signal.hh \
+ squid-tlv.cc \
+ squid-tlv.hh \
+ copyout.cc \
+ copyout.hh \
+ conffile.cc \
+ conffile.hh \
+ purge.cc
+
+purge_LDADD = \
+ $(COMPAT_LIB) \
+ $(XTRA_LIBS)
+
+EXTRA_DIST = README
/cache1/00/00/000000B7 0 406 7CFCB1D319F158ADC9CFD991BB8F6DCE 397d449b 39bf677b ffffffff 3820abfc 0460 1 http://www.netscape.com/images/nc_vera_tile.gif
-hexd
-====
-
-The hexd tool let's you conveniently hex dump a file both, in hex char and
-display char columns. Hexd only assumes that characters 0-31,127-159,255
-are not printable.
-
-
-$ ./hexd /cache1/00/00/000000B7 | less -r
-
-00000000: 03 00 00 00 6D 03 00 00-00 10 7C FC B1 D3 19 F1 ....m.....|???.?
-00000010: 58 AD C9 CF D9 91 BB 8F-6D CE 05 00 00 00 18 39 X????.?.m?.....9
-00000020: 7D 44 9B 39 BF 67 7B FF-FF FF FF 38 20 AB FC 00 }D.9?g{....8 ??.
-00000030: 00 00 00 00 01 04 60 04-00 00 00 30 68 74 74 70 ......`....0http
-00000040: 3A 2F 2F 77 77 77 2E 6E-65 74 73 63 61 70 65 2E ://www.netscape.
-00000050: 63 6F 6D 2F 69 6D 61 67-65 73 2F 6E 63 5F 76 65 com/images/nc_ve
-00000060: 72 61 5F 74 69 6C 65 2E-67 69 66 00 08 48 54 54 ra_tile.gif..HTT
-00000070: 50 2F 31 2E 30 20 32 30-30 20 4F 4B 0D 0A 53 65 P/1.0 200 OK..Se
-00000080: 72 76 65 72 3A 20 4E 65-74 73 63 61 70 65 2D 45 rver: Netscape-E
-00000090: 6E 74 65 72 70 72 69 73-65 2F 33 2E 36 0D 0A 44 nterprise/3.6..D
-000000A0: 61 74 65 3A 20 54 75 65-2C 20 32 35 20 4A 75 6C ate: Tue, 25 Jul
-000000B0: 20 32 30 30 30 20 30 37-3A 34 31 3A 31 35 20 47 2000 07:41:15 G
-000000C0: 4D 54 0D 0A 43 6F 6E 74-65 6E 74 2D 54 79 70 65 MT..Content-Type
-000000D0: 3A 20 69 6D 61 67 65 2F-67 69 66 0D 0A 4C 61 73 : image/gif..Las
-000000E0: 74 2D 4D 6F 64 69 66 69-65 64 3A 20 57 65 64 2C t-Modified: Wed,
-000000F0: 20 30 33 20 4E 6F 76 20-31 39 39 39 20 32 31 3A 03 Nov 1999 21:
-00000100: 34 31 3A 31 36 20 47 4D-54 0D 0A 43 6F 6E 74 65 41:16 GMT..Conte
-00000110: 6E 74 2D 4C 65 6E 67 74-68 3A 20 36 37 0D 0A 41 nt-Length: 67..A
-00000120: 63 63 65 70 74 2D 52 61-6E 67 65 73 3A 20 62 79 ccept-Ranges: by
-00000130: 74 65 73 0D 0A 41 67 65-3A 20 31 38 32 37 31 33 tes..Age: 182713
-00000140: 0D 0A 58 2D 43 61 63 68-65 3A 20 48 49 54 20 66 ..X-Cache: HIT f
-00000150: 72 6F 6D 20 63 73 2D 68-61 6E 34 2E 77 69 6E 2D rom cs-han4.win-
-00000160: 69 70 2E 64 66 6E 2E 64-65 0D 0A 58 2D 43 61 63 ip.dfn.de..X-Cac
-00000170: 68 65 2D 4C 6F 6F 6B 75-70 3A 20 48 49 54 20 66 he-Lookup: HIT f
-00000180: 72 6F 6D 20 63 73 2D 68-61 6E 34 2E 77 69 6E 2D rom cs-han4.win-
-00000190: 69 70 2E 64 66 6E 2E 64-65 3A 38 30 38 31 0D 0A ip.dfn.de:8081..
-000001A0: 50 72 6F 78 79 2D 43 6F-6E 6E 65 63 74 69 6F 6E Proxy-Connection
-000001B0: 3A 20 6B 65 65 70 2D 61-6C 69 76 65 0D 0A 0D 0A : keep-alive....
-000001C0: 47 49 46 38 39 61 01 00-26 00 A2 00 00 00 00 00 GIF89a..&.?.....
-000001D0: FF FF FF 00 33 66 33 66-99 FF FF FF 00 00 00 00 ....3f3f........
-000001E0: 00 00 00 00 00 21 F9 04-01 00 00 04 00 2C 00 00 .....!?......,..
-000001F0: 00 00 01 00 26 00 00 03-08 38 A2 BC DE F0 C9 A8 ....&....8??????
-00000200: 12 00 3B ..;
-
-
-
limitations
===========
// match, please record
memset( &cd, 0, sizeof(cd) );
if ( debug ) fprintf( debug, "# match from %d-%d on line %s",
- subs[0].rm_so, subs[0].rm_eo, line );
+ (int)subs[0].rm_so, (int)subs[0].rm_eo,
+ line );
// terminate line after matched expression
line[ subs[0].rm_eo ] = '\0';
// new version, disk type at position 2
line[ subs[offset].rm_eo ] = '\0';
if ( debug ) fprintf( debug, "# match from %d-%d on \"%s\"\n",
- subs[offset].rm_so, subs[offset].rm_eo,
+ (int)subs[offset].rm_so,
+ (int)subs[offset].rm_eo,
line+subs[offset].rm_so );
if ( strcmp( line + subs[offset].rm_so, "ufs" ) == 0 )
cd.type = CacheDir::CDT_UFS;
// extract base directory
line[ subs[offset].rm_eo ] = '\0';
if ( debug ) fprintf( debug, "# match from %d-%d on \"%s\"\n",
- subs[offset].rm_so, subs[offset].rm_eo,
+ (int)subs[offset].rm_so,
+ (int)subs[offset].rm_eo,
line+subs[offset].rm_so );
cd.base = strdup( line+subs[offset].rm_so );
offset++;
// extract size information
line[ subs[offset].rm_eo ] = '\0';
if ( debug ) fprintf( debug, "# match from %d-%d on \"%s\"\n",
- subs[offset].rm_so, subs[offset].rm_eo,
+ (int)subs[offset].rm_so,
+ (int)subs[offset].rm_eo,
line+subs[offset].rm_so );
cd.size = strtoul( line+subs[offset].rm_so, 0, 10 );
offset++;
// extract 1st level directories
line[ subs[offset].rm_eo ] = '\0';
if ( debug ) fprintf( debug, "# match from %d-%d on \"%s\"\n",
- subs[offset].rm_so, subs[offset].rm_eo,
+ (int)subs[offset].rm_so,
+ (int)subs[offset].rm_eo,
line+subs[offset].rm_so );
cd.level[0] = strtoul( line+subs[offset].rm_so, 0, 10 );
offset++;
// extract 2nd level directories
line[ subs[offset].rm_eo ] = '\0';
if ( debug ) fprintf( debug, "# match from %d-%d on \"%s\"\n",
- subs[offset].rm_so, subs[offset].rm_eo,
+ (int)subs[offset].rm_so,
+ (int)subs[offset].rm_eo,
line+subs[offset].rm_so );
cd.level[1] = strtoul( line+subs[offset].rm_so, 0, 10 );
offset++;
#ifndef _CONFFILE_HH
#define _CONFFILE_HH
+#if !defined(__cplusplus)
#if defined(__GNUC__) || defined(__GNUG__)
#pragma interface
#else
-#ifndef HAS_BOOL
-#define HAS_BOOL
+#ifndef HAVE_BOOL
+#define HAVE_BOOL
typedef int bool;
#define false 0
#define true 1
#endif
#endif
+#endif /* __cplusplus */
#ifndef DEFAULT_SQUID_CONF
#define SA struct sockaddr
#endif
-static const char* RCS_ID =
- "$Id$";
-
const char*
my_inet_ntoa( const struct in_addr& a, HostAddress output )
// purpose: thread-safely convert IPv4 address -> ASCII representation
// Refer to errno in case of error (usually unconnected fd...)
{
struct sockaddr_in socket;
- SOCKLEN len = sizeof(socket);
+ socklen_t len = sizeof(socket);
if ( (peer ? getpeername( fd, (SA*) &socket, &len ) :
getsockname( fd, (SA*) &socket, &len )) == -1 )
#ifndef _CONVERT_HH
#define _CONVERT_HH
+#if !defined(__cplusplus)
#if defined(__GNUC__) || defined(__GNUG__)
#pragma interface
#else
-#ifndef HAS_BOOL
-#define HAS_BOOL
-typedef int bool;
+#ifndef HAVE_BOOL
+#define HAVE_BOOL 1
+typedef char bool;
#define false 0
#define true 1
#endif
#endif
+#endif /* __cplusplus */
#include <sys/types.h>
#include <sys/socket.h>
#pragma implementation
#endif
-#include <assert.h>
-#include <sys/types.h>
+#include "config.h"
+#include "copyout.hh"
+
+//#include <assert.h>
+//#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
-
#include <sys/mman.h>
+
#ifndef MAP_FILE
#define MAP_FILE 0
#endif // MAP_FILE
-#include "copyout.hh"
-
-static const char* RCS_ID =
- "$Id$";
-
int
assert_copydir( const char* copydir )
// purpose: check, if copydir is a directory and that we can write into it.
static const char* index = "index.html";
// find hostname part after the scheme (okok, not counting port, etc.)
- char* ptr = strstr( url, "://" );
+ const char* ptr = strstr( url, "://" );
if ( ptr == 0 || strlen(ptr) < 4 ) return false;
// create filename to store contents into
// seek end of output file ...
off_t position = lseek( out, filesize-metasize-1, SEEK_SET );
if ( position == -1 ) {
- fprintf( stderr, "lseek(%s,%lu): %s\n", filename, filesize-metasize,
+ fprintf( stderr, "lseek(%s,%lu): %s\n", filename,
+ (unsigned long)filesize-metasize,
strerror(errno) );
BAUTZ(false);
} else if ( debug & 0x02 ) {
fprintf( stderr, "# filesize=%lu, metasize=%lu, filepos=%ld\n",
- filesize, metasize, position );
+ (unsigned long)filesize, (unsigned long)metasize,
+ (long)position );
}
// ...and write 1 byte there (create a file that length)
#ifndef _COPYOUT_HH
#define _COPYOUT_HH
+#if !defined(__cplusplus)
#if defined(__GNUC__) || defined(__GNUG__)
#pragma interface
#else
-#ifndef HAS_BOOL
-#define HAS_BOOL
+#ifndef HAVE_BOOL
+#define HAVE_BOOL
typedef int bool;
#define false 0
#define true 1
#endif
#endif
+#endif /* __cplusplus */
int
assert_copydir( const char* copydir );
+++ /dev/null
-#include <ctype.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-
-unsigned char
-xlate( unsigned char ch )
-{
- return (isprint(ch & 0x7f) ? ch : '.');
-}
-
-typedef struct {
- int fd, rsize, cursor;
- size_t bufsize;
- unsigned char* buffer;
-} InputByByte;
-
-int
-in_open( InputByByte* this, const char* fn, size_t size )
-{
- if ( (this->fd = open( fn, O_RDONLY )) == -1 ) return -1;
- if ( (this->buffer=(unsigned char*) malloc(size)) == 0 ) {
- close(this->fd);
- return -1;
- }
- this->bufsize = size;
- this->rsize = this->cursor = 0;
- return 0;
-}
-
-int
-in_get( InputByByte* this )
-/*
- * purpose: read next character
- * returns: 0..255 as valid character, -1 for error, -2 for EOF
- */
-{
- if ( this->cursor >= this->rsize ) {
- do {
- this->rsize = read( this->fd, this->buffer, this->bufsize );
- } while ( this->rsize == -1 && errno == EINTR );
- if ( this->rsize > 0 ) this->cursor = 0;
- else return ((-2) - this->rsize);
- }
-
- return this->buffer[this->cursor++];
-}
-
-int
-in_close( InputByByte* this )
-{
- free((void*) this->buffer);
- return close(this->fd);
-}
-
-int
-main( int argc, char* argv[] )
-{
- int ch, i;
- unsigned line = 0;
- InputByByte in;
- char b2[20];
-
- if ( argc != 2 ) {
- fprintf( stderr, "Usage: %s filename\n", argv[0] );
- return 1;
- }
-
- if ( in_open(&in,argv[1],32768) == -1 ) {
- perror( "open" );
- return 1;
- }
-
- for ( ch = in_get(&in); ch >= 0; ) {
- printf( "%08X: ", line );
- memset( b2, 0, sizeof(b2) );
- for ( i=0; i < 16 && ch >= 0; i++ ) {
- printf( "%02X%c", ch, ((i==7) ? '-' : ' ' ) );
- b2[i] = xlate(ch);
- ch = in_get(&in);
- }
- line += i;
- for ( ; i<16; i++ ) fputs(" ",stdout);
- printf( " %s\n", b2 );
- }
-
- return in_close(&in);
-}
-
-
//
#if defined(__GNUC__) || defined(__GNUG__)
#pragma implementation
-#else
-#ifndef HAS_BOOL
-#define HAS_BOOL
-typedef int bool;
-#define false 0
-#define true 1
-#endif
#endif
-#include <assert.h>
+#include "config.h"
+// for xstrdup
+#include "util.h"
+
+//#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <dirent.h>
-#include <ctype.h>
+//#include <ctype.h>
#include <string.h>
-#include <sys/types.h>
+//#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
-#if defined(HAS_PSIGNAL) && !defined(LINUX) && !defined(FREEBSD)
+#if HAVE_SIGINFO_H
#include <siginfo.h>
-#endif // HAS_PSIGNAL
+#endif
#include <netinet/in.h>
#include <netinet/tcp.h> // TCP_NODELAY
#include <arpa/inet.h>
#include <netdb.h> // gethostbyname()
-#include <regex.h>
+//#include <regex.h> //comes via compat.h
#include "convert.hh"
#include "socket.hh"
char* linebuffer = 0;
size_t buffersize = 16834;
static char* copydir = 0;
-static unsigned debug = 0;
+static unsigned debugFlag = 0;
static unsigned purgeMode = 0;
static bool iamalive = false;
static bool reminder = false;
static bool envelope = false;
static bool no_fork = false;
static const char* programname = 0;
-static const char* RCS_ID =
- "$Id$";
+static const char* RCS_ID = "$Id$";
// ----------------------------------------------------------------------
};
REList::REList( const char* what, bool doCase )
- :next(0),data(strdup(what))
+ :next(0),data(xstrdup(what))
{
int result = regcomp( &rexp, what,
REG_EXTENDED | REG_NOSUB | (doCase ? 0 : REG_ICASE) );
REList::~REList()
{
if ( next ) delete next;
- if ( data ) free((void*) data);
+ if ( data ) xfree((void*) data);
regfree(&rexp);
}
}
md5[32] = '\0'; // terminate string
} else {
- sprintf( md5, "%-32s", "(no_md5_data_available)" );
+ snprintf( md5, sizeof(md5), "%-32s", "(no_md5_data_available)" );
}
char timeb[64];
StoreMetaStd temp;
// make data aligned, avoid SIGBUS on RISC machines (ARGH!)
memcpy( &temp, findings->data, sizeof(StoreMetaStd) );
- sprintf( timeb, "%08x %08x %08x %08x %04x %5hu ",
- temp.timestamp, temp.lastref,
- temp.expires, temp.lastmod, temp.flags, temp.refcount );
+ snprintf( timeb, sizeof(timeb), "%08lx %08lx %08lx %08lx %04x %5hu ",
+ (unsigned long)temp.timestamp, (unsigned long)temp.lastref,
+ (unsigned long)temp.expires, (unsigned long)temp.lastmod, temp.flags, temp.refcount );
} else if ( meta && (findings = meta->search( STORE_META_STD_LFS )) ) {
StoreMetaStdLFS temp;
// make data aligned, avoid SIGBUS on RISC machines (ARGH!)
memcpy( &temp, findings->data, sizeof(StoreMetaStd) );
- sprintf( timeb, "%08x %08x %08x %08x %04x %5hu ",
- temp.timestamp, temp.lastref,
- temp.expires, temp.lastmod, temp.flags, temp.refcount );
+ snprintf( timeb, sizeof(timeb), "%08lx %08lx %08lx %08lx %04x %5hu ",
+ (unsigned long)temp.timestamp, (unsigned long)temp.lastref,
+ (unsigned long)temp.expires, (unsigned long)temp.lastmod, temp.flags, temp.refcount );
} else {
- sprintf( timeb, "%08x %08x %08x %08x %04x %5hu ", -1, -1, -1, -1, 0, 0 );
+ snprintf( timeb, sizeof(timeb), "%08lx %08lx %08lx %08lx %04x %5hu ", (unsigned long)-1, (unsigned long)-1, (unsigned long)-1, (unsigned long)-1, 0, 0 );
}
// make sure that there is just one printf()
// if we want to copy out the file, do that first of all.
if ( ::copydir && *copydir && size > 0 )
- copy_out( st.st_size, metasize, ::debug,
+ copy_out( st.st_size, metasize, ::debugFlag,
fn, url, ::copydir, ::envelope );
// do we need to PURGE the file, yes, if purgemode bit#0 was set.
unsigned long bufsize = strlen(url) + strlen(schablone) + 4;
char* buffer = new char[bufsize];
- sprintf( buffer, schablone, url );
+ snprintf( buffer, bufsize, schablone, url );
int sockfd = connectTo( serverHost, serverPort, true );
if ( sockfd == -1 ) {
fprintf( stderr, "unable to connect to server: %s\n", strerror(errno) );
static const size_t addon = sizeof(unsigned char) + sizeof(unsigned int);
bool flag = true;
- if ( debug & 0x01 ) fprintf( stderr, "# [3] %s\n", fn );
+ if ( debugFlag & 0x01 ) fprintf( stderr, "# [3] %s\n", fn );
int fd = open( fn, O_RDONLY );
if ( fd != -1 ) {
if ( read(fd,::linebuffer,::buffersize-1) > 60 ) {
// returns: true, if every subdir && action was successful.
{
struct dirent* entry;
- if ( debug & 0x01 )
+ if ( debugFlag & 0x01 )
fprintf( stderr, "# [2] %s\n", directory );
DIR* dir = opendir( directory );
// warning: this function is once-recursive, no deeper.
{
struct dirent* entry;
- if ( debug & 0x01 )
+ if ( debugFlag & 0x01 )
fprintf( stderr, "# [%d] %s\n", (level ? 1 : 0), dirname );
DIR* dir = opendir( dirname );
break;
case 'C':
if ( optarg && *optarg ) {
- if ( copydir ) free( (void*) copydir );
- assert( (copydir = strdup(optarg)) );
+ if ( copydir ) xfree( (void*) copydir );
+ assert( (copydir = xstrdup(optarg)) );
}
break;
case 'c':
if ( optarg && *optarg ) {
- if ( *conffile ) free((void*) conffile );
- assert( (conffile = strdup(optarg)) );
+ if ( *conffile ) xfree((void*) conffile );
+ assert( (conffile = xstrdup(optarg)) );
}
break;
case 'd':
- ::debug = strtoul( optarg, 0, 0 );
+ ::debugFlag = strtoul( optarg, 0, 0 );
break;
case 'E':
}
// adjust
- if ( ! isatty(fileno(stdout)) || (::debug & 0x01) ) ::iamalive = false;
+ if ( ! isatty(fileno(stdout)) || (::debugFlag & 0x01) ) ::iamalive = false;
if ( head == 0 ) {
fputs( "There was no regular expression defined. If you intend\n", stderr );
fputs( "to match all possible URLs, use \"-e .\" instead.\n", stderr );
printf( "#\n# Currently active values for %s:\n# %s\n",
::programname, ::RCS_ID );
printf( "# Debug level : " );
- if ( ::debug ) printf( "%#6.4hx", ::debug );
+ if ( ::debugFlag ) printf( "%#6.4hx", ::debugFlag );
else printf( "production level" ); // printf omits 0x prefix for 0!
printf( " + %s mode", ::no_fork ? "linear" : "parallel" );
puts( ::verbose ? " + extra verbosity" : "" );
{
// setup variables
REList* list = 0;
- char* conffile = strdup( DEFAULT_SQUID_CONF );
+ char* conffile = xstrdup( DEFAULT_SQUID_CONF );
serverPort = htons(DEFAULTPORT);
if ( convertHostname(DEFAULTHOST,serverHost) == -1 ) {
fprintf( stderr, "unable to resolve host %s!\n", DEFAULTHOST );
// try to read squid.conf file to determine all cache_dir locations
CacheDirVector cdv(0);
- if ( readConfigFile( cdv, conffile, debug ? stderr : 0 ) > 0 ) {
+ if ( readConfigFile( cdv, conffile, debugFlag ? stderr : 0 ) > 0 ) {
// there are some valid cache_dir entries.
// unless forking was forbidden by cmdline option,
// for a process for each cache_dir entry to remove files.
if ( ! dirlevel(i->base,list) )
fprintf( stderr, "program terminated due to error: %s",
strerror(errno) );
- free((void*) i->base);
+ xfree((void*) i->base);
}
} else {
// parallel mode, all cache_dir in parallel
::iamalive = false;
}
- for ( int i=0; i < cdv.size(); ++i ) {
+ for ( size_t i=0; i < cdv.size(); ++i ) {
if ( getpid() == getpgrp() ) {
// only parent == group leader may fork off new processes
if ( (child[i]=fork()) < 0 ) {
if ( ! dirlevel(cdv[i].base,list) )
fprintf( stderr, "program terminated due to error: %s\n",
strerror(errno) );
- free((void*) cdv[i].base);
+ xfree((void*) cdv[i].base);
return 0;
} else {
// parent mode
- if ( ::debug ) printf( "forked child %d\n", (int) child[i] );
+ if ( ::debugFlag ) printf( "forked child %d\n", (int) child[i] );
}
}
}
// collect the garbase
pid_t temp;
int status;
- for ( int i=0; i < cdv.size(); ++i ) {
+ for ( size_t i=0; i < cdv.size(); ++i ) {
while ( (temp=waitpid( (pid_t)-1, &status, 0 )) == -1 )
if ( errno == EINTR ) continue;
- if ( ::debug ) printf( "collected child %d\n", (int) temp );
+ if ( ::debugFlag ) printf( "collected child %d\n", (int) temp );
}
delete[] child;
}
}
// clean up
- if ( copydir ) free( (void*) copydir );
- free((void*) conffile);
+ if ( copydir ) xfree( (void*) copydir );
+ xfree((void*) conffile);
delete list;
return 0;
}
#pragma implementation
#endif
-#include <sys/types.h>
+#include "config.h"
+#include "signal.hh"
+
+//#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <memory.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
-#include <signal.h>
-
-#include "signal.hh"
-
-static const char* RCS_ID =
- "$Id$";
-
-#ifndef HAS_PSIGNAL
-#ifdef AIX
-extern const char* const sys_siglist[];
-#define _sys_nsig 64
-#define _sys_siglist sys_siglist
-#endif // AIX
-
-void
-psignal( int sig, const char* msg )
-// purpose: print message, colon, space, signal name and LF.
-// paramtr: sig (IN): signal number
-// msg (IN): message to prepend
-{
- if ( msg && *msg ) fprintf( stderr, "%s: ", msg );
- if ( sig > 0 && sig < _sys_nsig )
- fprintf( stderr, "%s\n", _sys_siglist[sig] );
- else
- fputs( "(unknown)\n", stderr );
-}
-#endif // !HAS_PSIGNAL
+//#include <signal.h>
SigFunc*
Signal( int signo, SigFunc* newhandler, bool doInterrupt )
{
pid_t pid;
int status = signo; // to stop GNU from complaining...
- char line[128];
int saveerr = errno;
while ( (pid = waitpid( -1, &status, WNOHANG )) > 0 ) {
if ( WIFEXITED(status) ) {
- sprintf( line, "child (pid=%ld) reaped, status %d\n%c",
+ fprintf( stderr, "child (pid=%ld) reaped, status %d\n%c",
(long) pid, WEXITSTATUS(status), 0 );
} else if ( WIFSIGNALED(status) ) {
- sprintf( line, "child (pid=%ld) died on signal %d%s\n%c",
+ fprintf( stderr, "child (pid=%ld) died on signal %d%s\n%c",
(long) pid, WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status) ? " (core generated)" : "",
#endif
0 );
} else {
- sprintf( line, "detected dead child (pid=%ld), status %d\n%c",
+ fprintf( stderr, "detected dead child (pid=%ld), status %d\n%c",
(long) pid, status, 0 );
}
- write( STDERR_FILENO, line, strlen(line) );
}
errno = saveerr;
// Initial revision
//
//
+
#ifndef _SIGNAL_HH
#define _SIGNAL_HH
+#include "config.h"
+
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#if !defined(__cplusplus)
#if defined(__GNUC__) || defined(__GNUG__)
#pragma interface
#else
-#ifndef HAS_BOOL
-#define HAS_BOOL
+#ifndef HAVE_BOOL
+#define HAVE_BOOL
typedef int bool;
#define false 0
#define true 1
#endif
#endif
+#endif /* __cplusplus */
#if 1 // so far, all systems I know use void
# define SIGRETTYPE void
typedef SIGRETTYPE SigFunc( SIGPARAM );
}
-#ifndef HAS_PSIGNAL
-void
-psignal( int sig, const char* msg );
- // purpose: print message, colon, space, signal name and LF.
- // paramtr: sig (IN): signal number
- // msg (IN): message to prepend
-#endif // ! HAS_PSIGNAL
-
SigFunc*
Signal( int signo, SigFunc* newhandler, bool doInterrupt );
// purpose: install reliable signals
#include "convert.hh"
-static const char* RCS_ID =
- "$Id$";
-
int
setSocketBuffers( int sockfd, int size )
// purpose: set socket buffers for both directions to the specified size
// -1, if an error occurred (e.g. datagram socket)
{
int delay = 0;
- SOCKLEN len = sizeof(delay);
+ socklen_t len = sizeof(delay);
if ( getsockopt( sockfd, IPPROTO_TCP, TCP_NODELAY,
(char*) &delay, &len ) == -1 ) {
perror( "# getsockopt( TCP_NODELAY ) failed" );
#ifndef _SOCKET_HH
#define _SOCKET_HH
+#if !defined(__cplusplus)
#if defined(__GNUC__) || defined(__GNUG__)
#pragma interface
#else
-#ifndef HAS_BOOL
-#define HAS_BOOL
+#ifndef HAVE_BOOL
+#define HAVE_BOOL
typedef int bool;
#define false 0
#define true 1
#endif
#endif
+#endif /* __cplusplus */
#include <sys/types.h>
#include <sys/socket.h> // SOMAXCONN
#pragma implementation
#endif
-#include <assert.h>
+#include "config.h"
+//#include <assert.h>
#include "squid-tlv.hh"
-static const char* RCS_ID =
- "$Id$";
-
SquidTLV::SquidTLV( SquidMetaType _type, size_t _size, void* _data )
:next(0),size(_size)
{
#ifndef _SQUID_TLV_HH
#define _SQUID_TLV_HH
+#if !defined(__cplusplus)
#if defined(__GNUC__) || defined(__GNUG__)
#pragma interface
#else
-#ifndef HAS_BOOL
-#define HAS_BOOL
+#ifndef HAVE_BOOL
+#define HAVE_BOOL
typedef int bool;
#define false 0
#define true 1
#endif
#endif
+#endif /* __cplusplus */
#include <sys/types.h>
#include <netinet/in.h>
STORE_META_VALID,
STORE_META_VARY_HEADERS, // Stores Vary request headers
STORE_META_STD_LFS, // standard metadata in lfs format
- STORE_META_OBJSIZE, // object size, if its known
+ STORE_META_OBJSIZE // object size, if its known
};
// taken from Squid-2.x
local host
.if !'po4a'hide' .B "] [ \-m"
method
+.if !'po4a'hide' .B "] [ \-n"
+.if !'po4a'hide' .B "] [ \-N"
.if !'po4a'hide' .B "] [ \-p"
port
.if !'po4a'hide' .B "] [ \-P"
.if !'po4a'hide' .fi
.
.if !'po4a'hide' .TP
+.if !'po4a'hide' .B "\-n"
+Proxy Negotiate(Kerberos) authentication.
+.if !'po4a'hide' .nf
+Use kinit username@DOMAIN first to get initial TGS.
+.
+.if !'po4a'hide' .TP
+.if !'po4a'hide' .B "\-N"
+WWW Negotiate(Kerberos) authentication.
+.if !'po4a'hide' .nf
+Use kinit username@DOMAIN first to get initial TGS.
+.
+.if !'po4a'hide' .TP
.if !'po4a'hide' .B "\-p port"
Port number of cache. Default is 3128.
.
#include <getopt.h>
#endif
+#if HAVE_GSSAPI
+#ifdef HAVE_HEIMDAL_KERBEROS
+#ifdef HAVE_GSSAPI_GSSAPI_H
+#include <gssapi/gssapi.h>
+#elif defined(HAVE_GSSAPI_H)
+#include <gssapi.h>
+#else
+#error "GSSAPI header required"
+#endif
+#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
+#else
+#ifdef HAVE_SEAM_KERBEROS
+#ifdef HAVE_GSSAPI_GSSAPI_H
+#include <gssapi/gssapi.h>
+#elif defined(HAVE_GSSAPI_H)
+#include <gssapi.h>
+#else
+#error "GSSAPI header required"
+#endif
+#ifdef HAVE_GSSAPI_GSSAPI_EXT_H
+#include <gssapi/gssapi_ext.h>
+#endif
+#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
+#else /*MIT */
+#ifdef HAVE_GSSAPI_GSSAPI_H
+#include <gssapi/gssapi.h>
+#elif defined(HAVE_GSSAPI_H)
+#include <gssapi.h>
+#else
+#error "GSSAPI header required"
+#endif
+#ifdef HAVE_GSSAPI_GSSAPI_KRB5_H
+#include <gssapi/gssapi_krb5.h>
+#endif
+#ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H
+#include <gssapi/gssapi_generic.h>
+#endif
+#endif
+#endif
+
+#ifndef gss_mech_spnego
+static gss_OID_desc _gss_mech_spnego = {6, (void *) "\x2b\x06\x01\x05\x05\x02"};
+gss_OID gss_mech_spnego = &_gss_mech_spnego;
+#endif
+#endif
#ifndef BUFSIZ
#define BUFSIZ 8192
static void set_our_signal(void);
static ssize_t myread(int fd, void *buf, size_t len);
static ssize_t mywrite(int fd, void *buf, size_t len);
+
+
+#if HAVE_GSSAPI
+static int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status, const char *function);
+static char *GSSAPI_token(const char *server);
+#endif
+
static int put_fd;
static char *put_file = NULL;
fprintf(stderr,
"Version: %s\n"
"Usage: %s [-arsv] [-g count] [-h remote host] [-H 'string'] [-i IMS] [-I ping-interval] [-j 'Host-header']"
- "[-k] [-l local-host] [-m method] [-p port] [-P file] [-t count] [-T timeout] [-u proxy-user] [-U www-user] "
+ "[-k] [-l local-host] [-m method] "
+#if HAVE_GSSAPI
+ "[-n] [-N] "
+#endif
+ "[-p port] [-P file] [-t count] [-T timeout] [-u proxy-user] [-U www-user] "
"[-V version] [-w proxy-password] [-W www-password] url\n"
"\n"
"Options:\n"
" -k Keep the connection active. Default is to do only one request then close.\n"
" -l host Specify a local IP address to bind to. Default is none.\n"
" -m method Request method, default is GET.\n"
+#if HAVE_GSSAPI
+ " -n Proxy Negotiate(Kerberos) authentication\n"
+ " -N WWW Negotiate(Kerberos) authentication\n"
+#endif
" -p port Port number of cache. Default is %d.\n"
" -P file PUT request. Using the named file\n"
" -r Force cache to reload URL.\n"
" -u user Proxy authentication username\n"
" -U user WWW authentication username\n"
" -v Verbose. Print outgoing message to stderr.\n"
- " -V version HTTP Version. Use '-' for HTTP/0.9 omitted case\n",
+ " -V version HTTP Version. Use '-' for HTTP/0.9 omitted case\n"
" -w password Proxy authentication password\n"
- " -W password WWW authentication password\n"
+ " -W password WWW authentication password\n",
VERSION, progname, CACHE_HTTP_PORT);
exit(1);
}
int keep_alive = 0;
int opt_noaccept = 0;
int opt_verbose = 0;
+ int www_neg, proxy_neg;
const char *hostname, *localhost;
Ip::Address iaddr;
char url[BUFSIZ], msg[MESSAGELEN], buf[BUFSIZ];
ping = 0;
pcount = 0;
ping_int = 1 * 1000;
+ www_neg = 0;
+ proxy_neg = 0;
if (argc < 2) {
usage(argv[0]); /* need URL */
if (url[0] == '-')
usage(argv[0]);
-
+#if HAVE_GSSAPI
+ while ((c = getopt(argc, argv, "ah:j:V:l:P:i:km:p:rsvt:g:p:I:H:T:u:U:w:W:nN?")) != -1)
+#else
while ((c = getopt(argc, argv, "ah:j:V:l:P:i:km:p:rsvt:g:p:I:H:T:u:U:w:W:?")) != -1)
+#endif
switch (c) {
case 'a':
www_password = optarg;
break;
+#if HAVE_GSSAPI
+ case 'n':
+ proxy_neg = 1;
+ break;
+
+ case 'N':
+ www_neg = 1;
+ break;
+#endif
case 'v':
/* undocumented: may increase verb-level by giving more -v's */
opt_verbose++;
snprintf(buf, BUFSIZ, "Authorization: Basic %s\r\n", base64_encode(buf));
strcat(msg, buf);
}
-
- /* HTTP/1.0 may need keep-alive */
- if (strcmp(version, "1.0") == 0) {
- if (keep_alive) {
- if (strchr(url, ':')) {
- snprintf(buf, BUFSIZ, "Proxy-Connection: keep-alive\r\n");
- strcat(msg, buf);
- } else
- strcat(msg, "Connection: keep-alive\r\n");
- }
+#if HAVE_GSSAPI
+ if (www_neg) {
+ if (host) {
+ snprintf(buf, BUFSIZ, "Authorization: Negotiate %s\r\n", GSSAPI_token(host));
+ strcat(msg, buf);
+ } else
+ fprintf(stderr, "ERROR: server host missing\n");
+ }
+ if (proxy_neg) {
+ if (hostname) {
+ snprintf(buf, BUFSIZ, "Proxy-Authorization: Negotiate %s\r\n", GSSAPI_token(hostname));
+ strcat(msg, buf);
+ } else
+ fprintf(stderr, "ERROR: proxy server host missing\n");
}
- /* HTTP/1.1 may need close */
+#endif
+
+ /* HTTP/1.0 may need keep-alive explicitly */
+ if (strcmp(version, "1.0") == 0 && keep_alive)
+ strcat(msg, "Connection: keep-alive\r\n");
+
+ /* HTTP/1.1 may need close explicitly */
if (!keep_alive)
strcat(msg, "Connection: close\r\n");
return send(fd, buf, len, 0);
#endif
}
+
+#if HAVE_GSSAPI
+/*
+ * Check return valuse major_status, minor_status for error and print error description
+ * in case of an error.
+ * Returns 1 in case of gssapi error
+ * 0 in case of no gssapi error
+ */
+#define BUFFER_SIZE 8192
+static int
+check_gss_err(OM_uint32 major_status, OM_uint32 minor_status, const char *function)
+{
+ if (GSS_ERROR(major_status)) {
+ OM_uint32 maj_stat, min_stat;
+ OM_uint32 msg_ctx = 0;
+ gss_buffer_desc status_string;
+ char buf[BUFFER_SIZE];
+ size_t len;
+
+ len = 0;
+ msg_ctx = 0;
+ while (!msg_ctx) {
+ /* convert major status code (GSS-API error) to text */
+ maj_stat = gss_display_status(&min_stat, major_status,
+ GSS_C_GSS_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx, &status_string);
+ if (maj_stat == GSS_S_COMPLETE) {
+ snprintf(buf + len, BUFFER_SIZE-len, "%s", (char *) status_string.value);
+ len += status_string.length;
+ gss_release_buffer(&min_stat, &status_string);
+ break;
+ }
+ gss_release_buffer(&min_stat, &status_string);
+ }
+ snprintf(buf + len, BUFFER_SIZE-len, "%s", ". ");
+ len += 2;
+ msg_ctx = 0;
+ while (!msg_ctx) {
+ /* convert minor status code (underlying routine error) to text */
+ maj_stat = gss_display_status(&min_stat, minor_status,
+ GSS_C_MECH_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx, &status_string);
+ if (maj_stat == GSS_S_COMPLETE) {
+ snprintf(buf + len, BUFFER_SIZE-len,"%s", (char *) status_string.value);
+ len += status_string.length;
+ gss_release_buffer(&min_stat, &status_string);
+ break;
+ }
+ gss_release_buffer(&min_stat, &status_string);
+ }
+ fprintf(stderr, "%s failed: %s\n", function, buf);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Get gssapi token for service HTTP/<server>
+ * User has to initiate a kinit user@DOMAIN on commandline first for the
+ * function to be successful
+ * Returns base64 encoded token if successful
+ * string "ERROR" if unsuccessful
+ */
+static char *
+GSSAPI_token(const char *server)
+{
+ OM_uint32 major_status, minor_status;
+ gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
+ gss_name_t server_name = GSS_C_NO_NAME;
+ gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+ char *token = NULL;
+
+ setbuf(stdout, NULL);
+ setbuf(stdin, NULL);
+
+ if (!server) {
+ fprintf(stderr, "Error: No server name\n");
+ return (char *)"ERROR";
+ }
+ service.value = xmalloc(strlen("HTTP") + strlen(server) + 2);
+ snprintf((char *) service.value, strlen("HTTP") + strlen(server) + 2, "%s@%s", "HTTP", server);
+ service.length = strlen((char *) service.value);
+
+ major_status = gss_import_name(&minor_status, &service,
+ gss_nt_service_name, &server_name);
+
+ if (!check_gss_err(major_status, minor_status, "gss_import_name()")) {
+
+ major_status = gss_init_sec_context(&minor_status,
+ GSS_C_NO_CREDENTIAL,
+ &gss_context,
+ server_name,
+ gss_mech_spnego,
+ 0,
+ 0,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &input_token,
+ NULL,
+ &output_token,
+ NULL,
+ NULL);
+
+ if (!check_gss_err(major_status, minor_status, "gss_init_sec_context()")) {
+
+ if (output_token.length)
+ token = (char *) base64_encode_bin((const char *) output_token.value, output_token.length);
+ }
+ }
+
+ if (!output_token.length)
+ token = (char *) "ERROR";
+ gss_delete_sec_context(&minor_status, &gss_context, NULL);
+ gss_release_buffer(&minor_status, &service);
+ gss_release_buffer(&minor_status, &input_token);
+ gss_release_buffer(&minor_status, &output_token);
+ gss_release_name(&minor_status, &server_name);
+
+ return token;
+}
+#endif