diff -Nur squid-3/acinclude/krb5.m4 squid-3-krb5/acinclude/krb5.m4
--- squid-3/acinclude/krb5.m4	2010-05-30 01:15:32.000000000 +0100
+++ squid-3-krb5/acinclude/krb5.m4	2010-05-30 15:13:58.000000000 +0100
@@ -104,23 +104,25 @@
 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)
 {
diff -Nur squid-3/configure.in squid-3-krb5/configure.in
--- squid-3/configure.in	2010-05-30 01:16:51.000000000 +0100
+++ squid-3-krb5/configure.in	2010-05-30 15:13:58.000000000 +0100
@@ -1792,6 +1792,7 @@
     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]),)
@@ -1877,6 +1878,9 @@
 		else
 			AC_MSG_NOTICE([external acl helper $helper ... found but cannot be built])
 		fi
+      if test "$helper" = "kerberos_ldap_group" ; then
+        squid_require_sasl=yes
+      fi
 	done
 fi
 AC_MSG_NOTICE([External acl helpers built: $EXTERNAL_ACL_HELPERS])
@@ -1987,6 +1991,16 @@
       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
 
@@ -2850,6 +2864,71 @@
 AC_SUBST(LDAPLIB)
 AC_SUBST(LBERLIB)
 
+AC_CHECK_HEADERS(ldap.h lber.h)
+
+dnl
+dnl Check for LDAP_OPT_DEBUG_LEVEL
+dnl
+AC_EGREP_CPP(YES_OPT_DEBUG_LEVEL,[#include <ldap.h>
+#ifdef LDAP_OPT_DEBUG_LEVEL
+YES_OPT_DEBUG_LEVEL
+#endif],ac_cv_ldap_opt_debug_level="yes",ac_cv_ldap_opt_debug_level="no")
+if test "x$ac_cv_lib_lber_main" != "xyes" -a "x$ac_cv_lib_lber___main" != "xyes" -a "x$ac_cv_ldap_opt_debug_level" = "xno" ; then
+  AC_DEFINE(HAVE_SUN_LDAP_SDK,1,[Define to 1 if you have Sun ldap sdk])
+fi
+
+dnl
+dnl Check for LDAP_REBINDPROC_CALLBACK
+dnl
+AC_EGREP_HEADER(LDAP_REBINDPROC_CALLBACK,ldap.h,AC_DEFINE(HAVE_LDAP_REBINDPROC_CALLBACK,1,[Define to 1 if you have LDAP_REBINDPROC_CALLBACK]))
+
+dnl
+dnl Check for LDAP_REBIND_PROC
+dnl
+AC_EGREP_HEADER(LDAP_REBIND_PROC,ldap.h,AC_DEFINE(HAVE_LDAP_REBIND_PROC,1,[Define to 1 if you have LDAP_REBIND_PROC]))
+
+dnl
+dnl Check for LDAP_REBIND_FUNCTION
+dnl
+AC_EGREP_CPP(LDAP_REBIND_FUNCTION,[#define LDAP_REFERRALS
+#include <ldap.h>],AC_DEFINE(HAVE_LDAP_REBIND_FUNCTION,1,[Define to 1 if you have LDAP_REBIND_FUNCTION]))
+
+dnl
+dnl Check for LDAP_OPT_X_TLS_CACERTFILE assume it is OpenLDAP
+dnl
+AC_EGREP_CPP(YES_OPT_X_TLS_CACERTFILE,[#include <ldap.h>
+#ifdef LDAP_OPT_X_TLS_CACERTFILE
+YES_OPT_X_TLS_CACERTFILE
+#endif],AC_DEFINE(HAVE_OPENLDAP,1,[Define to 1 if you have Openldap]), )
+
+dnl
+dnl Check for LDAP_SCOPE_DEFAULT
+dnl
+AC_EGREP_CPP(YES_SCOPE_DEFAULT,[#include <ldap.h>
+#ifdef LDAP_SCOPE_DEFAULT
+YES_SCOPE_DEFAULT
+#endif],AC_DEFINE(HAVE_LDAP_SCOPE_DEFAULT,1,[Define to 1 if you have LDAP_SCOPE_DEFAULT]))
+
+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]),)
+
 dnl Check for libdb
 dnl this is not fully functional if db.h is for a differend db version
 DBLIB=
@@ -3825,6 +3904,7 @@
 	helpers/negotiate_auth/mswin_sspi/Makefile \
 	helpers/external_acl/Makefile \
 	helpers/external_acl/ip_user/Makefile \
+	helpers/external_acl/kerberos_ldap_group/Makefile \
 	helpers/external_acl/ldap_group/Makefile \
 	helpers/external_acl/session/Makefile \
 	helpers/external_acl/unix_group/Makefile \
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/cert_tool squid-3-krb5/helpers/external_acl/kerberos_ldap_group/cert_tool
--- squid-3/helpers/external_acl/kerberos_ldap_group/cert_tool	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/cert_tool	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,83 @@
+#!/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
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/config.test squid-3-krb5/helpers/external_acl/kerberos_ldap_group/config.test
--- squid-3/helpers/external_acl/kerberos_ldap_group/config.test	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/config.test	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,7 @@
+#!/bin/sh
+# Don't build without gssapi.h
+if ( test -f /usr/include/gssapi/gssapi.h || test -f  /usr/include/gssapi.h ) &&
+   test -f /usr/include/ldap.h ; then
+       exit 0
+fi
+exit 1
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/COPYING squid-3-krb5/helpers/external_acl/kerberos_ldap_group/COPYING
--- squid-3/helpers/external_acl/kerberos_ldap_group/COPYING	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/COPYING	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/kerberos_ldap_group.cc squid-3-krb5/helpers/external_acl/kerberos_ldap_group/kerberos_ldap_group.cc
--- squid-3/helpers/external_acl/kerberos_ldap_group/kerberos_ldap_group.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/kerberos_ldap_group.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,384 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 <unistd.h>
+#include <ctype.h>
+
+#include "support.h"
+
+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->debug = 0;
+    margs->log = 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':
+	    margs.debug = 1;
+	    break;
+	case 'i':
+	    margs.log = 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:
+	    fprintf(stderr, "%s| %s: WARNING: unknown option: -%c.\n", LogTime(), PROGRAM, opt);
+	}
+    }
+
+    if (margs.debug)
+	fprintf(stderr, "%s| %s: INFO: Starting version %s\n", LogTime(), PROGRAM, KERBEROS_LDAP_GROUP_VERSION);
+    if (create_gd(&margs)) {
+	if (margs.debug)
+	    fprintf(stderr, "%s| %s: FATAL: Error in group list: %s\n", LogTime(), PROGRAM, margs.glist ? margs.glist : "NULL");
+	fprintf(stdout, "ERR\n");
+	clean_args(&margs);
+	exit(1);
+    }
+    if (create_nd(&margs)) {
+	if (margs.debug)
+	    fprintf(stderr, "%s| %s: FATAL: Error in netbios list: %s\n", LogTime(), PROGRAM, margs.nlist ? margs.nlist : "NULL");
+	fprintf(stdout, "ERR\n");
+	clean_args(&margs);
+	exit(1);
+    }
+    while (1) {
+	if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
+	    if (ferror(stdin)) {
+		if (margs.debug)
+		    fprintf(stderr, "%s| %s: FATAL: fgets() failed! dying..... errno=%d (%s)\n", LogTime(), PROGRAM, ferror(stdin),
+			strerror(ferror(stdin)));
+
+		fprintf(stdout, "ERR\n");
+		clean_args(&margs);
+		exit(1);	/* BIIG buffer */
+	    }
+	    fprintf(stdout, "ERR\n");
+	    clean_args(&margs);
+	    exit(0);
+	}
+	c = (char *) memchr(buf, '\n', sizeof(buf) - 1);
+	if (c) {
+	    *c = '\0';
+	    length = c - buf;
+	} else {
+	    fprintf(stdout, "ERR\n");
+	    if (margs.debug)
+		fprintf(stderr, "%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 (margs.debug || margs.log)
+		fprintf(stderr, "%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 (margs.debug || margs.log)
+		fprintf(stderr, "%s| %s: INFO: Got User: %s set default domain: %s\n", LogTime(), PROGRAM, user, domain);
+	}
+	if (margs.debug || margs.log)
+	    fprintf(stderr, "%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)) {
+	    fprintf(stdout, "OK\n");
+	    if (margs.debug)
+		fprintf(stderr, "%s| %s: OK\n", LogTime(), PROGRAM);
+	} else {
+	    fprintf(stdout, "ERR\n");
+	    if (margs.debug)
+		fprintf(stderr, "%s| %s: ERR\n", LogTime(), PROGRAM);
+	}
+    }
+
+
+}
+
+void
+strup(char *s)
+{
+    while (*s) {
+	*s = toupper((unsigned char) *s);
+	s++;
+    }
+}
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/Makefile.am squid-3-krb5/helpers/external_acl/kerberos_ldap_group/Makefile.am
--- squid-3/helpers/external_acl/kerberos_ldap_group/Makefile.am	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/Makefile.am	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,15 @@
+include $(top_srcdir)/src/Common.am
+
+EXTRA_DIST = README COPYING config.test
+SUBDIRS = 
+
+
+libexec_PROGRAMS = kerberos_ldap_group
+
+kerberos_ldap_group_SOURCES = kerberos_ldap_group.cc support_group.cc support_netbios.cc support_member.cc support_krb5.cc support_ldap.cc support_sasl.cc support_resolv.cc
+
+AM_CPPFLAGS = $(INCLUDES) -I$(srcdir)
+
+kerberos_ldap_group_LDFLAGS =
+kerberos_ldap_group_LDADD = $(COMPAT_LIB) $(LDAPLIB) $(LBERLIB) $(LIBSASL) $(XTRA_LIBS) $(KRB5LIBS)
+
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/README squid-3-krb5/helpers/external_acl/kerberos_ldap_group/README
--- squid-3/helpers/external_acl/kerberos_ldap_group/README	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/README	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,119 @@
+--------------------------------------------------------------------------------
+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
+
+
+
+
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/support_group.cc squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_group.cc
--- squid-3/helpers/external_acl/kerberos_ldap_group/support_group.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_group.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,440 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 "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';
+	if (margs->debug)
+	    fprintf(stderr, "%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 {
+	    if (margs->debug)
+		fprintf(stderr, "%s| %s: WARNING: Invalid Hex value %c\n", LogTime(), PROGRAM, ival);
+	    if (ul)
+		xfree(ul);
+	    return NULL;
+	}
+
+
+	if (n == a - 1) {
+	    if (margs->debug)
+		fprintf(stderr, "%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 {
+	    if (margs->debug)
+		fprintf(stderr, "%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';
+		if (margs->debug)
+		    fprintf(stderr, "%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';
+		if (margs->debug)
+		    fprintf(stderr, "%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';
+		if (margs->debug)
+		    fprintf(stderr, "%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';
+	    if (margs->debug)
+		fprintf(stderr, "%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) {
+	if (margs->debug) {
+	    fprintf(stderr, "%s| %s: INFO: iUTF2: %d iUTF3: %d iUTF4: %d\n", LogTime(), PROGRAM, iUTF2, iUTF3, iUTF4);
+	    fprintf(stderr, "%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;
+    if (margs->debug)
+	fprintf(stderr, "%s| %s: INFO: Group list %s\n", LogTime(), PROGRAM, p ? p : "NULL");
+    dp = NULL;
+
+    if (!p) {
+	if (margs->debug)
+	    fprintf(stderr, "%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 */
+		if (margs->debug)
+		    fprintf(stderr, "%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 */
+		if (margs->debug)
+		    fprintf(stderr, "%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 */
+	    if (margs->debug)
+		fprintf(stderr, "%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 */
+	if (margs->debug)
+	    fprintf(stderr, "%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;
+    }
+    if (margs->debug)
+	fprintf(stderr, "%s| %s: INFO: Group %s  Domain %s\n", LogTime(), PROGRAM, gdsp->group, gdsp->domain ? gdsp->domain : "NULL");
+
+    margs->groups = gdsp;
+    return (0);
+}
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/support.h squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support.h
--- squid-3/helpers/external_acl/kerberos_ldap_group/support.h	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support.h	2010-05-30 16:05:06.000000000 +0100
@@ -0,0 +1,180 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "config.h"
+#include "compat/getaddrinfo.h"
+#include "compat/getnameinfo.h"
+#include "util.h"
+
+#define KERBEROS_LDAP_GROUP_VERSION "1.2.2sq"
+
+#ifdef HAVE_HEIMDAL_KERBEROS
+#ifdef HAVE_GSSAPI_GSSAPI_H
+#include <gssapi/gssapi.h>
+#elif defined(HAVE_GSSAPI_H)
+#include <gssapi.h>
+#endif
+#ifdef HAVE_KRB5_H
+#include <krb5.h>
+#endif
+#ifdef HAVE_COM_ERR_H
+#include <com_err.h>
+#else
+#define error_message(code) krb5_get_err_text(kparam.context,code)
+#endif
+#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
+
+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 debug;
+    int log;
+    int AD;
+    int mdepth;
+    char *ddomain;
+    struct gdstruct *groups;
+    struct ndstruct *ndoms;
+};
+
+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);
+static 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"
+
+static 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;
+}
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/support_krb5.cc squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_krb5.cc
--- squid-3/helpers/external_acl/kerberos_ldap_group/support_krb5.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_krb5.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,353 @@
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * 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 <unistd.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+
+#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) {
+	fprintf(stderr, "%s| %s: ERROR: Error while initialising Kerberos library : %s\n", LogTime(), PROGRAM, error_message(code));
+	retval = 1;
+	goto cleanup;
+    }
+    /*
+     * getting default keytab name
+     */
+
+    if (margs->debug)
+	fprintf(stderr, "%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);
+    if (margs->debug)
+	fprintf(stderr, "%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) {
+	fprintf(stderr, "%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) {
+	fprintf(stderr, "%s| %s: ERROR: Error while starting keytab scan : %s\n", LogTime(), PROGRAM, error_message(code));
+	retval = 1;
+	goto cleanup;
+    }
+    if (margs->debug)
+	fprintf(stderr, "%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++]);
+	if (margs->debug)
+#ifdef HAVE_HEIMDAL_KERBEROS
+	    fprintf(stderr, "%s| %s: DEBUG: Keytab entry has realm name: %s\n", LogTime(), PROGRAM, entry.principal->realm);
+#else
+	    fprintf(stderr, "%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) {
+		fprintf(stderr, "%s| %s: ERROR: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code));
+	    } else {
+		if (margs->debug)
+		    fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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) {
+	fprintf(stderr, "%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) {
+	fprintf(stderr, "%s| %s: ERROR: Error while ending keytab scan : %s\n", LogTime(), PROGRAM, error_message(code));
+	retval = 1;
+	goto cleanup;
+    }
+    /*
+     * prepare memory credential cache
+     */
+#ifndef HAVE_KRB5_MEMORY_CACHE
+    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);
+    if (margs->debug)
+	fprintf(stderr, "%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) {
+	fprintf(stderr, "%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) {
+	if (margs->debug) {
+	    fprintf(stderr, "%s| %s: DEBUG: Did not find a principal in keytab for domain %s.\n", LogTime(), PROGRAM, domain);
+	    fprintf(stderr, "%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) {
+		if (margs->debug)
+		    fprintf(stderr, "%s| %s: DEBUG: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code));
+		goto loop_end;
+	    }
+	    if (margs->debug)
+		fprintf(stderr, "%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) {
+		if (margs->debug)
+		    fprintf(stderr, "%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) {
+		fprintf(stderr, "%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) {
+		if (margs->debug)
+		    fprintf(stderr, "%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) {
+		fprintf(stderr, "%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) {
+		if (margs->debug)
+		    fprintf(stderr, "%s| %s: DEBUG: Error while getting tgt : %s\n", LogTime(), PROGRAM, error_message(code));
+		goto loop_end;
+	    } else {
+		if (margs->debug)
+		    fprintf(stderr, "%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) {
+
+	if (margs->debug)
+	    fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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) {
+	    fprintf(stderr, "%s| %s: ERROR: Error while storing credentials : %s\n", LogTime(), PROGRAM, error_message(code));
+	    retval = 1;
+	    goto cleanup;
+	}
+	if (margs->debug)
+	    fprintf(stderr, "%s| %s: DEBUG: Stored credentials\n", LogTime(), PROGRAM);
+    } else {
+	if (margs->debug)
+	    fprintf(stderr, "%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);
+}
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/support_ldap.cc squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_ldap.cc
--- squid-3/helpers/external_acl/kerberos_ldap_group/support_ldap.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_ldap.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,1273 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "support.h"
+
+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);
+
+#ifdef HAVE_SUN_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;
+
+    if (margs->debug)
+	fprintf(stderr, "%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);
+	if (margs->debug)
+	    fprintf(stderr, "%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);
+	if (margs->debug)
+	    fprintf(stderr, "%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 {
+	if (margs->debug)
+	    fprintf(stderr, "%s| %s: DEBUG: Did not find ldap entry for subschemasubentry\n", LogTime(), PROGRAM);
+    }
+    if (margs->debug)
+	fprintf(stderr, "%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) {
+	if (margs->debug)
+	    fprintf(stderr, "%s| %s: DEBUG: Max search depth reached %d>%d\n", LogTime(), PROGRAM, depth, margs->mdepth);
+	return 0;
+    }
+    if (margs->debug)
+	fprintf(stderr, "%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) {
+	fprintf(stderr, "%s| %s: ERROR: Error searching ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+	ldap_unbind_s(ld);
+	return 0;
+    }
+    if (margs->debug)
+	fprintf(stderr, "%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 (margs->debug) {
+	    int n;
+	    fprintf(stderr, "%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 (margs->debug)
+		fprintf(stderr, "%s| %s: DEBUG: Entry %d \"%s\" matches group name \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
+	    break;
+	} else {
+	    if (margs->debug)
+		fprintf(stderr, "%s| %s: DEBUG: Entry %d \"%s\" does not match group name \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
+	}
+	/*
+	 * Do recursive group search
+	 */
+	if (margs->debug)
+	    fprintf(stderr, "%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 (margs->debug)
+		fprintf(stderr, "%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) {
+	if (margs->debug)
+	    fprintf(stderr, "%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) {
+	if (margs->debug)
+	    fprintf(stderr, "%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) {
+	if (margs->debug)
+	    fprintf(stderr, "%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) {
+	ssl_cacertfile = getenv("TLS_CACERTFILE");
+	free_path = 0;
+	if (!ssl_cacertfile) {
+	    ssl_cacertfile = xstrdup("/etc/ssl/certs/cert.pem");
+	    free_path = 1;
+	}
+	if (margs->debug)
+	    fprintf(stderr, "%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) {
+	    fprintf(stderr, "%s| %s: ERROR: Error while setting LDAP_OPT_X_TLS_CACERTFILE for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+	    return rc;
+	}
+    } else {
+	if (margs->debug)
+	    fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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");
+    }
+    if (margs->debug)
+	fprintf(stderr, "%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);
+	if (margs->debug)
+	    fprintf(stderr, "%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) {
+	fprintf(stderr, "%s| %s: ERROR: Error while setting SSL for ldap server: %s\n", LogTime(), PROGRAM, ldapssl_err2string(rc));
+	return rc;
+    }
+#else
+    fprintf(stderr, "%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)
+{
+/* Part of this work is 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>.
+ */
+
+    LDAPMessage *msg;
+    char **attr_value = NULL;
+    int max_attr = 0;
+
+    attr_value = *ret_value;
+    /*
+     * loop over attributes
+     */
+    if (margs->debug)
+	fprintf(stderr, "%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:
+	    if (margs->debug)
+		fprintf(stderr, "%s| %s: DEBUG: Received a search reference message\n", LogTime(), PROGRAM);
+	    break;
+	case LDAP_RES_SEARCH_RESULT:
+	    if (margs->debug)
+		fprintf(stderr, "%s| %s: DEBUG: Received a search result message\n", LogTime(), PROGRAM);
+	    break;
+	default:
+	    break;
+	}
+    }
+
+    if (margs->debug)
+	fprintf(stderr, "%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) {
+	fprintf(stderr, "%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) {
+	fprintf(stderr, "%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) {
+	fprintf(stderr, "%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
+	 */
+	if (margs->debug)
+	    fprintf(stderr, "%s| %s: DEBUG: Set SSL defaults\n", LogTime(), PROGRAM);
+	rc = ldap_set_ssl_defaults(margs);
+	if (rc != LDAP_SUCCESS) {
+	    fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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) {
+		fprintf(stderr, "%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) {
+		fprintf(stderr, "%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) {
+		fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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
+	fprintf(stderr, "%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) {
+	if (margs->debug)
+	    fprintf(stderr, "%s| %s: DEBUG: Setup Kerberos credential cache\n", LogTime(), PROGRAM);
+
+	kc = krb5_create_cache(margs, domain);
+	if (kc) {
+	    fprintf(stderr, "%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
+
+    if (margs->debug)
+	fprintf(stderr, "%s| %s: DEBUG: Initialise ldap connection\n", LogTime(), PROGRAM);
+
+
+    if (domain && !kc) {
+	if (margs->ssl) {
+	    if (margs->debug)
+		fprintf(stderr, "%s| %s: DEBUG: Enable SSL to ldap servers\n", LogTime(), PROGRAM);
+	}
+	if (margs->debug)
+	    fprintf(stderr, "%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;
+	    if (margs->debug)
+		fprintf(stderr, "%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)
+	    if (margs->debug)
+		fprintf(stderr, "%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) {
+		fprintf(stderr, "%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) {
+		if (margs->debug)
+		    fprintf(stderr, "%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;
+	    fprintf(stderr, "%s| %s: ERROR: SASL not supported on system\n", LogTime(), PROGRAM);
+	    continue;
+#endif
+	}
+	nhosts = free_hostname_list(&hlist, nhosts);
+	if (ld == NULL) {
+	    if (margs->debug)
+		fprintf(stderr, "%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) {
+	    if (margs->debug)
+		fprintf(stderr, "%s| %s: DEBUG: Enable SSL to ldap servers\n", LogTime(), PROGRAM);
+	}
+	if (margs->debug)
+	    fprintf(stderr, "%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
+	     */
+
+	    if (margs->debug)
+		fprintf(stderr, "%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) {
+		fprintf(stderr, "%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);
+	    if (margs->debug)
+		fprintf(stderr, "%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) {
+	if (margs->debug)
+	    fprintf(stderr, "%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) {
+	fprintf(stderr, "%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);
+
+    if (margs->debug)
+	fprintf(stderr, "%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) {
+	fprintf(stderr, "%s| %s: ERROR: Error searching ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+	ldap_unbind(ld);
+	ld = NULL;
+	retval = 0;
+	goto cleanup;
+    }
+    if (margs->debug)
+	fprintf(stderr, "%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 (margs->debug) {
+		int n;
+		fprintf(stderr, "%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 (margs->debug)
+		    fprintf(stderr, "%s| %s: DEBUG: Entry %d \"%s\" matches group name \"%s\"\n", LogTime(), PROGRAM, j + 1, av, group);
+		else
+		    break;
+	    } else {
+		if (margs->debug)
+		    fprintf(stderr, "%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 (margs->debug && max_attr > 0)
+		fprintf(stderr, "%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 (margs->debug)
+			fprintf(stderr, "%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
+	 */
+	if (margs->debug)
+	    fprintf(stderr, "%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);
+
+	if (margs->debug)
+	    fprintf(stderr, "%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 (margs->debug)
+	    fprintf(stderr, "%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);
+
+	    if (margs->debug)
+		fprintf(stderr, "%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;
+		    if (margs->debug)
+			fprintf(stderr, "%s| %s: DEBUG: \"%s\" matches group name \"%s\"\n", LogTime(), PROGRAM, av, group);
+		} else {
+		    if (margs->debug)
+			fprintf(stderr, "%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);
+
+	    if (margs->debug)
+		fprintf(stderr, "%s| %s: DEBUG: Users primary group %s %s\n", LogTime(), PROGRAM, retval ? "matches" : "does not match", group);
+
+	} else {
+	    if (margs->debug)
+		fprintf(stderr, "%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) {
+	fprintf(stderr, "%s| %s: ERROR: Error unbind ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
+    }
+    if (margs->debug)
+	fprintf(stderr, "%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);
+
+}
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/support_member.cc squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_member.cc
--- squid-3/helpers/external_acl/kerberos_ldap_group/support_member.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_member.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,126 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 "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) {
+	if (margs->debug)
+	    fprintf(stderr, "%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)) {
+	    if (margs->debug)
+		fprintf(stderr, "%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 (margs->debug || margs->log)
+		    fprintf(stderr, "%s| %s: INFO: User %s is member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain);
+		found++;
+		break;
+	    } else {
+		if (margs->debug || margs->log)
+		    fprintf(stderr, "%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) {
+	if (margs->debug)
+	    fprintf(stderr, "%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, "")) {
+	    if (margs->debug)
+		fprintf(stderr, "%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 (margs->debug || margs->log)
+		    fprintf(stderr, "%s| %s: INFO: User %s is member of group@domain %s@%s\n", LogTime(), PROGRAM, user, gr->group, gr->domain);
+		found++;
+		break;
+	    } else {
+		if (margs->debug || margs->log)
+		    fprintf(stderr, "%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) {
+	if (margs->debug)
+	    fprintf(stderr, "%s| %s: DEBUG: Default group loop: group@domain %s@%s\n", LogTime(), PROGRAM, gr->group, gr->domain ? gr->domain : "NULL");
+	if (!gr->domain) {
+	    if (margs->debug)
+		fprintf(stderr, "%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 (margs->debug || margs->log)
+		    fprintf(stderr, "%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 (margs->debug || margs->log)
+		    fprintf(stderr, "%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);
+}
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/support_netbios.cc squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_netbios.cc
--- squid-3/helpers/external_acl/kerberos_ldap_group/support_netbios.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_netbios.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,156 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 "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;
+    if (margs->debug)
+	fprintf(stderr, "%s| %s: DEBUG: Netbios list %s\n", LogTime(), PROGRAM, margs->nlist ? margs->nlist : "NULL");
+    dp = NULL;
+
+    if (!p) {
+	if (margs->debug)
+	    fprintf(stderr, "%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 */
+		if (margs->debug)
+		    fprintf(stderr, "%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 */
+		if (margs->debug)
+		    fprintf(stderr, "%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, "")) {
+		if (margs->debug)
+		    fprintf(stderr, "%s| %s: DEBUG: No domain defined for netbios name %s\n", LogTime(), PROGRAM, ndsp->netbios);
+		return (1);
+	    }
+	    if (margs->debug)
+		fprintf(stderr, "%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 */
+	if (margs->debug)
+	    fprintf(stderr, "%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, "")) {
+	if (margs->debug)
+	    fprintf(stderr, "%s| %s: DEBUG: No domain defined for netbios name %s\n", LogTime(), PROGRAM, ndsp->netbios);
+	return (1);
+    }
+    if (margs->debug)
+	fprintf(stderr, "%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) {
+	if (margs->debug)
+	    fprintf(stderr, "%s| %s: DEBUG: Netbios domain loop: netbios@domain %s@%s\n", LogTime(), PROGRAM, nd->netbios, nd->domain);
+	if (nd->netbios && !strcasecmp(nd->netbios, netbios)) {
+	    if (margs->debug)
+		fprintf(stderr, "%s| %s: DEBUG: Found netbios@domain %s@%s\n", LogTime(), PROGRAM, nd->netbios, nd->domain);
+	    return (nd->domain);
+	}
+	nd = nd->next;
+    }
+
+    return NULL;
+}
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/support_resolv.cc squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_resolv.cc
--- squid-3/helpers/external_acl/kerberos_ldap_group/support_resolv.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_resolv.cc	2010-05-30 16:09:19.000000000 +0100
@@ -0,0 +1,652 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 <errno.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <arpa/nameser.h>
+
+#include "support.h"
+
+void nsError(int error, 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 *));
+
+/*
+ * http://www.ietf.org/rfc/rfc1035.txt
+ */
+/*
+ * The header contains the following fields:
+ * 
+ * 1  1  1  1  1  1
+ * 0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |                      ID                       |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |                    QDCOUNT                    |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |                    ANCOUNT                    |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |                    NSCOUNT                    |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |                    ARCOUNT                    |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * 
+ * where:
+ * 
+ * ID              A 16 bit identifier assigned by the program that
+ * generates any kind of query.  This identifier is copied
+ * the corresponding reply and can be used by the requester
+ * to match up replies to outstanding queries.
+ * 
+ * QR              A one bit field that specifies whether this message is a
+ * query (0), or a response (1).
+ * 
+ * OPCODE          A four bit field that specifies kind of query in this
+ * message.  This value is set by the originator of a query
+ * and copied into the response.  The values are:
+ * 
+ * 0               a standard query (QUERY)
+ * 
+ * 1               an inverse query (IQUERY)
+ * 
+ * 2               a server status request (STATUS)
+ * 
+ * 3-15            reserved for future use
+ * 
+ * AA              Authoritative Answer - this bit is valid in responses,
+ * and specifies that the responding name server is an
+ * authority for the domain name in question section.
+ * 
+ * Note that the contents of the answer section may have
+ * multiple owner names because of aliases.  The AA bit
+ * corresponds to the name which matches the query name, or
+ * the first owner name in the answer section.
+ * 
+ * TC              TrunCation - specifies that this message was truncated
+ * due to length greater than that permitted on the
+ * transmission channel.
+ * 
+ * RD              Recursion Desired - this bit may be set in a query and
+ * is copied into the response.  If RD is set, it directs
+ * the name server to pursue the query recursively.
+ * Recursive query support is optional.
+ * 
+ * RA              Recursion Available - this be is set or cleared in a
+ * response, and denotes whether recursive query support is
+ * available in the name server.
+ * 
+ * Z               Reserved for future use.  Must be zero in all queries
+ * and responses.
+ * 
+ * RCODE           Response code - this 4 bit field is set as part of
+ * responses.  The values have the following
+ * interpretation:
+ * 
+ * 0               No error condition
+ * 
+ * 1               Format error - The name server was
+ * unable to interpret the query.
+ * 
+ * 2               Server failure - The name server was
+ * unable to process this query due to a
+ * problem with the name server.
+ * 
+ * 3               Name Error - Meaningful only for
+ * responses from an authoritative name
+ * server, this code signifies that the
+ * domain name referenced in the query does
+ * not exist.
+ * 
+ * 4               Not Implemented - The name server does
+ * not support the requested kind of query.
+ * 
+ * 5               Refused - The name server refuses to
+ * perform the specified operation for
+ * policy reasons.  For example, a name
+ * server may not wish to provide the
+ * information to the particular requester,
+ * or a name server may not wish to perform
+ * a particular operation (e.g., zone
+ * transfer) for particular data.
+ * 
+ * 6-15            Reserved for future use.
+ * 
+ * QDCOUNT         an unsigned 16 bit integer specifying the number of
+ * entries in the question section.
+ * 
+ * ANCOUNT         an unsigned 16 bit integer specifying the number of
+ * resource records in the answer section.
+ * 
+ * NSCOUNT         an unsigned 16 bit integer specifying the number of name
+ * server resource records in the authority records
+ * section.
+ * 
+ * ARCOUNT         an unsigned 16 bit integer specifying the number of
+ * resource records in the additional records section.
+ * 
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |                                               |
+ * /                    QNAME                      /
+ * /                                               /
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+ * |                    QTYPE                      |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+ * |                    QCLASS                     | 
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+ * QNAME is a variable length field to fit the hostname 
+ * QCLASS should be 1 since we are on internet 
+ * QTYPE determines what you want to know ; ipv4 address,mx etc. 
+ * 
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+ * |                                               |
+ * /                                               / 
+ * /                     NAME                      / 
+ * |                                               | 
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |                     TYPE                      |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+ * |                     CLASS                     | 
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+ * |                     TTL                       |
+ * |                                               |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+ * |                  RDLENGTH                     | 
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ * /                     RDATA                     /
+ * /                                               /
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+ * 
+ * NAME and RDATA are variable length field 
+ * Type field tells how RDATA relates to NAME. e.g. if TYPE is 1 then RDATA contains the ipv4 address of the NAME. 
+ * 
+ */
+/*
+ * http://www.ietf.org/rfc/rfc2782.txt
+ * 
+ * Here is the format of the SRV RR, whose DNS type code is 33:
+ * 
+ * _Service._Proto.Name TTL Class SRV Priority Weight Port Target
+ * 
+ * 
+ * Service
+ * The symbolic name of the desired service, as defined in Assigned
+ * Numbers [STD 2] or locally.  An underscore (_) is prepended to
+ * the service identifier to avoid collisions with DNS labels that
+ * occur in nature.
+ * Some widely used services, notably POP, don't have a single
+ * universal name.  If Assigned Numbers names the service
+ * indicated, that name is the only name which is legal for SRV
+ * lookups.  The Service is case insensitive.
+ * 
+ * Proto
+ * The symbolic name of the desired protocol, with an underscore
+ * (_) prepended to prevent collisions with DNS labels that occur
+ * in nature.  _TCP and _UDP are at present the most useful values
+ * for this field, though any name defined by Assigned Numbers or
+ * locally may be used (as for Service).  The Proto is case
+ * insensitive.
+ * 
+ * Name
+ * The domain this RR refers to.  The SRV RR is unique in that the
+ * name one searches for is not this name; the example near the end
+ * shows this clearly.
+ * 
+ * TTL
+ * Standard DNS meaning [RFC 1035].
+ * 
+ * Class
+ * Standard DNS meaning [RFC 1035].   SRV records occur in the IN
+ * Class.
+ * 
+ * Priority
+ * The priority of this target host.  A client MUST attempt to
+ * contact the target host with the lowest-numbered priority it can
+ * reach; target hosts with the same priority SHOULD be tried in an
+ * order defined by the weight field.  The range is 0-65535.  This
+ * is a 16 bit unsigned integer in network byte order.
+ * 
+ * Weight
+ * A server selection mechanism.  The weight field specifies a
+ * relative weight for entries with the same priority. Larger
+ * weights SHOULD be given a proportionately higher probability of
+ * being selected. The range of this number is 0-65535.  This is a
+ * 16 bit unsigned integer in network byte order.  Domain
+ * administrators SHOULD use Weight 0 when there isn't any server
+ * selection to do, to make the RR easier to read for humans (less
+ * noisy).  In the presence of records containing weights greater
+ * than 0, records with weight 0 should have a very small chance of
+ * being selected.
+ * 
+ * In the absence of a protocol whose specification calls for the
+ * use of other weighting information, a client arranges the SRV
+ * RRs of the same Priority in the order in which target hosts,
+ * specified by the SRV RRs, will be contacted. The following
+ * algorithm SHOULD be used to order the SRV RRs of the same
+ * priority:
+ * 
+ * To select a target to be contacted next, arrange all SRV RRs
+ * (that have not been ordered yet) in any order, except that all
+ * those with weight 0 are placed at the beginning of the list.
+ * 
+ * Compute the sum of the weights of those RRs, and with each RR
+ * associate the running sum in the selected order. Then choose a
+ * uniform random number between 0 and the sum computed
+ * (inclusive), and select the RR whose running sum value is the
+ * first in the selected order which is greater than or equal to
+ * the random number selected. The target host specified in the
+ * selected SRV RR is the next one to be contacted by the client.
+ * Remove this SRV RR from the set of the unordered SRV RRs and
+ * apply the described algorithm to the unordered SRV RRs to select
+ * the next target host.  Continue the ordering process until there
+ * are no unordered SRV RRs.  This process is repeated for each
+ * Priority.
+ * 
+ * Port
+ * The port on this target host of this service.  The range is 0-
+ * 65535.  This is a 16 bit unsigned integer in network byte order.
+ * This is often as specified in Assigned Numbers but need not be.
+ * 
+ * Target
+ * The domain name of the target host.  There MUST be one or more
+ * address records for this name, the name MUST NOT be an alias (in
+ * the sense of RFC 1034 or RFC 2181).  Implementors are urged, but
+ * not required, to return the address record(s) in the Additional
+ * Data section.  Unless and until permitted by future standards
+ * action, name compression is not to be used for this field.
+ * 
+ * A Target of "." means that the service is decidedly not
+ * available at this domain.
+ * 
+ * 
+ */
+void
+nsError(int error, char *service)
+{
+    switch (error) {
+    case HOST_NOT_FOUND:
+	fprintf(stderr, "%s| %s: ERROR: res_search: Unknown service record: %s\n", LogTime(), PROGRAM, service);
+	break;
+    case NO_DATA:
+	fprintf(stderr, "%s| %s: ERROR: res_search: No SRV record for %s\n", LogTime(), PROGRAM, service);
+	break;
+    case TRY_AGAIN:
+	fprintf(stderr, "%s| %s: ERROR: res_search: No response for SRV query\n", LogTime(), PROGRAM);
+	break;
+    default:
+	fprintf(stderr, "%s| %s: ERROR: res_search: Unexpected error: %s\n", LogTime(), PROGRAM, strerror(error));
+    }
+}
+
+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->host = b->host;
+    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) {
+	fprintf(stderr, "%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) {
+	    fprintf(stderr, "%s| %s: ERROR: Error while resolving ip address with getnameinfo: %s\n", LogTime(), PROGRAM, gai_strerror(rc));
+	    freeaddrinfo(hres);
+	    *hlist = hp;
+	    return (nhosts);
+	}
+	count++;
+	if (margs->debug)
+	    fprintf(stderr, "%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) {
+	fprintf(stderr, "%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) {
+		fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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) {
+	fprintf(stderr, "%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) {
+	fprintf(stderr, "%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) {
+	fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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) {
+		fprintf(stderr, "%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) {
+		fprintf(stderr, "%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) {
+		fprintf(stderr, "%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) {
+		fprintf(stderr, "%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) {
+		fprintf(stderr, "%s| %s: ERROR: Error while expanding SRV RR name with dn_expand:  %s\n", LogTime(), PROGRAM, strerror(errno));
+		goto cleanup;
+	    }
+	    if (margs->debug)
+		fprintf(stderr, "%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) {
+	    fprintf(stderr, "%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)
+	fprintf(stderr, "%s| %s: ERROR: Inconsistence message length: %ld!=0\n", LogTime(), PROGRAM, buffer + len - p);
+#else
+	fprintf(stderr, "%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 (margs->debug) {
+	fprintf(stderr, "%s| %s: DEBUG: Sorted ldap server names for domain %s:\n", LogTime(), PROGRAM, domain);
+	for (i = 0; i < nhosts; i++) {
+	    fprintf(stderr, "%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);
+}
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group/support_sasl.cc squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_sasl.cc
--- squid-3/helpers/external_acl/kerberos_ldap_group/support_sasl.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group/support_sasl.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,294 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 "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);
+
+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) {
+	    fprintf(stderr, "%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) {
+	fprintf(stderr, "%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
diff -Nur squid-3/helpers/external_acl/kerberos_ldap_group.cc squid-3-krb5/helpers/external_acl/kerberos_ldap_group.cc
--- squid-3/helpers/external_acl/kerberos_ldap_group.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/kerberos_ldap_group.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,372 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 <unistd.h>
+#include <ctype.h>
+
+#include "support.h"
+
+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->debug=0;
+  margs->log=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) {
+      free(p->group);
+      p->group=NULL;
+  }
+  if (p->domain) {
+      free(p->domain);
+      p->domain=NULL;
+  }
+  if (pp && pp->next) {
+    free(pp->next);
+    pp->next=NULL;
+  }
+  if (p == gdsp) {
+     free(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) {
+      free(p->netbios);
+      p->netbios=NULL;
+  }
+  if (p->domain) {
+      free(p->domain);
+      p->domain=NULL;
+  }
+  if (pp && pp->next) {
+    free(pp->next);
+    pp->next=NULL;
+  }
+  if (p == ndsp) {
+     free(ndsp);
+     ndsp=NULL;
+  }
+  goto start;
+}
+
+void clean_args(struct main_args *margs) {
+  if (margs->glist) {
+      free(margs->glist);
+      margs->glist=NULL;
+  }
+  if (margs->ulist) {
+      free(margs->ulist);
+      margs->ulist=NULL;
+  }
+  if (margs->tlist) {
+      free(margs->tlist);
+      margs->tlist=NULL;
+  }
+  if (margs->nlist) {
+      free(margs->nlist);
+      margs->nlist=NULL;
+  }
+  if (margs->luser) {
+      free(margs->luser);
+      margs->luser=NULL;
+  }
+  if (margs->lpass) {
+      free(margs->lpass);
+      margs->lpass=NULL;
+  }
+  if (margs->lbind) {
+      free(margs->lbind);
+      margs->lbind=NULL;
+  }
+  if (margs->lurl) {
+      free(margs->lurl);
+      margs->lurl=NULL;
+  }
+  if (margs->ssl) {
+      free(margs->ssl);
+      margs->ssl=NULL;
+  }
+  if (margs->ddomain) {
+      free(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':
+      margs.debug = 1;
+      break;
+    case 'i':
+      margs.log= 1;
+      break;
+    case 'a':
+      margs.rc_allow= 1;
+      break;
+    case 's':
+      margs.ssl= (char *)"yes";
+      break;
+    case 'g':
+      margs.glist = strdup(optarg);
+      break;
+    case 'D':
+      margs.ddomain = strdup(optarg);
+      break;
+    case 'N':
+      margs.nlist = strdup(optarg);
+      break;
+    case 'u':
+      margs.luser = strdup(optarg);
+      break;
+    case 'U':
+      margs.ulist = strdup(optarg);
+      break;
+    case 't':
+      margs.ulist = strdup(optarg);
+      break;
+    case 'T':
+      margs.tlist = strdup(optarg);
+      break;
+    case 'p':
+      margs.lpass = strdup(optarg);
+      /* Hide Password */
+      memset (optarg, 'X', strlen (optarg));
+      break;
+    case 'l':
+      margs.lurl = strdup(optarg);
+      break;
+    case 'b':
+      margs.lbind = strdup(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:
+      fprintf(stderr, "%s| %s: unknown option: -%c.\n", LogTime(), PROGRAM, opt);
+    }
+  }
+
+  if (margs.debug)
+    fprintf(stderr, "%s| %s: Starting version %s\n", LogTime(), PROGRAM, VERSION);
+  if (create_gd(&margs)) {
+    if (margs.debug)
+      fprintf(stderr, "%s| %s: Error in group list: %s\n",LogTime(), PROGRAM,margs.glist?margs.glist:"NULL");
+    fprintf(stdout, "ERR\n");
+    clean_args(&margs);
+    exit(1);
+  }
+  if (create_nd(&margs)) {
+    if (margs.debug)
+      fprintf(stderr, "%s| %s: Error in netbios list: %s\n",LogTime(), PROGRAM,margs.nlist?margs.nlist:"NULL");
+    fprintf(stdout, "ERR\n");
+    clean_args(&margs);
+    exit(1);
+  }
+  
+  while (1) {
+    if (fgets(buf, sizeof(buf)-1, stdin) == NULL) {
+      if (ferror(stdin)) {
+        if (margs.debug)
+          fprintf(stderr, "%s| %s: fgets() failed! dying..... errno=%d (%s)\n", LogTime(), PROGRAM, ferror(stdin),
+		  strerror(ferror(stdin)));
+
+        fprintf(stdout, "ERR\n");
+        clean_args(&margs);
+        exit(1);    /* BIIG buffer */
+      }
+      fprintf(stdout, "ERR\n");
+      clean_args(&margs);
+      exit(0);
+    }
+    c=memchr(buf,'\n',sizeof(buf)-1);
+    if (c) {
+      *c = '\0';
+      length = c-buf;
+    } else {
+      fprintf(stdout, "ERR\n");
+      if (margs.debug)
+        fprintf(stderr, "%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 (margs.debug || margs.log)
+        fprintf(stderr, "%s| %s: 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=strdup(margs.ddomain);
+      if (margs.debug || margs.log)
+        fprintf(stderr, "%s| %s: Got User: %s set default domain: %s\n",LogTime(), PROGRAM,user,domain);
+    }
+    if (margs.debug || margs.log)
+      fprintf(stderr, "%s| %s: 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)) {
+      fprintf(stdout, "OK\n");
+      if (margs.debug)
+        fprintf(stderr, "%s| %s: OK\n",LogTime(), PROGRAM);
+    } else {
+      fprintf(stdout, "ERR\n");
+      if (margs.debug)
+        fprintf(stderr, "%s| %s: ERR\n",LogTime(), PROGRAM);
+    }
+  } 
+
+
+}
+
+void strup(char *s)
+{
+   while (*s) {
+          *s = toupper((unsigned char)*s);
+          s++;
+   }
+}
diff -Nur squid-3/helpers/external_acl/support_group.cc squid-3-krb5/helpers/external_acl/support_group.cc
--- squid-3/helpers/external_acl/support_group.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/support_group.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,427 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 "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 = 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';
+    if (margs->debug)
+       fprintf(stderr, "%s| %s: 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=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 {
+         if (margs->debug)
+            fprintf(stderr, "%s| %s: Invalid Hex value %c\n",LogTime(), PROGRAM, ival);
+         if (ul)
+           xfree(ul);
+         return NULL;
+       }
+
+
+       if (n == a - 1 ) {
+         if (margs->debug)
+            fprintf(stderr, "%s| %s: 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 {
+         if (margs->debug)
+            fprintf(stderr, "%s| %s: 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';
+            if (margs->debug)
+               fprintf(stderr, "%s| %s: 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' ;
+            if (margs->debug)
+              fprintf(stderr, "%s| %s: 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' ;
+            if (margs->debug)
+              fprintf(stderr, "%s| %s: 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' ;
+          if (margs->debug)
+            fprintf(stderr, "%s| %s: 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) {
+      if (margs->debug) {
+        fprintf(stderr, "%s| %s: iUTF2: %d iUTF3: %d iUTF4: %d\n",LogTime(), PROGRAM,iUTF2,iUTF3,iUTF4);
+        fprintf(stderr, "%s| %s: 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=xmalloc(strlen(up)+strlen(hp1)+strlen(hp2)+2);
+        strcpy(p,up);
+        strcat(p,":");
+        strcat(p,hp1);
+        strcat(p,":");
+        strcat(p,hp2);
+      } else {
+        p=xmalloc(strlen(hp1)+strlen(hp2)+1);
+        strcpy(p,hp1);
+        strcat(p,":");
+        strcat(p,hp2);
+      }
+    } else {
+      if (up) {
+        p=xmalloc(strlen(up)+strlen(hp1)+1);
+        strcpy(p,up);
+        strcat(p,":");
+        strcat(p,hp1);
+      } else
+        p = hp1;
+    }
+  } else {
+    if (hp2) {
+      if (up) {
+        p=xmalloc(strlen(up)+strlen(hp2)+1);
+        strcpy(p,up);
+        strcat(p,":");
+        strcat(p,hp2);
+      } else 
+        p = hp2;
+    } else 
+      p = up;
+  }
+  gp=p;
+  if (margs->debug)
+    fprintf(stderr, "%s| %s: Group list %s\n",LogTime(), PROGRAM,p?p:"NULL");
+  dp=NULL;
+
+  if (!p) {
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: 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 */
+	if (margs->debug)
+	  fprintf(stderr, "%s| %s: 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 */
+	if (margs->debug)
+	  fprintf(stderr, "%s| %s: 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 */ 
+      if (margs->debug) 
+	fprintf(stderr, "%s| %s: Group %s  Domain %s\n",LogTime(), PROGRAM,gdsp->group,gdsp->domain?gdsp->domain:"NULL");
+    } else 
+      p++;
+  }
+  if (p == gp) { /* empty group name not allowed */
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: 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;
+  }
+  if (margs->debug) 
+    fprintf(stderr, "%s| %s: Group %s  Domain %s\n",LogTime(), PROGRAM,gdsp->group,gdsp->domain?gdsp->domain:"NULL");
+
+  margs->groups=gdsp; 
+  return(0);
+}
diff -Nur squid-3/helpers/external_acl/support_krb5.cc squid-3-krb5/helpers/external_acl/support_krb5.cc
--- squid-3/helpers/external_acl/support_krb5.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/support_krb5.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,376 @@
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * 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 <unistd.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "support.h"
+
+#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)
+    {
+	fprintf(stderr, "%s| %s: Error while initialising Kerberos library : %s\n",LogTime(), PROGRAM, error_message(code));
+	retval=1;
+	goto cleanup;
+    }
+
+    /*
+     * getting default keytab name
+     */
+
+    if (margs->debug)
+	fprintf(stderr, "%s| %s: 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);
+    if (margs->debug)
+	fprintf(stderr, "%s| %s: Got default keytab file name %s\n",LogTime(), PROGRAM, keytab_name);
+
+    code = krb5_kt_resolve(kparam.context, keytab_name, &keytab);
+    if (code)
+    {
+	fprintf(stderr, "%s| %s: 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)
+    {
+	fprintf(stderr, "%s| %s: Error while starting keytab scan : %s\n", LogTime(), PROGRAM, error_message(code));
+	retval=1;
+	goto cleanup;
+    }
+    if (margs->debug)
+	fprintf(stderr, "%s| %s: 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=realloc(principal_list,sizeof(krb5_principal)*(nprinc+1));
+        krb5_copy_principal(kparam.context,entry.principal,&principal_list[nprinc++]);
+	if (margs->debug)
+#ifdef HAVE_HEIMDAL_KERBEROS
+	    fprintf(stderr, "%s| %s: Keytab entry has realm name: %s\n", LogTime(), PROGRAM, entry.principal->realm);
+#else
+	    fprintf(stderr, "%s| %s: 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)
+		{
+		    fprintf(stderr, "%s| %s: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code));
+		} else {
+		    if (margs->debug)
+			fprintf(stderr, "%s| %s: 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)
+        {
+	    fprintf(stderr, "%s| %s: Error while freeing keytab entry : %s\n", LogTime(), PROGRAM, error_message(code));
+	    retval=1;
+	    break;
+        }
+        if (found) 
+            break;
+    }
+
+    if (code && code != KRB5_KT_END) 
+    {
+	fprintf(stderr, "%s| %s: 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)
+    {
+	fprintf(stderr, "%s| %s: Error while ending keytab scan : %s\n", LogTime(), PROGRAM, error_message(code));
+	retval=1;
+	goto cleanup;
+    }
+
+    /*
+     * prepare memory credential cache
+     */
+#ifndef HAVE_KRB5_MEMORY_CACHE
+    mem_cache=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=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);
+    if (margs->debug)
+	fprintf(stderr, "%s| %s: Set credential cache to %s\n",LogTime(), PROGRAM,mem_cache);
+    code = krb5_cc_resolve(kparam.context, mem_cache , &kparam.cc);
+    if (code) 
+    {
+	fprintf(stderr, "%s| %s: 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)
+    {
+	if (margs->debug) {
+	    fprintf(stderr, "%s| %s: Did not find a principal in keytab for domain %s.\n",LogTime(), PROGRAM,domain);
+	    fprintf(stderr, "%s| %s: Try to get principal of trusted domain.\n",LogTime(), PROGRAM);
+	}
+	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)
+            {
+                if (margs->debug)
+                    fprintf(stderr, "%s| %s: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code));
+		goto loop_end;
+            }
+	    if (margs->debug)
+	        fprintf(stderr, "%s| %s: 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=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)
+            {
+		if (margs->debug)
+		    fprintf(stderr, "%s| %s: 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)
+            {
+                fprintf(stderr, "%s| %s: 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)
+	    {
+	        if (margs->debug)
+		    fprintf(stderr, "%s| %s: 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=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=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)
+	    {
+		fprintf(stderr, "%s| %s: 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) {
+		if (margs->debug)
+		    fprintf(stderr, "%s| %s: Error while getting tgt : %s\n",LogTime(), PROGRAM, error_message(code));
+		goto loop_end;
+	    } else {
+		if (margs->debug)
+		    fprintf(stderr, "%s| %s: 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) {
+
+	if (margs->debug)
+	    fprintf(stderr, "%s| %s: Got principal name %s\n",LogTime(), PROGRAM, principal_name);
+	/*
+	 * build principal
+	 */
+	code = krb5_parse_name(kparam.context, principal_name, &principal);
+	if (code)
+	{
+	    fprintf(stderr, "%s| %s: Error while parsing name %s : %s\n", LogTime(), PROGRAM, principal_name,error_message(code));
+	    retval=1;
+	    goto cleanup;
+	}
+  
+	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=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)
+	{
+	    fprintf(stderr, "%s| %s: 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)
+        {
+            fprintf(stderr, "%s| %s: 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) 
+	{
+	    fprintf(stderr, "%s| %s: Error while storing credentials : %s\n",LogTime(), PROGRAM, error_message(code));
+	    retval=1;
+	    goto cleanup;
+	}
+	if (margs->debug)
+	    fprintf(stderr, "%s| %s: Stored credentials\n",LogTime(), PROGRAM);
+    } else {
+	if (margs->debug)
+	    fprintf(stderr, "%s| %s: 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);
+}
+
diff -Nur squid-3/helpers/external_acl/support_ldap.cc squid-3-krb5/helpers/external_acl/support_ldap.cc
--- squid-3/helpers/external_acl/support_ldap.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/support_ldap.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,1264 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "support.h"
+
+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);
+
+#ifdef HAVE_SUN_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=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=calloc(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;
+
+  if (margs->debug)
+    fprintf(stderr, "%s| %s: 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);
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: 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);
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: 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 {
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: Did not find ldap entry for subschemasubentry\n",LogTime(), PROGRAM);
+  }
+  if (margs->debug)
+    fprintf(stderr, "%s| %s: 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=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) {
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: Max search depth reached %d>%d\n",LogTime(), PROGRAM,depth,margs->mdepth);
+    return 0;
+  }
+  if (margs->debug)
+    fprintf(stderr, "%s| %s: 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) {
+    fprintf(stderr, "%s| %s: Error searching ldap server: %s\n",LogTime(), PROGRAM,ldap_err2string(rc));
+    ldap_unbind_s(ld);
+    return 0;
+  }
+
+  if (margs->debug)
+    fprintf(stderr, "%s| %s: 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 (margs->debug) { 
+      int n;
+      fprintf(stderr, "%s| %s: 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 (margs->debug)
+        fprintf(stderr, "%s| %s: Entry %d \"%s\" matches group name \"%s\"\n",LogTime(), PROGRAM, j+1, av, group);
+      break;
+    } else {
+      if (margs->debug)
+        fprintf(stderr, "%s| %s: Entry %d \"%s\" does not match group name \"%s\"\n",LogTime(), PROGRAM, j+1, av, group);
+    }
+    /*
+     * Do recursive group search
+     */
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: 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 (margs->debug)
+        fprintf(stderr, "%s| %s: 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 ) {
+    if(margs->debug)
+      fprintf(stderr, "%s| %s: 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 ) {
+    if(margs->debug)
+      fprintf(stderr, "%s| %s: 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 ) {
+    if(margs->debug)
+      fprintf(stderr, "%s| %s: 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) {
+    ssl_cacertfile=getenv("TLS_CACERTFILE");
+    free_path=0;
+    if (!ssl_cacertfile) {
+      ssl_cacertfile=xstrdup("/etc/ssl/certs/cert.pem");
+      free_path=1;
+    }
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: 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 ) {
+      fprintf(stderr, "%s| %s: Error while setting LDAP_OPT_X_TLS_CACERTFILE for ldap server: %s\n",LogTime(), PROGRAM,ldap_err2string(rc));
+      return rc;
+    }
+  } else {
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: 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 ) {
+      fprintf(stderr, "%s| %s: 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");
+  }
+  if (margs->debug)
+    fprintf(stderr, "%s| %s: 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);
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: Disable server certificate check for ldap server.\n",LogTime(), PROGRAM);
+  }
+  if (ssl_certdbpath) {
+    xfree(ssl_certdbpath);
+    ssl_certdbpath=NULL;
+  }
+  if ( rc != LDAP_SUCCESS ) {
+    fprintf(stderr, "%s| %s: Error while setting SSL for ldap server: %s\n",LogTime(), PROGRAM,ldapssl_err2string(rc));
+    return rc;
+  }
+#else
+  fprintf(stderr, "%s| %s: 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) {
+/* Part of this work is 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>.
+ */
+
+  LDAPMessage *msg;
+  char **attr_value=NULL;
+  int max_attr=0;
+
+  attr_value=*ret_value;
+  /*
+   * loop over attributes
+   */
+  if (margs->debug)
+    fprintf(stderr, "%s| %s: 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= realloc (attr_value,(il+1)*sizeof(char *));
+			if ( !attr_value) 
+			  break;
+
+                        attr_value[il] = 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:
+	if (margs->debug)
+	  fprintf(stderr, "%s| %s: Received a search reference message\n",LogTime(), PROGRAM);
+	break;
+      case LDAP_RES_SEARCH_RESULT:
+	if (margs->debug)
+	  fprintf(stderr, "%s| %s: Received a search result message\n",LogTime(), PROGRAM);
+	break;
+      default:
+	break;
+      }
+    }
+
+  if (margs->debug)
+    fprintf(stderr, "%s| %s: %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 = 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) {
+        fprintf(stderr, "%s| %s: 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) {
+        fprintf(stderr, "%s| %s: 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) {
+        fprintf(stderr, "%s| %s: 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
+         */
+	if (margs->debug)
+          fprintf(stderr, "%s| %s: Set SSL defaults\n",LogTime(), PROGRAM);
+        rc = ldap_set_ssl_defaults(margs);
+        if (rc != LDAP_SUCCESS) {
+          fprintf(stderr, "%s| %s: 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 ) {
+	  fprintf(stderr, "%s| %s: Error while setting start_tls for ldap server: %s\n",LogTime(), PROGRAM,ldap_err2string(rc));
+          ldap_unbind(ld);
+          ld=NULL;
+          url = 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) {
+            fprintf(stderr, "%s| %s: 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) {
+            fprintf(stderr, "%s| %s: 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) {
+            fprintf(stderr, "%s| %s: 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) {
+	  fprintf(stderr, "%s| %s: 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) {
+          fprintf(stderr, "%s| %s: Error while setting default options for ldap server: %s\n",LogTime(), PROGRAM,ldap_err2string(rc));
+          ldap_unbind(ld);
+          ld = NULL;
+          return NULL;
+        }
+#else
+        fprintf(stderr, "%s| %s: 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) {
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: Setup Kerberos credential cache\n",LogTime(), PROGRAM);
+
+    kc = krb5_create_cache(margs,domain);
+    if (kc) {
+      fprintf(stderr, "%s| %s: 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
+
+  if (margs->debug)
+    fprintf(stderr, "%s| %s: Initialise ldap connection\n",LogTime(), PROGRAM);
+
+
+  if (domain && !kc) {
+    if (margs->ssl) {
+      if (margs->debug)
+	fprintf(stderr, "%s| %s: Enable SSL to ldap servers\n",LogTime(), PROGRAM);
+    }
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: 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;
+      if (margs->debug)
+	fprintf(stderr, "%s| %s: 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)
+      if (margs->debug)
+        fprintf(stderr, "%s| %s: Bind to ldap server with SASL/GSSAPI\n",LogTime(), PROGRAM);
+
+      rc = tool_sasl_bind(ld, bindp, margs->ssl);
+      if (rc != LDAP_SUCCESS) {
+        fprintf(stderr, "%s| %s: Error while binding to ldap server with SASL/GSSAPI: %s\n",LogTime(), PROGRAM,ldap_err2string(rc));
+        ldap_unbind(ld);
+        ld=NULL;
+        continue;
+      }
+      lcreds=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 ) {
+	if (margs->debug)
+	    fprintf(stderr, "%s| %s: %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;
+      fprintf(stderr, "%s| %s: SASL not supported on system\n",LogTime(), PROGRAM);
+      continue;
+#endif
+    }
+    nhosts=free_hostname_list(&hlist,nhosts);
+    if ( ld == NULL ) {
+      if (margs->debug)
+        fprintf(stderr, "%s| %s: 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) {
+      if (margs->debug)
+	fprintf(stderr, "%s| %s: Enable SSL to ldap servers\n",LogTime(), PROGRAM);
+    }
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: 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
+       */
+
+      if (margs->debug)
+	fprintf(stderr, "%s| %s: Bind to ldap server with Username/Password\n",LogTime(), PROGRAM);
+      rc = ldap_simple_bind_s(ld, margs->luser, margs->lpass);
+      if (rc != LDAP_SUCCESS) {
+	fprintf(stderr, "%s| %s: Error while binding to ldap server with Username/Password: %s\n",LogTime(), PROGRAM,ldap_err2string(rc));
+	ldap_unbind(ld);
+	ld=NULL;
+	continue;
+      }
+      lcreds=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);
+      if (margs->debug)
+	fprintf(stderr, "%s| %s: %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 ) {
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: 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) {
+    fprintf(stderr, "%s| %s: 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=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 (margs->debug)
+    fprintf(stderr, "%s| %s: 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) {
+    fprintf(stderr, "%s| %s: Error searching ldap server: %s\n",LogTime(), PROGRAM,ldap_err2string(rc));
+    ldap_unbind(ld);
+    ld=NULL;
+    retval=0;
+    goto cleanup;
+  }
+
+  if (margs->debug)
+    fprintf(stderr, "%s| %s: 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 (margs->debug) { 
+        int n;
+        fprintf(stderr, "%s| %s: 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 (margs->debug)
+	  fprintf(stderr, "%s| %s: Entry %d \"%s\" matches group name \"%s\"\n",LogTime(), PROGRAM, j+1, av, group);
+        else
+          break;
+      } else {
+        if (margs->debug)
+  	  fprintf(stderr, "%s| %s: 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 (margs->debug && max_attr > 0)
+        fprintf(stderr, "%s| %s: 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 (margs->debug)
+            fprintf(stderr, "%s| %s: 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
+     */
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: Search for primary group membership: \"%s\"\n",LogTime(), PROGRAM,group);
+    filter=(char *)FILTER_UID;
+
+    ldap_filter_esc = escape_filter(user);
+
+    search_exp=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 (margs->debug)
+      fprintf(stderr, "%s| %s: 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 (margs->debug)
+      fprintf(stderr, "%s| %s: 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=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 (margs->debug)
+	fprintf(stderr, "%s| %s: 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;
+          if (margs->debug)
+            fprintf(stderr, "%s| %s: \"%s\" matches group name \"%s\"\n",LogTime(), PROGRAM, av, group);
+        } else {
+          if (margs->debug)
+            fprintf(stderr, "%s| %s: \"%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);
+
+      if (margs->debug)
+	fprintf(stderr, "%s| %s: Users primary group %s %s\n",LogTime(), PROGRAM, retval?"matches":"does not match", group);
+  
+    } else {
+      if (margs->debug)
+	fprintf(stderr, "%s| %s: 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) {
+    fprintf(stderr, "%s| %s: Error unbind ldap server: %s\n",LogTime(), PROGRAM,ldap_err2string(rc));
+  }
+  if (margs->debug)
+    fprintf(stderr, "%s| %s: 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) ;
+
+}
diff -Nur squid-3/helpers/external_acl/support_member.cc squid-3-krb5/helpers/external_acl/support_member.cc
--- squid-3/helpers/external_acl/support_member.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/support_member.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,125 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 "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) {
+    if (margs->debug)
+      fprintf(stderr,"%s| %s: User domain loop: group@domain %s@%s\n",LogTime(), PROGRAM,gr->group,gr->domain?gr->domain:"NULL");
+    if (gr->domain && !strcasecmp(gr->domain,domain)) {
+      if (margs->debug)
+	fprintf(stderr,"%s| %s: Found group@domain %s@%s\n",LogTime(), PROGRAM,gr->group,gr->domain);
+      /* query ldap */
+      if (get_memberof(margs,user,domain,gr->group)) {
+        if (margs->debug || margs->log)
+	  fprintf(stderr,"%s| %s: User %s is member of group@domain %s@%s\n",LogTime(), PROGRAM,user,gr->group,gr->domain);
+	found++;
+	break;
+      } else {
+        if (margs->debug || margs->log)
+	  fprintf(stderr,"%s| %s: 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) {
+    if (margs->debug)
+      fprintf(stderr,"%s| %s: Default domain loop: group@domain %s@%s\n",LogTime(), PROGRAM,gr->group,gr->domain?gr->domain:"NULL");
+    if (gr->domain && !strcasecmp(gr->domain,"")) {
+      if (margs->debug)
+	fprintf(stderr,"%s| %s: Found group@domain %s@%s\n",LogTime(), PROGRAM,gr->group,gr->domain);
+      /* query ldap */
+      if (get_memberof(margs,user,domain,gr->group)) {
+        if (margs->debug || margs->log)
+	  fprintf(stderr,"%s| %s: User %s is member of group@domain %s@%s\n",LogTime(), PROGRAM,user,gr->group,gr->domain);
+	found++;
+	break;
+      } else {
+        if (margs->debug || margs->log)
+	  fprintf(stderr,"%s| %s: 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) {
+    if (margs->debug)
+      fprintf(stderr,"%s| %s: Default group loop: group@domain %s@%s\n",LogTime(), PROGRAM,gr->group,gr->domain?gr->domain:"NULL");
+    if (!gr->domain) {
+      if (margs->debug)
+	fprintf(stderr,"%s| %s: 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 (margs->debug || margs->log)
+	  fprintf(stderr,"%s| %s: User %s is member of group@domain %s@%s\n",LogTime(), PROGRAM,user,gr->group,gr->domain?gr->domain:"NULL");
+	found++;
+	break;
+      } else {
+        if (margs->debug || margs->log)
+	  fprintf(stderr,"%s| %s: 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);
+}
+
diff -Nur squid-3/helpers/external_acl/support_netbios.cc squid-3-krb5/helpers/external_acl/support_netbios.cc
--- squid-3/helpers/external_acl/support_netbios.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/support_netbios.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,151 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 "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;
+  if (margs->debug)
+    fprintf(stderr, "%s| %s: Netbios list %s\n",LogTime(), PROGRAM,margs->nlist?margs->nlist:"NULL");
+  dp=NULL;
+
+  if (!p) {
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: 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 */
+	if (margs->debug)
+	  fprintf(stderr, "%s| %s: 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 */
+	if (margs->debug)
+	  fprintf(stderr, "%s| %s: 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,"")) {
+        if (margs->debug)
+          fprintf(stderr, "%s| %s: No domain defined for netbios name %s\n",LogTime(), PROGRAM,ndsp->netbios);
+        return(1);
+      }
+      if (margs->debug) 
+	fprintf(stderr, "%s| %s: Netbios name %s  Domain %s\n",LogTime(), PROGRAM,ndsp->netbios,ndsp->domain);
+    } else 
+      p++;
+  }
+  if (p == np) { /* empty group name not allowed */
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: 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,"")) {
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: No domain defined for netbios name %s\n",LogTime(), PROGRAM,ndsp->netbios);
+    return(1);
+  }
+  if (margs->debug) 
+    fprintf(stderr, "%s| %s: 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) {
+    if (margs->debug)
+      fprintf(stderr,"%s| %s: Netbios domain loop: netbios@domain %s@%s\n",LogTime(), PROGRAM,nd->netbios,nd->domain);
+    if (nd->netbios && !strcasecmp(nd->netbios,netbios)) {
+      if (margs->debug)
+        fprintf(stderr,"%s| %s: Found netbios@domain %s@%s\n",LogTime(), PROGRAM,nd->netbios,nd->domain);
+      return(nd->domain);
+    }
+    nd = nd->next;
+  }
+
+  return NULL;
+}
+
diff -Nur squid-3/helpers/external_acl/support_resolv.cc squid-3-krb5/helpers/external_acl/support_resolv.cc
--- squid-3/helpers/external_acl/support_resolv.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/support_resolv.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,636 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 <errno.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <arpa/nameser.h>
+
+#include "support.h"
+
+void nsError(int error, 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 *));
+
+/*
+  http://www.ietf.org/rfc/rfc1035.txt
+*/
+/*
+  The header contains the following fields:
+
+  1  1  1  1  1  1
+  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+  |                      ID                       |
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+  |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+  |                    QDCOUNT                    |
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+  |                    ANCOUNT                    |
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+  |                    NSCOUNT                    |
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+  |                    ARCOUNT                    |
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+  where:
+
+  ID              A 16 bit identifier assigned by the program that
+  generates any kind of query.  This identifier is copied
+  the corresponding reply and can be used by the requester
+  to match up replies to outstanding queries.
+
+  QR              A one bit field that specifies whether this message is a
+  query (0), or a response (1).
+
+  OPCODE          A four bit field that specifies kind of query in this
+  message.  This value is set by the originator of a query
+  and copied into the response.  The values are:
+
+  0               a standard query (QUERY)
+
+  1               an inverse query (IQUERY)
+
+  2               a server status request (STATUS)
+
+  3-15            reserved for future use
+
+  AA              Authoritative Answer - this bit is valid in responses,
+  and specifies that the responding name server is an
+  authority for the domain name in question section.
+
+  Note that the contents of the answer section may have
+  multiple owner names because of aliases.  The AA bit
+  corresponds to the name which matches the query name, or
+  the first owner name in the answer section.
+
+  TC              TrunCation - specifies that this message was truncated
+  due to length greater than that permitted on the
+  transmission channel.
+
+  RD              Recursion Desired - this bit may be set in a query and
+  is copied into the response.  If RD is set, it directs
+  the name server to pursue the query recursively.
+  Recursive query support is optional.
+
+  RA              Recursion Available - this be is set or cleared in a
+  response, and denotes whether recursive query support is
+  available in the name server.
+
+  Z               Reserved for future use.  Must be zero in all queries
+  and responses.
+
+  RCODE           Response code - this 4 bit field is set as part of
+  responses.  The values have the following
+  interpretation:
+
+  0               No error condition
+
+  1               Format error - The name server was
+  unable to interpret the query.
+
+  2               Server failure - The name server was
+  unable to process this query due to a
+  problem with the name server.
+
+  3               Name Error - Meaningful only for
+  responses from an authoritative name
+  server, this code signifies that the
+  domain name referenced in the query does
+  not exist.
+
+  4               Not Implemented - The name server does
+  not support the requested kind of query.
+
+  5               Refused - The name server refuses to
+  perform the specified operation for
+  policy reasons.  For example, a name
+  server may not wish to provide the
+  information to the particular requester,
+  or a name server may not wish to perform
+  a particular operation (e.g., zone
+  transfer) for particular data.
+
+  6-15            Reserved for future use.
+
+  QDCOUNT         an unsigned 16 bit integer specifying the number of
+  entries in the question section.
+
+  ANCOUNT         an unsigned 16 bit integer specifying the number of
+  resource records in the answer section.
+
+  NSCOUNT         an unsigned 16 bit integer specifying the number of name
+  server resource records in the authority records
+  section.
+
+  ARCOUNT         an unsigned 16 bit integer specifying the number of
+  resource records in the additional records section.
+
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+  |                                               |
+  /                    QNAME                      /
+  /                                               /
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+  |                    QTYPE                      |
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+  |                    QCLASS                     | 
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+  QNAME is a variable length field to fit the hostname 
+  QCLASS should be 1 since we are on internet 
+  QTYPE determines what you want to know ; ipv4 address,mx etc. 
+
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+  |                                               |
+  /                                               / 
+  /                     NAME                      / 
+  |                                               | 
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+  |                     TYPE                      |
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+  |                     CLASS                     | 
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+  |                     TTL                       |
+  |                                               |
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+  |                  RDLENGTH                     | 
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+  /                     RDATA                     /
+  /                                               /
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 
+
+  NAME and RDATA are variable length field 
+  Type field tells how RDATA relates to NAME. e.g. if TYPE is 1 then RDATA contains the ipv4 address of the NAME. 
+
+*/
+/*
+  http://www.ietf.org/rfc/rfc2782.txt
+
+  Here is the format of the SRV RR, whose DNS type code is 33:
+
+  _Service._Proto.Name TTL Class SRV Priority Weight Port Target
+
+
+  Service
+  The symbolic name of the desired service, as defined in Assigned
+  Numbers [STD 2] or locally.  An underscore (_) is prepended to
+  the service identifier to avoid collisions with DNS labels that
+  occur in nature.
+  Some widely used services, notably POP, don't have a single
+  universal name.  If Assigned Numbers names the service
+  indicated, that name is the only name which is legal for SRV
+  lookups.  The Service is case insensitive.
+
+  Proto
+  The symbolic name of the desired protocol, with an underscore
+  (_) prepended to prevent collisions with DNS labels that occur
+  in nature.  _TCP and _UDP are at present the most useful values
+  for this field, though any name defined by Assigned Numbers or
+  locally may be used (as for Service).  The Proto is case
+  insensitive.
+
+  Name
+  The domain this RR refers to.  The SRV RR is unique in that the
+  name one searches for is not this name; the example near the end
+  shows this clearly.
+
+  TTL
+  Standard DNS meaning [RFC 1035].
+
+  Class
+  Standard DNS meaning [RFC 1035].   SRV records occur in the IN
+  Class.
+
+  Priority
+  The priority of this target host.  A client MUST attempt to
+  contact the target host with the lowest-numbered priority it can
+  reach; target hosts with the same priority SHOULD be tried in an
+  order defined by the weight field.  The range is 0-65535.  This
+  is a 16 bit unsigned integer in network byte order.
+
+  Weight
+  A server selection mechanism.  The weight field specifies a
+  relative weight for entries with the same priority. Larger
+  weights SHOULD be given a proportionately higher probability of
+  being selected. The range of this number is 0-65535.  This is a
+  16 bit unsigned integer in network byte order.  Domain
+  administrators SHOULD use Weight 0 when there isn't any server
+  selection to do, to make the RR easier to read for humans (less
+  noisy).  In the presence of records containing weights greater
+  than 0, records with weight 0 should have a very small chance of
+  being selected.
+
+  In the absence of a protocol whose specification calls for the
+  use of other weighting information, a client arranges the SRV
+  RRs of the same Priority in the order in which target hosts,
+  specified by the SRV RRs, will be contacted. The following
+  algorithm SHOULD be used to order the SRV RRs of the same
+  priority:
+
+  To select a target to be contacted next, arrange all SRV RRs
+  (that have not been ordered yet) in any order, except that all
+  those with weight 0 are placed at the beginning of the list.
+
+  Compute the sum of the weights of those RRs, and with each RR
+  associate the running sum in the selected order. Then choose a
+  uniform random number between 0 and the sum computed
+  (inclusive), and select the RR whose running sum value is the
+  first in the selected order which is greater than or equal to
+  the random number selected. The target host specified in the
+  selected SRV RR is the next one to be contacted by the client.
+  Remove this SRV RR from the set of the unordered SRV RRs and
+  apply the described algorithm to the unordered SRV RRs to select
+  the next target host.  Continue the ordering process until there
+  are no unordered SRV RRs.  This process is repeated for each
+  Priority.
+
+  Port
+  The port on this target host of this service.  The range is 0-
+  65535.  This is a 16 bit unsigned integer in network byte order.
+  This is often as specified in Assigned Numbers but need not be.
+
+  Target
+  The domain name of the target host.  There MUST be one or more
+  address records for this name, the name MUST NOT be an alias (in
+  the sense of RFC 1034 or RFC 2181).  Implementors are urged, but
+  not required, to return the address record(s) in the Additional
+  Data section.  Unless and until permitted by future standards
+  action, name compression is not to be used for this field.
+
+  A Target of "." means that the service is decidedly not
+  available at this domain.
+
+
+*/
+void nsError(int error, char* service) {
+  switch (error) {
+  case HOST_NOT_FOUND:
+    fprintf(stderr,"%s| %s: res_search: Unknown service record: %s\n",LogTime(), PROGRAM,service);
+    break;
+  case NO_DATA:
+    fprintf(stderr,"%s| %s: res_search: No SRV record for %s\n",LogTime(), PROGRAM,service);
+    break;
+  case TRY_AGAIN:
+    fprintf(stderr,"%s| %s: res_search: No response for SRV query\n",LogTime(), PROGRAM);
+    break;
+  default:
+    fprintf(stderr,"%s| %s: res_search: Unexpected error: %s\n",LogTime(), PROGRAM,strerror(error));
+  }
+}
+
+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->host=b->host;
+  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)];
+  struct addrinfo *hres=NULL, *hres_list;
+  int rc,count;
+  struct hstruct *hp=NULL;
+
+  if (!name)
+    return(nhosts);
+
+  hp=*hlist;
+
+  rc = xgetaddrinfo(name,NULL,NULL,&hres);
+  if (rc != 0) {
+    fprintf(stderr, "%s| %s: Error while resolving hostname with getaddrinfo: %s\n",LogTime(), PROGRAM,xgai_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 = xgetnameinfo (hres_list->ai_addr, hres_list->ai_addrlen,host, sizeof (host), NULL, 0, 0);
+    if (rc != 0) {
+      fprintf(stderr, "%s| %s: Error while resolving ip address with getnameinfo: %s\n",LogTime(), PROGRAM,xgai_strerror(rc));
+      xfreeaddrinfo(hres);
+      *hlist=hp;
+      return(nhosts);
+    }
+    count++;
+    if (margs->debug)
+      fprintf(stderr, "%s| %s: Resolved address %d of %s to %s\n",LogTime(), PROGRAM, count, name, host);
+
+    hp=realloc(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;
+  }
+
+  xfreeaddrinfo(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 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=malloc(strlen("_ldaps._tcp.")+strlen(domain)+1);
+    strcpy(service,"_ldaps._tcp.");
+  } else {
+    service=malloc(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=malloc(PACKETSZ_MULT*NS_PACKETSZ);
+  if ((len = res_search(service, ns_c_in, ns_t_srv, (u_char *)buffer, PACKETSZ_MULT*NS_PACKETSZ))<0) {
+    fprintf(stderr,"%s| %s: Error while resolving service record %s with res_search\n",LogTime(), PROGRAM,service); 
+    nsError(h_errno,service);
+    if (margs->ssl) {
+      xfree(service);
+      service=malloc(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) {
+        fprintf(stderr,"%s| %s: 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=realloc(buffer,len);
+    if ((len = res_search(service, ns_c_in, ns_t_srv, (u_char *)buffer, len))<0) {
+      fprintf(stderr,"%s| %s: Error while resolving service record %s with res_search\n",LogTime(), PROGRAM,service); 
+      nsError(h_errno,service);
+      goto cleanup;
+    }
+    if (len > olen) {
+      fprintf(stderr,"%s| %s: 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 ) {
+    fprintf(stderr,"%s| %s: 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) {
+    fprintf(stderr,"%s| %s: 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 ) {
+    fprintf(stderr,"%s| %s: 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) {
+      fprintf(stderr,"%s| %s: 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 ) {
+      fprintf(stderr,"%s| %s: 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 ) {
+      fprintf(stderr,"%s| %s: 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 ) {
+	fprintf(stderr,"%s| %s: 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 ) {
+	fprintf(stderr,"%s| %s: Message to small: %d <  SRV RR + priority\n",LogTime(), PROGRAM,len); 
+	goto cleanup;
+      }
+      NS_GET16(weight,p);      /* Weight (16bit) */
+      if ( p > buffer+len ) {
+	fprintf(stderr,"%s| %s: Message to small: %d <  SRV RR + priority + weight\n",LogTime(), PROGRAM,len); 
+	goto cleanup;
+      }
+      NS_GET16(port,p);       /* Port (16bit) */
+      if ( p > buffer+len ) {
+	fprintf(stderr,"%s| %s: 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) {
+	fprintf(stderr,"%s| %s: Error while expanding SRV RR name with dn_expand:  %s\n",LogTime(), PROGRAM,strerror(errno));
+	goto cleanup;
+      } 
+      if (margs->debug)
+	fprintf(stderr, "%s| %s: Resolved SRV %s record to %s\n",LogTime(), PROGRAM, service, host);
+      hp=realloc(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 ) {
+      fprintf(stderr,"%s| %s: Message to small: %d <  SRV RR + priority + weight + port + name\n",LogTime(), PROGRAM,len); 
+      goto cleanup;
+    }
+  }
+  if ( p != buffer+len ) {
+#if (SIZEOF_LONG == 8)
+    fprintf(stderr,"%s| %s: Inconsistence message length: %ld!=0\n",LogTime(), PROGRAM,buffer+len-p);
+#else
+    fprintf(stderr,"%s| %s: 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=realloc(hp,sizeof(struct hstruct)*(nhosts+1));
+	}
+      }
+    }
+  }
+
+  /* Sort by Priority / Weight */
+  msort(hp,nhosts,compare_hosts);
+
+  if (margs->debug) {
+    fprintf(stderr, "%s| %s: Sorted ldap server names for domain %s:\n",LogTime(), PROGRAM,domain);
+    for (i=0;i<nhosts;i++) {
+      fprintf(stderr, "%s| %s: 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);
+}
diff -Nur squid-3/helpers/external_acl/support_sasl.cc squid-3-krb5/helpers/external_acl/support_sasl.cc
--- squid-3/helpers/external_acl/support_sasl.cc	1970-01-01 01:00:00.000000000 +0100
+++ squid-3-krb5/helpers/external_acl/support_sasl.cc	2010-05-30 15:13:58.000000000 +0100
@@ -0,0 +1,276 @@
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * 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 "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 );
+
+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 *)malloc( sizeof( lutilSASLdefaults ) );
+
+  if( defaults == NULL ) return NULL;
+
+  defaults->mech = mech ? strdup(mech) : NULL;
+  defaults->realm = realm ? strdup(realm) : NULL;
+  defaults->authcid = authcid ? strdup(authcid) : NULL;
+  defaults->passwd = passwd ? strdup(passwd) : NULL;
+  defaults->authzid = authzid ? strdup(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 = strlen( interact->result );
+
+  return LDAP_SUCCESS;
+}
+
+int lutil_sasl_interact(
+			LDAP *ld,
+			unsigned flags,
+			void *defaults,
+			void *in )
+{
+  sasl_interact_t *interact = in;
+
+  if( ld == NULL ) return LDAP_PARAM_ERROR;
+
+  while( interact->id != SASL_CB_LIST_END ) {
+    int rc = interaction( flags, interact, defaults );
+
+    if( rc )  return rc;
+    interact++;
+  }
+
+  return LDAP_SUCCESS;
+}
+
+void
+lutil_sasl_freedefs(
+		    void *defaults )
+{
+  lutilSASLdefaults *defs = defaults;
+
+  if (defs->mech) free(defs->mech);
+  if (defs->realm) free(defs->realm);
+  if (defs->authcid) free(defs->authcid);
+  if (defs->passwd) free(defs->passwd);
+  if (defs->authzid) free(defs->authzid);
+  if (defs->resps) free(defs->resps);
+
+  free(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) {
+	fprintf(stderr,"%s| %s: 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 ) {
+      fprintf(stderr,"%s| %s: 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: Dummy function\n",LogTime(), PROGRAM);
+}
+#endif
+    
+    
+  
diff -Nur squid-3/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth-logging.patch squid-3-krb5/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth-logging.patch
--- squid-3/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth-logging.patch	2010-02-09 19:17:07.000000000 +0000
+++ squid-3-krb5/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth-logging.patch	1970-01-01 01:00:00.000000000 +0100
@@ -1,216 +0,0 @@
---- negotiate_kerberos_auth.cc	2010-02-09 19:16:27.000000000 +0000
-+++ negotiate_kerberos_auth-new.cc	2010-02-09 19:16:03.000000000 +0000
-@@ -120,14 +120,14 @@
- 
-     rc = gethostname(hostname, sysconf(_SC_HOST_NAME_MAX));
-     if (rc) {
--        fprintf(stderr, "%s| %s: error while resolving hostname '%s'\n",
-+        fprintf(stderr, "%s| %s: ERROR: resolving hostname '%s' failed\n",
-                 LogTime(), PROGRAM, hostname);
-         return NULL;
-     }
-     rc = xgetaddrinfo(hostname, NULL, NULL, &hres);
-     if (rc != 0) {
-         fprintf(stderr,
--                "%s| %s: error while resolving hostname with getaddrinfo: %s\n",
-+                "%s| %s: ERROR: resolving hostname with getaddrinfo: %s failed\n",
-                 LogTime(), PROGRAM, xgai_strerror(rc));
-         return NULL;
-     }
-@@ -141,7 +141,7 @@
-                       sizeof(hostname), NULL, 0, 0);
-     if (rc != 0) {
-         fprintf(stderr,
--                "%s| %s: error while resolving ip address with getnameinfo: %s\n",
-+                "%s| %s: ERROR: resolving ip address with getnameinfo: %s failed\n",
-                 LogTime(), PROGRAM, xgai_strerror(rc));
-         xfreeaddrinfo(hres);
-         return NULL;
-@@ -199,11 +199,11 @@
-             gss_release_buffer(&min_stat, &status_string);
-         }
-         if (debug)
--            fprintf(stderr, "%s| %s: %s failed: %s\n", LogTime(), PROGRAM,
-+            fprintf(stderr, "%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: User not authenticated\n", LogTime(),
-+            fprintf(stderr, "%s| %s: INFO: User not authenticated\n", LogTime(),
-                     PROGRAM);
-         return (1);
-     }
-@@ -267,13 +267,13 @@
-             fprintf(stderr, "default SPN is HTTP/fqdn@DEFAULT_REALM\n");
-             exit(0);
-         default:
--            fprintf(stderr, "%s| %s: unknown option: -%c.\n", LogTime(),
-+            fprintf(stderr, "%s| %s: WARNING: unknown option: -%c.\n", LogTime(),
-                     PROGRAM, opt);
-         }
-     }
- 
-     if (debug)
--        fprintf(stderr, "%s| %s: Starting version %s\n", LogTime(), PROGRAM,
-+        fprintf(stderr, "%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;
-@@ -282,7 +282,7 @@
-         host_name = gethost_name();
-         if (!host_name) {
-             fprintf(stderr,
--                    "%s| %s: Local hostname could not be determined. Please specify the service principal\n",
-+                    "%s| %s: FATAL: Local hostname could not be determined. Please specify the service principal\n",
-                     LogTime(), PROGRAM);
-             fprintf(stdout, "BH hostname error\n");
-             exit(-1);
-@@ -298,7 +298,7 @@
-             if (ferror(stdin)) {
-                 if (debug)
-                     fprintf(stderr,
--                            "%s| %s: fgets() failed! dying..... errno=%d (%s)\n",
-+                            "%s| %s: FATAL: fgets() failed! dying..... errno=%d (%s)\n",
-                             LogTime(), PROGRAM, ferror(stdin),
-                             strerror(ferror(stdin)));
- 
-@@ -318,7 +318,7 @@
-         }
-         if (err) {
-             if (debug)
--                fprintf(stderr, "%s| %s: Oversized message\n", LogTime(),
-+                fprintf(stderr, "%s| %s: ERROR: Oversized message\n", LogTime(),
-                         PROGRAM);
-             fprintf(stdout, "BH Oversized message\n");
-             err = 0;
-@@ -326,12 +326,12 @@
-         }
- 
-         if (debug)
--            fprintf(stderr, "%s| %s: Got '%s' from squid (length: %d).\n",
-+            fprintf(stderr, "%s| %s: DEBUG: Got '%s' from squid (length: %d).\n",
-                     LogTime(), PROGRAM, buf, length);
- 
-         if (buf[0] == '\0') {
-             if (debug)
--                fprintf(stderr, "%s| %s: Invalid request\n", LogTime(),
-+                fprintf(stderr, "%s| %s: ERROR: Invalid request\n", LogTime(),
-                         PROGRAM);
-             fprintf(stdout, "BH Invalid request\n");
-             continue;
-@@ -339,7 +339,7 @@
- 
-         if (strlen(buf) < 2) {
-             if (debug)
--                fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(),
-+                fprintf(stderr, "%s| %s: ERROR: Invalid request [%s]\n", LogTime(),
-                         PROGRAM, buf);
-             fprintf(stdout, "BH Invalid request\n");
-             continue;
-@@ -382,7 +382,7 @@
- 
-         if (strncmp(buf, "YR", 2) && strncmp(buf, "KK", 2)) {
-             if (debug)
--                fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(),
-+                fprintf(stderr, "%s| %s: ERROR: Invalid request [%s]\n", LogTime(),
-                         PROGRAM, buf);
-             fprintf(stdout, "BH Invalid request\n");
-             continue;
-@@ -395,7 +395,7 @@
- 
-         if (strlen(buf) <= 3) {
-             if (debug)
--                fprintf(stderr, "%s| %s: Invalid negotiate request [%s]\n",
-+                fprintf(stderr, "%s| %s: ERROR: Invalid negotiate request [%s]\n",
-                         LogTime(), PROGRAM, buf);
-             fprintf(stdout, "BH Invalid negotiate request\n");
-             continue;
-@@ -403,7 +403,7 @@
- 
-         input_token.length = ska_base64_decode_len(buf + 3);
-         if (debug)
--            fprintf(stderr, "%s| %s: Decode '%s' (decoded length: %d).\n",
-+            fprintf(stderr, "%s| %s: DEBUG: Decode '%s' (decoded length: %d).\n",
-                     LogTime(), PROGRAM, buf + 3, (int) input_token.length);
-         input_token.value = xmalloc(input_token.length);
- 
-@@ -413,7 +413,7 @@
-         if ((input_token.length >= sizeof ntlmProtocol + 1) &&
-                 (!memcmp(input_token.value, ntlmProtocol, sizeof ntlmProtocol))) {
-             if (debug)
--                fprintf(stderr, "%s| %s: received type %d NTLM token\n",
-+                fprintf(stderr, "%s| %s: WARNING: received type %d NTLM token\n",
-                         LogTime(), PROGRAM,
-                         (int) *((unsigned char *) input_token.value +
-                                 sizeof ntlmProtocol));
-@@ -462,7 +462,7 @@
-             token = (char*)xmalloc(ska_base64_encode_len(spnegoTokenLength));
-             if (token == NULL) {
-                 if (debug)
--                    fprintf(stderr, "%s| %s: Not enough memory\n", LogTime(),
-+                    fprintf(stderr, "%s| %s: ERROR: Not enough memory\n", LogTime(),
-                             PROGRAM);
-                 fprintf(stdout, "BH Not enough memory\n");
-                 goto cleanup;
-@@ -476,7 +476,7 @@
-                 goto cleanup;
-             if (major_status & GSS_S_CONTINUE_NEEDED) {
-                 if (debug)
--                    fprintf(stderr, "%s| %s: continuation needed\n", LogTime(),
-+                    fprintf(stderr, "%s| %s: INFO: continuation needed\n", LogTime(),
-                             PROGRAM);
-                 fprintf(stdout, "TT %s\n", token);
-                 goto cleanup;
-@@ -492,7 +492,7 @@
-             user = (char*)xmalloc(output_token.length + 1);
-             if (user == NULL) {
-                 if (debug)
--                    fprintf(stderr, "%s| %s: Not enough memory\n", LogTime(),
-+                    fprintf(stderr, "%s| %s: ERROR: Not enough memory\n", LogTime(),
-                             PROGRAM);
-                 fprintf(stdout, "BH Not enough memory\n");
-                 goto cleanup;
-@@ -504,10 +504,10 @@
-             }
-             fprintf(stdout, "AF %s %s\n", token, user);
-             if (debug)
--                fprintf(stderr, "%s| %s: AF %s %s\n", LogTime(), PROGRAM, token,
-+                fprintf(stderr, "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, token,
-                         user);
-             if (log)
--                fprintf(stderr, "%s| %s: User %s authenticated\n", LogTime(),
-+                fprintf(stderr, "%s| %s: INFO: User %s authenticated\n", LogTime(),
-                         PROGRAM, user);
-             goto cleanup;
-         } else {
-@@ -516,7 +516,7 @@
-                 goto cleanup;
-             if (major_status & GSS_S_CONTINUE_NEEDED) {
-                 if (debug)
--                    fprintf(stderr, "%s| %s: continuation needed\n", LogTime(),
-+                    fprintf(stderr, "%s| %s: INFO: continuation needed\n", LogTime(),
-                             PROGRAM);
-                 fprintf(stdout, "NA %s\n", token);
-                 goto cleanup;
-@@ -535,7 +535,7 @@
-             user = (char*)xmalloc(output_token.length + 1);
-             if (user == NULL) {
-                 if (debug)
--                    fprintf(stderr, "%s| %s: Not enough memory\n", LogTime(),
-+                    fprintf(stderr, "%s| %s: ERROR: Not enough memory\n", LogTime(),
-                             PROGRAM);
-                 fprintf(stdout, "BH Not enough memory\n");
-                 goto cleanup;
-@@ -547,10 +547,10 @@
-             }
-             fprintf(stdout, "AF %s %s\n", "AA==", user);
-             if (debug)
--                fprintf(stderr, "%s| %s: AF %s %s\n", LogTime(), PROGRAM,
-+                fprintf(stderr, "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM,
-                         "AA==", user);
-             if (log)
--                fprintf(stderr, "%s| %s: User %s authenticated\n", LogTime(),
-+                fprintf(stderr, "%s| %s: INFO: User %s authenticated\n", LogTime(),
-                         PROGRAM, user);
- 
-         }
diff -Nur squid-3/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth-new.cc squid-3-krb5/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth-new.cc
--- squid-3/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth-new.cc	2010-02-09 19:16:03.000000000 +0000
+++ squid-3-krb5/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth-new.cc	1970-01-01 01:00:00.000000000 +0100
@@ -1,608 +0,0 @@
-/*
- * -----------------------------------------------------------------------------
- *
- * 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"
-
-#if HAVE_GSSAPI
-
-#if HAVE_STRING_H
-#include <string.h>
-#endif
-#if HAVE_STDOI_H
-#include <stdio.h>
-#endif
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#if HAVE_TIME_H
-#include <time.h>
-#endif
-#if HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#include "util.h"
-#include "base64.h"
-#include "getaddrinfo.h"
-#include "getnameinfo.h"
-
-#if HAVE_GSSAPI_GSSAPI_H
-#include <gssapi/gssapi.h>
-#elif HAVE_GSSAPI_H
-#include <gssapi.h>
-#endif /* HAVE_GSSAPI_GSSAPI_H */
-#if HAVE_GSSAPI_GSSAPI_KRB5_H
-#include <gssapi/gssapi_krb5.h>
-#endif /* HAVE_GSSAPI_GSSAPI_KRB5_H */
-#if HAVE_GSSAPI_GSSAPI_GENERIC_H
-#include <gssapi/gssapi_generic.h>
-#endif /* HAVE_GSSAPI_GSSAPI_GENERIC_H */
-#ifndef gss_nt_service_name
-#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
-#endif
-
-#define PROGRAM "negotiate_kerberos_auth"
-
-#ifndef MAX_AUTHTOKEN_LEN
-#define MAX_AUTHTOKEN_LEN   65535
-#endif
-#ifndef SQUID_KERB_AUTH_VERSION
-#define SQUID_KERB_AUTH_VERSION "3.0.2sq"
-#endif
-
-int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status,
-                  const char *function, int debug, int log);
-char *gethost_name(void);
-static const char *LogTime(void);
-
-static const unsigned char ntlmProtocol[] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', 0 };
-
-static 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((time_t *) & now.tv_sec);
-        strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
-        last_t = now.tv_sec;
-    }
-    return buf;
-}
-
-char *
-gethost_name(void)
-{
-    /*
-        char hostname[sysconf(_SC_HOST_NAME_MAX)];
-    */
-    char hostname[1024];
-    struct addrinfo *hres = NULL, *hres_list;
-    int rc, count;
-
-    rc = gethostname(hostname, sysconf(_SC_HOST_NAME_MAX));
-    if (rc) {
-        fprintf(stderr, "%s| %s: ERROR: resolving hostname '%s' failed\n",
-                LogTime(), PROGRAM, hostname);
-        return NULL;
-    }
-    rc = xgetaddrinfo(hostname, NULL, NULL, &hres);
-    if (rc != 0) {
-        fprintf(stderr,
-                "%s| %s: ERROR: resolving hostname with getaddrinfo: %s failed\n",
-                LogTime(), PROGRAM, xgai_strerror(rc));
-        return NULL;
-    }
-    hres_list = hres;
-    count = 0;
-    while (hres_list) {
-        count++;
-        hres_list = hres_list->ai_next;
-    }
-    rc = xgetnameinfo(hres->ai_addr, hres->ai_addrlen, hostname,
-                      sizeof(hostname), NULL, 0, 0);
-    if (rc != 0) {
-        fprintf(stderr,
-                "%s| %s: ERROR: resolving ip address with getnameinfo: %s failed\n",
-                LogTime(), PROGRAM, xgai_strerror(rc));
-        xfreeaddrinfo(hres);
-        return NULL;
-    }
-
-    xfreeaddrinfo(hres);
-    hostname[sysconf(_SC_HOST_NAME_MAX) - 1] = '\0';
-    return (xstrdup(hostname));
-}
-
-int
-check_gss_err(OM_uint32 major_status, OM_uint32 minor_status,
-              const char *function, int debug, int log)
-{
-    if (GSS_ERROR(major_status)) {
-        OM_uint32 maj_stat, min_stat;
-        OM_uint32 msg_ctx = 0;
-        gss_buffer_desc status_string;
-        char buf[1024];
-        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) {
-                if (sizeof(buf) > len + status_string.length + 1) {
-                    sprintf(buf + 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);
-        }
-        if (sizeof(buf) > len + 2) {
-            sprintf(buf + 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) {
-                if (sizeof(buf) > len + status_string.length) {
-                    sprintf(buf + 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);
-        }
-        if (debug)
-            fprintf(stderr, "%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(),
-                    PROGRAM);
-        return (1);
-    }
-    return (0);
-}
-
-
-
-int
-main(int argc, char *const argv[])
-{
-    char buf[MAX_AUTHTOKEN_LEN];
-    char *c, *p;
-    char *user = NULL;
-    int length = 0;
-    static int err = 0;
-    int opt, debug = 0, log = 0, norealm = 0;
-    OM_uint32 ret_flags = 0, spnego_flag = 0;
-    char *service_name = (char *) "HTTP", *host_name = NULL;
-    char *token = NULL;
-    char *service_principal = NULL;
-    OM_uint32 major_status, minor_status;
-    gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
-    gss_name_t client_name = GSS_C_NO_NAME;
-    gss_name_t server_name = GSS_C_NO_NAME;
-    gss_cred_id_t server_creds = GSS_C_NO_CREDENTIAL;
-    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;
-    const unsigned char *kerberosToken = NULL;
-    const unsigned char *spnegoToken = NULL;
-    size_t spnegoTokenLength = 0;
-
-    setbuf(stdout, NULL);
-    setbuf(stdin, NULL);
-
-    while (-1 != (opt = getopt(argc, argv, "dirs:h"))) {
-        switch (opt) {
-        case 'd':
-            debug = 1;
-            break;
-        case 'i':
-            log = 1;
-            break;
-        case 'r':
-            norealm = 1;
-            break;
-        case 's':
-            service_principal = xstrdup(optarg);
-            break;
-        case 'h':
-            fprintf(stderr, "Usage: \n");
-            fprintf(stderr, "squid_kerb_auth [-d] [-i] [-s SPN] [-h]\n");
-            fprintf(stderr, "-d full debug\n");
-            fprintf(stderr, "-i informational messages\n");
-            fprintf(stderr, "-r remove realm from username\n");
-            fprintf(stderr, "-s service principal name\n");
-            fprintf(stderr, "-h help\n");
-            fprintf(stderr,
-                    "The SPN can be set to GSS_C_NO_NAME to allow any entry from keytab\n");
-            fprintf(stderr, "default SPN is HTTP/fqdn@DEFAULT_REALM\n");
-            exit(0);
-        default:
-            fprintf(stderr, "%s| %s: WARNING: unknown option: -%c.\n", LogTime(),
-                    PROGRAM, opt);
-        }
-    }
-
-    if (debug)
-        fprintf(stderr, "%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);
-    } else {
-        host_name = gethost_name();
-        if (!host_name) {
-            fprintf(stderr,
-                    "%s| %s: FATAL: Local hostname could not be determined. Please specify the service principal\n",
-                    LogTime(), PROGRAM);
-            fprintf(stdout, "BH hostname error\n");
-            exit(-1);
-        }
-        service.value = xmalloc(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)) {
-                if (debug)
-                    fprintf(stderr,
-                            "%s| %s: FATAL: fgets() failed! dying..... errno=%d (%s)\n",
-                            LogTime(), PROGRAM, ferror(stdin),
-                            strerror(ferror(stdin)));
-
-                fprintf(stdout, "BH input error\n");
-                exit(1);	/* BIIG buffer */
-            }
-            fprintf(stdout, "BH input error\n");
-            exit(0);
-        }
-
-        c = (char*)memchr(buf, '\n', sizeof(buf) - 1);
-        if (c) {
-            *c = '\0';
-            length = c - buf;
-        } else {
-            err = 1;
-        }
-        if (err) {
-            if (debug)
-                fprintf(stderr, "%s| %s: ERROR: Oversized message\n", LogTime(),
-                        PROGRAM);
-            fprintf(stdout, "BH Oversized message\n");
-            err = 0;
-            continue;
-        }
-
-        if (debug)
-            fprintf(stderr, "%s| %s: DEBUG: Got '%s' from squid (length: %d).\n",
-                    LogTime(), PROGRAM, buf, length);
-
-        if (buf[0] == '\0') {
-            if (debug)
-                fprintf(stderr, "%s| %s: ERROR: Invalid request\n", LogTime(),
-                        PROGRAM);
-            fprintf(stdout, "BH Invalid request\n");
-            continue;
-        }
-
-        if (strlen(buf) < 2) {
-            if (debug)
-                fprintf(stderr, "%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);
-            gss_release_buffer(&minor_status, &service);
-            gss_release_cred(&minor_status, &server_creds);
-            if (server_name)
-                gss_release_name(&minor_status, &server_name);
-            if (client_name)
-                gss_release_name(&minor_status, &client_name);
-            if (gss_context != GSS_C_NO_CONTEXT)
-                gss_delete_sec_context(&minor_status, &gss_context, NULL);
-            if (kerberosToken) {
-                /* Allocated by parseNegTokenInit, but no matching free function exists.. */
-                if (!spnego_flag)
-                    xfree((char *) kerberosToken);
-                kerberosToken = NULL;
-            }
-            if (spnego_flag) {
-                /* Allocated by makeNegTokenTarg, but no matching free function exists.. */
-                if (spnegoToken)
-                    xfree((char *) spnegoToken);
-                spnegoToken = NULL;
-            }
-            if (token) {
-                xfree(token);
-                token = NULL;
-            }
-            if (host_name) {
-                xfree(host_name);
-                host_name = NULL;
-            }
-            fprintf(stdout, "BH quit command\n");
-            exit(0);
-        }
-
-        if (strncmp(buf, "YR", 2) && strncmp(buf, "KK", 2)) {
-            if (debug)
-                fprintf(stderr, "%s| %s: ERROR: Invalid request [%s]\n", LogTime(),
-                        PROGRAM, buf);
-            fprintf(stdout, "BH Invalid request\n");
-            continue;
-        }
-        if (!strncmp(buf, "YR", 2)) {
-            if (gss_context != GSS_C_NO_CONTEXT)
-                gss_delete_sec_context(&minor_status, &gss_context, NULL);
-            gss_context = GSS_C_NO_CONTEXT;
-        }
-
-        if (strlen(buf) <= 3) {
-            if (debug)
-                fprintf(stderr, "%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);
-        if (debug)
-            fprintf(stderr, "%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);
-
-
-        if ((input_token.length >= sizeof ntlmProtocol + 1) &&
-                (!memcmp(input_token.value, ntlmProtocol, sizeof ntlmProtocol))) {
-            if (debug)
-                fprintf(stderr, "%s| %s: WARNING: received type %d NTLM token\n",
-                        LogTime(), PROGRAM,
-                        (int) *((unsigned char *) input_token.value +
-                                sizeof ntlmProtocol));
-            fprintf(stdout, "BH received type %d NTLM token\n",
-                    (int) *((unsigned char *) input_token.value +
-                            sizeof ntlmProtocol));
-            goto cleanup;
-        }
-
-        if (service_principal) {
-            if (strcasecmp(service_principal, "GSS_C_NO_NAME")) {
-                major_status = gss_import_name(&minor_status, &service,
-                                               (gss_OID) GSS_C_NULL_OID, &server_name);
-
-            } else {
-                server_name = GSS_C_NO_NAME;
-                major_status = GSS_S_COMPLETE;
-            }
-        } else {
-            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()",
-                          debug, log))
-            goto cleanup;
-
-        major_status =
-            gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
-                             GSS_C_NO_OID_SET, GSS_C_ACCEPT, &server_creds, NULL, NULL);
-        if (check_gss_err(major_status, minor_status, "gss_acquire_cred()",
-                          debug, log))
-            goto cleanup;
-
-        major_status = gss_accept_sec_context(&minor_status,
-                                              &gss_context,
-                                              server_creds,
-                                              &input_token,
-                                              GSS_C_NO_CHANNEL_BINDINGS,
-                                              &client_name, NULL, &output_token, &ret_flags, NULL, NULL);
-
-
-        if (output_token.length) {
-            spnegoToken = (const unsigned char*)output_token.value;
-            spnegoTokenLength = output_token.length;
-            token = (char*)xmalloc(ska_base64_encode_len(spnegoTokenLength));
-            if (token == NULL) {
-                if (debug)
-                    fprintf(stderr, "%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()", debug, log))
-                goto cleanup;
-            if (major_status & GSS_S_CONTINUE_NEEDED) {
-                if (debug)
-                    fprintf(stderr, "%s| %s: INFO: continuation needed\n", LogTime(),
-                            PROGRAM);
-                fprintf(stdout, "TT %s\n", token);
-                goto cleanup;
-            }
-            gss_release_buffer(&minor_status, &output_token);
-            major_status =
-                gss_display_name(&minor_status, client_name, &output_token,
-                                 NULL);
-
-            if (check_gss_err(major_status, minor_status, "gss_display_name()",
-                              debug, log))
-                goto cleanup;
-            user = (char*)xmalloc(output_token.length + 1);
-            if (user == NULL) {
-                if (debug)
-                    fprintf(stderr, "%s| %s: ERROR: Not enough memory\n", LogTime(),
-                            PROGRAM);
-                fprintf(stdout, "BH Not enough memory\n");
-                goto cleanup;
-            }
-            memcpy(user, output_token.value, output_token.length);
-            user[output_token.length] = '\0';
-            if (norealm && (p = strchr(user, '@')) != NULL) {
-                *p = '\0';
-            }
-            fprintf(stdout, "AF %s %s\n", token, user);
-            if (debug)
-                fprintf(stderr, "%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);
-            goto cleanup;
-        } else {
-            if (check_gss_err(major_status, minor_status,
-                              "gss_accept_sec_context()", debug, log))
-                goto cleanup;
-            if (major_status & GSS_S_CONTINUE_NEEDED) {
-                if (debug)
-                    fprintf(stderr, "%s| %s: INFO: continuation needed\n", LogTime(),
-                            PROGRAM);
-                fprintf(stdout, "NA %s\n", token);
-                goto cleanup;
-            }
-            gss_release_buffer(&minor_status, &output_token);
-            major_status =
-                gss_display_name(&minor_status, client_name, &output_token,
-                                 NULL);
-
-            if (check_gss_err(major_status, minor_status, "gss_display_name()",
-                              debug, log))
-                goto cleanup;
-            /*
-             *  Return dummy token AA. May need an extra return tag then AF
-             */
-            user = (char*)xmalloc(output_token.length + 1);
-            if (user == NULL) {
-                if (debug)
-                    fprintf(stderr, "%s| %s: ERROR: Not enough memory\n", LogTime(),
-                            PROGRAM);
-                fprintf(stdout, "BH Not enough memory\n");
-                goto cleanup;
-            }
-            memcpy(user, output_token.value, output_token.length);
-            user[output_token.length] = '\0';
-            if (norealm && (p = strchr(user, '@')) != NULL) {
-                *p = '\0';
-            }
-            fprintf(stdout, "AF %s %s\n", "AA==", user);
-            if (debug)
-                fprintf(stderr, "%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);
-
-        }
-cleanup:
-        gss_release_buffer(&minor_status, &input_token);
-        gss_release_buffer(&minor_status, &output_token);
-        gss_release_cred(&minor_status, &server_creds);
-        if (server_name)
-            gss_release_name(&minor_status, &server_name);
-        if (client_name)
-            gss_release_name(&minor_status, &client_name);
-        if (kerberosToken) {
-            /* Allocated by parseNegTokenInit, but no matching free function exists.. */
-            if (!spnego_flag)
-                xfree((char *) kerberosToken);
-            kerberosToken = NULL;
-        }
-        if (spnego_flag) {
-            /* Allocated by makeNegTokenTarg, but no matching free function exists.. */
-            if (spnegoToken)
-                xfree((char *) spnegoToken);
-            spnegoToken = NULL;
-        }
-        if (token) {
-            xfree(token);
-            token = NULL;
-        }
-        if (user) {
-            xfree(user);
-            user = NULL;
-        }
-        continue;
-    }
-}
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef MAX_AUTHTOKEN_LEN
-#define MAX_AUTHTOKEN_LEN   65535
-#endif
-int
-main(int argc, char *const argv[])
-{
-    setbuf(stdout, NULL);
-    setbuf(stdin, NULL);
-    char buf[MAX_AUTHTOKEN_LEN];
-    while (1) {
-        if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
-            fprintf(stdout, "BH input error\n");
-            exit(0);
-        }
-        fprintf(stdout, "BH Kerberos authentication not supported\n");
-    }
-}
-#endif /* HAVE_GSSAPI */

