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 -#elif HAVE_GSSAPI_H +#elif defined(HAVE_GSSAPI_H) #include #endif - -#ifdef HAVE_GSSAPI_GSSAPI_EXT_H -#include +#else +#ifdef HAVE_GSSAPI_GSSAPI_H +#include +#elif defined(HAVE_GSSAPI_H) +#include #endif - #ifdef HAVE_GSSAPI_GSSAPI_KRB5_H #include #endif - #ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H #include #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 ]) 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 +#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 ],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 +#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 +#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 ]) + +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: +# .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 < 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. + + + Copyright (C) 19yy + + 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. + + , 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 +#include + +#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 or -t @ 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 @ 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 +#include +#include +#include +#include + +#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 +#elif defined(HAVE_GSSAPI_H) +#include +#endif +#ifdef HAVE_KRB5_H +#include +#endif +#ifdef HAVE_COM_ERR_H +#include +#else +#define error_message(code) krb5_get_err_text(kparam.context,code) +#endif +#else /*MIT */ +#ifdef HAVE_GSSAPI_GSSAPI_H +#include +#elif defined(HAVE_GSSAPI_H) +#include +#endif +#ifdef HAVE_GSSAPI_GSSAPI_KRB5_H +#include +#endif +#ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H +#include +#endif +#ifdef HAVE_GSSAPI_GSSAPI_EXT_H +#include +#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 +#endif +#ifdef HAVE_COM_ERR_H +#include +#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 +#endif +#ifdef HAVE_LDAP_H +#include +#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 +#include +#include +#include + +#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 +#include +#include + +#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 . + * + * 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 + * . + */ + + 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 +#include +#include +#include +#include +#include + +#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 +#elif defined(HAVE_SASL_SASL_H) +#include +#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 +#include + +#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 127 ) + c++; + if ( c != 0 ) { + p = xmalloc(strlen(src)+c); + dup = p; + for (n=0;n 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 +#include +#include +#include + +#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;idebug) + 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 +#include +#include + +#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;jAD) + 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;jdebug) + 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;jdebug) + 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 . + * + * 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 + * . + */ + + 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;idebug) + 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;idebug) + 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;jdebug) + 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;jAD) { + 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;jdebug) + 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;jdebug) + 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 +#include +#include +#include +#include +#include + +#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;iai_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;idebug) { + fprintf(stderr, "%s| %s: Sorted ldap server names for domain %s:\n",LogTime(), PROGRAM,domain); + for (i=0;i +#elif defined(HAVE_SASL_SASL_H) +#include +#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 -#endif -#if HAVE_STDOI_H -#include -#endif -#if HAVE_STDLIB_H -#include -#endif -#if HAVE_NETDB_H -#include -#endif -#if HAVE_UNISTD_H -#include -#endif -#if HAVE_TIME_H -#include -#endif -#if HAVE_SYS_TIME_H -#include -#endif - -#include "util.h" -#include "base64.h" -#include "getaddrinfo.h" -#include "getnameinfo.h" - -#if HAVE_GSSAPI_GSSAPI_H -#include -#elif HAVE_GSSAPI_H -#include -#endif /* HAVE_GSSAPI_GSSAPI_H */ -#if HAVE_GSSAPI_GSSAPI_KRB5_H -#include -#endif /* HAVE_GSSAPI_GSSAPI_KRB5_H */ -#if HAVE_GSSAPI_GSSAPI_GENERIC_H -#include -#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 -#include -#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 */