From: hno <> Date: Mon, 25 Jun 2007 04:34:15 +0000 (+0000) Subject: Author: Markus Moeller X-Git-Tag: SQUID_3_0_PRE7~201 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3e5d7cdf22bea10b5f35fd5881ed2d1724ba88b2;p=thirdparty%2Fsquid.git Author: Markus Moeller Kerberos SPNEGO helper Kerberos-only SPNEGO helper using MIT or Heimdal kerberos and the refrence SPNEGO parser published by Microsoft --- diff --git a/configure.in b/configure.in index 8194690736..14a2bfa41e 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ dnl Configuration input file for Squid dnl -dnl $Id: configure.in,v 1.459 2007/06/23 20:50:10 hno Exp $ +dnl $Id: configure.in,v 1.460 2007/06/24 22:34:15 hno Exp $ dnl dnl dnl @@ -11,7 +11,7 @@ AM_CONFIG_HEADER(include/autoconf.h) AC_CONFIG_AUX_DIR(cfgaux) AC_CONFIG_SRCDIR([src/main.cc]) AM_INIT_AUTOMAKE([tar-ustar]) -AC_REVISION($Revision: 1.459 $)dnl +AC_REVISION($Revision: 1.460 $)dnl AC_PREFIX_DEFAULT(/usr/local/squid) AM_MAINTAINER_MODE @@ -3368,6 +3368,7 @@ AC_CONFIG_FILES([\ helpers/ntlm_auth/mswin_sspi/Makefile \ helpers/negotiate_auth/Makefile \ helpers/negotiate_auth/mswin_sspi/Makefile \ + helpers/negotiate_auth/squid_kerb_auth/Makefile \ helpers/external_acl/Makefile \ helpers/external_acl/ip_user/Makefile \ helpers/external_acl/ldap_group/Makefile \ diff --git a/helpers/negotiate_auth/Makefile.am b/helpers/negotiate_auth/Makefile.am index a3c9e1e58d..5aa64c4fb9 100755 --- a/helpers/negotiate_auth/Makefile.am +++ b/helpers/negotiate_auth/Makefile.am @@ -1,7 +1,7 @@ # Makefile for negotiate authentication helpers in the Squid Object Cache server # -# $Id: Makefile.am,v 1.1 2005/10/30 21:48:21 serassio Exp $ +# $Id: Makefile.am,v 1.2 2007/06/24 22:34:15 hno Exp $ # -DIST_SUBDIRS = mswin_sspi +DIST_SUBDIRS = mswin_sspi squid_kerb_auth SUBDIRS = @NEGOTIATE_AUTH_HELPERS@ diff --git a/helpers/negotiate_auth/squid_kerb_auth/COPYING b/helpers/negotiate_auth/squid_kerb_auth/COPYING new file mode 100644 index 0000000000..12d74e6cbb --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/COPYING @@ -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 --git a/helpers/negotiate_auth/squid_kerb_auth/Makefile.am b/helpers/negotiate_auth/squid_kerb_auth/Makefile.am new file mode 100755 index 0000000000..44908bc521 --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/Makefile.am @@ -0,0 +1,27 @@ +# +# Makefile for the Squid Object Cache server +# +# $Id: Makefile.am,v 1.1 2007/06/24 22:34:15 hno Exp $ +# + +libexec_PROGRAMS = squid_kerb_auth + +SPNEGO = spnegohelp/derparse.c spnegohelp/derparse.h spnegohelp/Makefile spnegohelp/spnego.c spnegohelp/spnego.h spnegohelp/spnegohelp.c spnegohelp/spnegohelp.h spnegohelp/spnegoparse.c spnegohelp/spnegoparse.h +SOURCE = squid_kerb_auth.c base64.c base64.h +EXTRA_DIST = readme.txt do.sh + +squid_kerb_auth_SOURCES = $(SOURCE) $(SPNEGO) + +CPPFLAGS = $(KERBINC) -I$(srcdir)/spnegohelp -I. +#-I$(top_srcdir)/include -I$(top_srcdir)/src +LDADD = $(KERBLIBS) +#-L$(top_builddir)/lib -lmiscutil $(XTRA_LIBS) + +# HEIMDAL +#KERBINC = -DHEIMDAL -I/usr/include/heimdal +#KERBLIBS = -lgssapi -lkrb5 -lcom_err -lasn1 -lroken + +# MIT +KERBINC = +KERBLIBS = -lgssapi_krb5 -lkrb5 -lcom_err + diff --git a/helpers/negotiate_auth/squid_kerb_auth/Makefile.in b/helpers/negotiate_auth/squid_kerb_auth/Makefile.in new file mode 100644 index 0000000000..09852b1843 --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/Makefile.in @@ -0,0 +1,586 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Makefile for the Squid Object Cache server +# +# $Id: Makefile.in,v 1.1 2007/06/24 22:34:15 hno Exp $ +# + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +libexec_PROGRAMS = squid_kerb_auth$(EXEEXT) +subdir = helpers/negotiate_auth/squid_kerb_auth +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in COPYING +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/autoconf.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(libexecdir)" +libexecPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(libexec_PROGRAMS) +am__objects_1 = squid_kerb_auth.$(OBJEXT) base64.$(OBJEXT) +am__objects_2 = derparse.$(OBJEXT) spnego.$(OBJEXT) \ + spnegohelp.$(OBJEXT) spnegoparse.$(OBJEXT) +am_squid_kerb_auth_OBJECTS = $(am__objects_1) $(am__objects_2) +squid_kerb_auth_OBJECTS = $(am_squid_kerb_auth_OBJECTS) +squid_kerb_auth_LDADD = $(LDADD) +am__DEPENDENCIES_1 = +squid_kerb_auth_DEPENDENCIES = $(am__DEPENDENCIES_1) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/cfgaux/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(squid_kerb_auth_SOURCES) +DIST_SOURCES = $(squid_kerb_auth_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AR_R = @AR_R@ +AUTH_LIBS = @AUTH_LIBS@ +AUTH_MODULES = @AUTH_MODULES@ +AUTH_OBJS = @AUTH_OBJS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASIC_AUTH_HELPERS = @BASIC_AUTH_HELPERS@ +CACHE_HTTP_PORT = @CACHE_HTTP_PORT@ +CACHE_ICP_PORT = @CACHE_ICP_PORT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CGIEXT = @CGIEXT@ +CPP = @CPP@ +CPPFLAGS = $(KERBINC) -I$(srcdir)/spnegohelp -I. +CRYPTLIB = @CRYPTLIB@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DIGEST_AUTH_HELPERS = @DIGEST_AUTH_HELPERS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_HTCP_FALSE = @ENABLE_HTCP_FALSE@ +ENABLE_HTCP_TRUE = @ENABLE_HTCP_TRUE@ +ENABLE_MINGW32SPECIFIC_FALSE = @ENABLE_MINGW32SPECIFIC_FALSE@ +ENABLE_MINGW32SPECIFIC_TRUE = @ENABLE_MINGW32SPECIFIC_TRUE@ +ENABLE_PINGER_FALSE = @ENABLE_PINGER_FALSE@ +ENABLE_PINGER_TRUE = @ENABLE_PINGER_TRUE@ +ENABLE_SSL_FALSE = @ENABLE_SSL_FALSE@ +ENABLE_SSL_TRUE = @ENABLE_SSL_TRUE@ +ENABLE_UNLINKD_FALSE = @ENABLE_UNLINKD_FALSE@ +ENABLE_UNLINKD_TRUE = @ENABLE_UNLINKD_TRUE@ +ENABLE_WIN32SPECIFIC_FALSE = @ENABLE_WIN32SPECIFIC_FALSE@ +ENABLE_WIN32SPECIFIC_TRUE = @ENABLE_WIN32SPECIFIC_TRUE@ +ERR_DEFAULT_LANGUAGE = @ERR_DEFAULT_LANGUAGE@ +ERR_LANGUAGES = @ERR_LANGUAGES@ +EXEEXT = @EXEEXT@ +EXTERNAL_ACL_HELPERS = @EXTERNAL_ACL_HELPERS@ +FALSE = @FALSE@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBDLMALLOC = @LIBDLMALLOC@ +LIBOBJS = @LIBOBJS@ +LIBREGEX = @LIBREGEX@ +LIBS = @LIBS@ +LIBSASL = @LIBSASL@ +LIB_DB = @LIB_DB@ +LIB_EPOLL = @LIB_EPOLL@ +LIB_LBER = @LIB_LBER@ +LIB_LDAP = @LIB_LDAP@ +LIB_MALLOC = @LIB_MALLOC@ +LN = @LN@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +MAKE_LEAKFINDER_FALSE = @MAKE_LEAKFINDER_FALSE@ +MAKE_LEAKFINDER_TRUE = @MAKE_LEAKFINDER_TRUE@ +MKDIR = @MKDIR@ +MV = @MV@ +NEED_COSSDUMP_FALSE = @NEED_COSSDUMP_FALSE@ +NEED_COSSDUMP_TRUE = @NEED_COSSDUMP_TRUE@ +NEED_DISKD_FALSE = @NEED_DISKD_FALSE@ +NEED_DISKD_TRUE = @NEED_DISKD_TRUE@ +NEED_OWN_MD5_FALSE = @NEED_OWN_MD5_FALSE@ +NEED_OWN_MD5_TRUE = @NEED_OWN_MD5_TRUE@ +NEED_OWN_SNPRINTF_FALSE = @NEED_OWN_SNPRINTF_FALSE@ +NEED_OWN_SNPRINTF_TRUE = @NEED_OWN_SNPRINTF_TRUE@ +NEED_OWN_STRSEP_FALSE = @NEED_OWN_STRSEP_FALSE@ +NEED_OWN_STRSEP_TRUE = @NEED_OWN_STRSEP_TRUE@ +NEGOTIATE_AUTH_HELPERS = @NEGOTIATE_AUTH_HELPERS@ +NTLM_AUTH_HELPERS = @NTLM_AUTH_HELPERS@ +OBJEXT = @OBJEXT@ +OPT_DEFAULT_HOSTS = @OPT_DEFAULT_HOSTS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKGCONFIG = @PKGCONFIG@ +RANLIB = @RANLIB@ +REGEXLIB = @REGEXLIB@ +REPL_LIBS = @REPL_LIBS@ +REPL_OBJS = @REPL_OBJS@ +REPL_POLICIES = @REPL_POLICIES@ +RM = @RM@ +SET_MAKE = @SET_MAKE@ +SH = @SH@ +SHELL = @SHELL@ +SNMPLIB = @SNMPLIB@ +SSLLIB = @SSLLIB@ +STORE_LIBS = @STORE_LIBS@ +STORE_MODULES = @STORE_MODULES@ +STORE_OBJS = @STORE_OBJS@ +STRIP = @STRIP@ +TRUE = @TRUE@ +USE_AIOPS_WIN32_FALSE = @USE_AIOPS_WIN32_FALSE@ +USE_AIOPS_WIN32_TRUE = @USE_AIOPS_WIN32_TRUE@ +USE_DELAY_POOLS_FALSE = @USE_DELAY_POOLS_FALSE@ +USE_DELAY_POOLS_TRUE = @USE_DELAY_POOLS_TRUE@ +USE_DEVPOLL_FALSE = @USE_DEVPOLL_FALSE@ +USE_DEVPOLL_TRUE = @USE_DEVPOLL_TRUE@ +USE_DNSSERVER_FALSE = @USE_DNSSERVER_FALSE@ +USE_DNSSERVER_TRUE = @USE_DNSSERVER_TRUE@ +USE_EPOLL_FALSE = @USE_EPOLL_FALSE@ +USE_EPOLL_TRUE = @USE_EPOLL_TRUE@ +USE_KQUEUE_FALSE = @USE_KQUEUE_FALSE@ +USE_KQUEUE_TRUE = @USE_KQUEUE_TRUE@ +USE_POLL_FALSE = @USE_POLL_FALSE@ +USE_POLL_TRUE = @USE_POLL_TRUE@ +USE_SELECT_FALSE = @USE_SELECT_FALSE@ +USE_SELECT_SIMPLE_FALSE = @USE_SELECT_SIMPLE_FALSE@ +USE_SELECT_SIMPLE_TRUE = @USE_SELECT_SIMPLE_TRUE@ +USE_SELECT_TRUE = @USE_SELECT_TRUE@ +USE_SELECT_WIN32_FALSE = @USE_SELECT_WIN32_FALSE@ +USE_SELECT_WIN32_TRUE = @USE_SELECT_WIN32_TRUE@ +USE_SNMP_FALSE = @USE_SNMP_FALSE@ +USE_SNMP_TRUE = @USE_SNMP_TRUE@ +VERSION = @VERSION@ +WIN32_PSAPI = @WIN32_PSAPI@ +XTRA_LIBS = @XTRA_LIBS@ +XTRA_OBJS = @XTRA_OBJS@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +makesnmplib = @makesnmplib@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +SPNEGO = spnegohelp/derparse.c spnegohelp/derparse.h spnegohelp/Makefile spnegohelp/spnego.c spnegohelp/spnego.h spnegohelp/spnegohelp.c spnegohelp/spnegohelp.h spnegohelp/spnegoparse.c spnegohelp/spnegoparse.h +SOURCE = squid_kerb_auth.c base64.c base64.h +EXTRA_DIST = readme.txt do.sh +squid_kerb_auth_SOURCES = $(SOURCE) $(SPNEGO) +#-I$(top_srcdir)/include -I$(top_srcdir)/src +LDADD = $(KERBLIBS) +#-L$(top_builddir)/lib -lmiscutil $(XTRA_LIBS) + +# HEIMDAL +#KERBINC = -DHEIMDAL -I/usr/include/heimdal +#KERBLIBS = -lgssapi -lkrb5 -lcom_err -lasn1 -lroken + +# MIT +KERBINC = +KERBLIBS = -lgssapi_krb5 -lkrb5 -lcom_err +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign helpers/negotiate_auth/squid_kerb_auth/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign helpers/negotiate_auth/squid_kerb_auth/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libexecPROGRAMS: $(libexec_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(libexecdir)" || $(mkdir_p) "$(DESTDIR)$(libexecdir)" + @list='$(libexec_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(libexecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(libexecdir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(libexecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(libexecdir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-libexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(libexec_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(libexecdir)/$$f'"; \ + rm -f "$(DESTDIR)$(libexecdir)/$$f"; \ + done + +clean-libexecPROGRAMS: + -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) +squid_kerb_auth$(EXEEXT): $(squid_kerb_auth_OBJECTS) $(squid_kerb_auth_DEPENDENCIES) + @rm -f squid_kerb_auth$(EXEEXT) + $(LINK) $(squid_kerb_auth_LDFLAGS) $(squid_kerb_auth_OBJECTS) $(squid_kerb_auth_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/derparse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spnego.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spnegohelp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spnegoparse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/squid_kerb_auth.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +derparse.o: spnegohelp/derparse.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT derparse.o -MD -MP -MF "$(DEPDIR)/derparse.Tpo" -c -o derparse.o `test -f 'spnegohelp/derparse.c' || echo '$(srcdir)/'`spnegohelp/derparse.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/derparse.Tpo" "$(DEPDIR)/derparse.Po"; else rm -f "$(DEPDIR)/derparse.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='spnegohelp/derparse.c' object='derparse.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o derparse.o `test -f 'spnegohelp/derparse.c' || echo '$(srcdir)/'`spnegohelp/derparse.c + +derparse.obj: spnegohelp/derparse.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT derparse.obj -MD -MP -MF "$(DEPDIR)/derparse.Tpo" -c -o derparse.obj `if test -f 'spnegohelp/derparse.c'; then $(CYGPATH_W) 'spnegohelp/derparse.c'; else $(CYGPATH_W) '$(srcdir)/spnegohelp/derparse.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/derparse.Tpo" "$(DEPDIR)/derparse.Po"; else rm -f "$(DEPDIR)/derparse.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='spnegohelp/derparse.c' object='derparse.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o derparse.obj `if test -f 'spnegohelp/derparse.c'; then $(CYGPATH_W) 'spnegohelp/derparse.c'; else $(CYGPATH_W) '$(srcdir)/spnegohelp/derparse.c'; fi` + +spnego.o: spnegohelp/spnego.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spnego.o -MD -MP -MF "$(DEPDIR)/spnego.Tpo" -c -o spnego.o `test -f 'spnegohelp/spnego.c' || echo '$(srcdir)/'`spnegohelp/spnego.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/spnego.Tpo" "$(DEPDIR)/spnego.Po"; else rm -f "$(DEPDIR)/spnego.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='spnegohelp/spnego.c' object='spnego.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spnego.o `test -f 'spnegohelp/spnego.c' || echo '$(srcdir)/'`spnegohelp/spnego.c + +spnego.obj: spnegohelp/spnego.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spnego.obj -MD -MP -MF "$(DEPDIR)/spnego.Tpo" -c -o spnego.obj `if test -f 'spnegohelp/spnego.c'; then $(CYGPATH_W) 'spnegohelp/spnego.c'; else $(CYGPATH_W) '$(srcdir)/spnegohelp/spnego.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/spnego.Tpo" "$(DEPDIR)/spnego.Po"; else rm -f "$(DEPDIR)/spnego.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='spnegohelp/spnego.c' object='spnego.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spnego.obj `if test -f 'spnegohelp/spnego.c'; then $(CYGPATH_W) 'spnegohelp/spnego.c'; else $(CYGPATH_W) '$(srcdir)/spnegohelp/spnego.c'; fi` + +spnegohelp.o: spnegohelp/spnegohelp.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spnegohelp.o -MD -MP -MF "$(DEPDIR)/spnegohelp.Tpo" -c -o spnegohelp.o `test -f 'spnegohelp/spnegohelp.c' || echo '$(srcdir)/'`spnegohelp/spnegohelp.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/spnegohelp.Tpo" "$(DEPDIR)/spnegohelp.Po"; else rm -f "$(DEPDIR)/spnegohelp.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='spnegohelp/spnegohelp.c' object='spnegohelp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spnegohelp.o `test -f 'spnegohelp/spnegohelp.c' || echo '$(srcdir)/'`spnegohelp/spnegohelp.c + +spnegohelp.obj: spnegohelp/spnegohelp.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spnegohelp.obj -MD -MP -MF "$(DEPDIR)/spnegohelp.Tpo" -c -o spnegohelp.obj `if test -f 'spnegohelp/spnegohelp.c'; then $(CYGPATH_W) 'spnegohelp/spnegohelp.c'; else $(CYGPATH_W) '$(srcdir)/spnegohelp/spnegohelp.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/spnegohelp.Tpo" "$(DEPDIR)/spnegohelp.Po"; else rm -f "$(DEPDIR)/spnegohelp.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='spnegohelp/spnegohelp.c' object='spnegohelp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spnegohelp.obj `if test -f 'spnegohelp/spnegohelp.c'; then $(CYGPATH_W) 'spnegohelp/spnegohelp.c'; else $(CYGPATH_W) '$(srcdir)/spnegohelp/spnegohelp.c'; fi` + +spnegoparse.o: spnegohelp/spnegoparse.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spnegoparse.o -MD -MP -MF "$(DEPDIR)/spnegoparse.Tpo" -c -o spnegoparse.o `test -f 'spnegohelp/spnegoparse.c' || echo '$(srcdir)/'`spnegohelp/spnegoparse.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/spnegoparse.Tpo" "$(DEPDIR)/spnegoparse.Po"; else rm -f "$(DEPDIR)/spnegoparse.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='spnegohelp/spnegoparse.c' object='spnegoparse.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spnegoparse.o `test -f 'spnegohelp/spnegoparse.c' || echo '$(srcdir)/'`spnegohelp/spnegoparse.c + +spnegoparse.obj: spnegohelp/spnegoparse.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spnegoparse.obj -MD -MP -MF "$(DEPDIR)/spnegoparse.Tpo" -c -o spnegoparse.obj `if test -f 'spnegohelp/spnegoparse.c'; then $(CYGPATH_W) 'spnegohelp/spnegoparse.c'; else $(CYGPATH_W) '$(srcdir)/spnegohelp/spnegoparse.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/spnegoparse.Tpo" "$(DEPDIR)/spnegoparse.Po"; else rm -f "$(DEPDIR)/spnegoparse.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='spnegohelp/spnegoparse.c' object='spnegoparse.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spnegoparse.obj `if test -f 'spnegohelp/spnegoparse.c'; then $(CYGPATH_W) 'spnegohelp/spnegoparse.c'; else $(CYGPATH_W) '$(srcdir)/spnegohelp/spnegoparse.c'; fi` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(libexecdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-libexecPROGRAMS + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-libexecPROGRAMS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libexecPROGRAMS ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-libexecPROGRAMS install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-libexecPROGRAMS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/helpers/negotiate_auth/squid_kerb_auth/base64.c b/helpers/negotiate_auth/squid_kerb_auth/base64.c new file mode 100644 index 0000000000..475bcc8ca1 --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/base64.c @@ -0,0 +1,152 @@ +/* + * Markus Moeller has modified the following code from Squid + */ + +#include +#include +#include +#include "base64.h" + + +static void base64_init(void); + +static int base64_initialized = 0; +#define BASE64_VALUE_SZ 256 +int base64_value[BASE64_VALUE_SZ]; +const char base64_code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + +static void +base64_init(void) +{ + int i; + + for (i = 0; i < BASE64_VALUE_SZ; i++) + base64_value[i] = -1; + + for (i = 0; i < 64; i++) + base64_value[(int) base64_code[i]] = i; + base64_value['='] = 0; + + base64_initialized = 1; +} + +void base64_decode(char* result, const char *data, int result_size) +{ + int j; + int c; + long val; + if (!data) + return; + if (!base64_initialized) + base64_init(); + val = c = 0; + + for (j = 0; *data ;data++) { + unsigned int k = ((unsigned char) *data) % BASE64_VALUE_SZ; + if (base64_value[k] < 0) + continue; + val <<= 6; + val += base64_value[k]; + if (++c < 4) + continue; + /* One quantum of four encoding characters/24 bit */ + if (j >= result_size) + break; + result[j++] = val >> 16; /* High 8 bits */ + if (j >= result_size) + break; + result[j++] = (val >> 8) & 0xff; /* Mid 8 bits */ + if (j >= result_size) + break; + result[j++] = val & 0xff; /* Low 8 bits */ + val = c = 0; + } + return; +} + +/* adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments */ +void base64_encode(char* result, const char *data, int result_size, int data_size) +{ + int bits = 0; + int char_count = 0; + int out_cnt = 0; + + if (!data) + return; + + if (!base64_initialized) + base64_init(); + + while (data_size--) { + int c = (unsigned char) *data++; + bits += c; + char_count++; + if (char_count == 3) { + if (out_cnt >= result_size) + break; + result[out_cnt++] = base64_code[bits >> 18]; + if (out_cnt >= result_size) + break; + result[out_cnt++] = base64_code[(bits >> 12) & 0x3f]; + if (out_cnt >= result_size) + break; + result[out_cnt++] = base64_code[(bits >> 6) & 0x3f]; + if (out_cnt >= result_size) + break; + result[out_cnt++] = base64_code[bits & 0x3f]; + bits = 0; + char_count = 0; + } else { + bits <<= 8; + } + } + if (char_count != 0) { + bits <<= 16 - (8 * char_count); + if (out_cnt >= result_size) + goto end; + result[out_cnt++] = base64_code[bits >> 18]; + if (out_cnt >= result_size) + goto end; + result[out_cnt++] = base64_code[(bits >> 12) & 0x3f]; + if (char_count == 1) { + if (out_cnt >= result_size) + goto end; + result[out_cnt++] = '='; + if (out_cnt >= result_size) + goto end; + result[out_cnt++] = '='; + } else { + if (out_cnt >= result_size) + goto end; + result[out_cnt++] = base64_code[(bits >> 6) & 0x3f]; + if (out_cnt >= result_size) + goto end; + result[out_cnt++] = '='; + } + } +end: + if (out_cnt >= result_size) { + result[result_size-1] = '\0'; /* terminate */ + } else { + result[out_cnt] = '\0'; /* terminate */ + } + return; +} + +int base64_encode_len(int len) +{ + return ((len+2)/3*4)+1; +} + +int base64_decode_len(const char *data) +{ + int i,j; + + j=0; + for (i=strlen(data)-1;i>=0;i--) { + if (data[i] == '=') j++; + if (data[i] != '=') break; + } + return strlen(data)/4*3-j; +} diff --git a/helpers/negotiate_auth/squid_kerb_auth/base64.h b/helpers/negotiate_auth/squid_kerb_auth/base64.h new file mode 100644 index 0000000000..ebcb9bc1aa --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/base64.h @@ -0,0 +1,9 @@ +/* + * Markus Moeller has modified the following code from Squid + */ + +void base64_decode(char* result, const char *data, int result_size); +void base64_encode(char* result, const char *data, int result_size, int data_size); + +int base64_encode_len(int len); +int base64_decode_len(const char *data); diff --git a/helpers/negotiate_auth/squid_kerb_auth/do.sh b/helpers/negotiate_auth/squid_kerb_auth/do.sh new file mode 100755 index 0000000000..c245c8cb37 --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/do.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Linux: +# -D__LITTLE_ENDIAN__ +# Solaris: +# -D__BIG_ENDIAN__ +# +CC=gcc +#CFLAGS="-Wall -Wextra -Werror -Wcomment -Wpointer-arith -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wdeclaration-after-statement -Wshadow -O2" +CFLAGS="-Wall -Werror -Wcomment -Wpointer-arith -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wshadow -O2" +if [ "$1" = "HEIMDAL" ]; then + DEFINE="-DHEIMDAL -D__LITTLE_ENDIAN__" + INCLUDE="-I/usr/include/heimdal -Ispnegohelp" + LIBS="-lgssapi -lkrb5 -lcom_err -lasn1 -lroken" +else +if [ "$1" = "SOLARIS" ]; then +#MIT + CC=cc + CFLAGS="" + DEFINE="-D__BIG_ENDIAN__ -DSOLARIS_11" + INCLUDE="-Ispnegohelp -Iinclude -Iinclude/kerberosv5" + LIBS="-R/usr/lib/gss -L/usr/lib/gss -lgss /usr/lib/gss/mech_krb5.so -lsocket" +else +#MIT + DEFINE="-D__LITTLE_ENDIAN__" + INCLUDE=-Ispnegohelp + LIBS="-lgssapi_krb5 -lkrb5 -lcom_err" +fi +fi +SPNEGO="spnegohelp/derparse.c spnegohelp/spnego.c spnegohelp/spnegohelp.c spnegohelp/spnegoparse.c" +SOURCE="squid_kerb_auth.c base64.c" +$CC -g $CFLAGS -o squid_kerb_auth $DEFINE $INCLUDE $SOURCE $SPNEGO $LIBS diff --git a/helpers/negotiate_auth/squid_kerb_auth/readme.txt b/helpers/negotiate_auth/squid_kerb_auth/readme.txt new file mode 100644 index 0000000000..6af777e974 --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/readme.txt @@ -0,0 +1,90 @@ +-------------------------------------------------------------------------------- +readme.txt is the squid_kerb_auth read-me file. + +Author: Markus Moeller (markus_moeller at compuserve.com) + +Copyright (C) 2007 Markus Moeller. All rights reserved. +-------------------------------------------------------------------------------- + +squid_kerb_auth Read Me + +Markus Moeller +May 12, 2007 + +1 Introduction + +squid_kerb_auth is a reference implementation that supports authentication via +the Negotiate RFC 4559 for proxies. It decodes RFC 2478 SPNEGO GSS-API tokens +from IE7 either through helper functions or via SPNEGO supporting Kerberos libraries +and RFC 1964 Kerberos tokens from Firefox on Linux. Currently, squid_kerb_auth + supports Squid 2.6 on Linux. + +squid_auth_kerb requires either MIT or Heimdal Kerberos libraries and header files. + +2 Building and Installation + +# Linux: +# -D__LITTLE_ENDIAN__ +# Solaris: +# -D__BIG_ENDIAN__ +# +#DEFINE_SPNEGO=-DHAVE_SPNEGO +#HEIMDAL +# DEFINE="-DHEIMDAL $DEFINE_SPNEGO -D__LITTLE_ENDIAN__" +# INCLUDE=-I/usr/include/heimdal -Ispnegohelp +# LIBS="-lgssapi -lkrb5 -lcom_err -lasn1 -lroken" +#MIT + DEFINE="$DEFINE_SPNEGO -D__LITTLE_ENDIAN__" + INCLUDE=-Ispnegohelp + LIBS="-lgssapi_krb5 -lkrb5 -lcom_err" +# +SPNEGO="spnegohelp/derparse.c spnegohelp/spnego.c spnegohelp/spnegohelp.c spnegohelp/spnegoparse.c" +SOURCE="squid_kerb_auth.c base64.c" +gcc -o squid_kerb_auth $DEFINE $INCLUDE $SOURCE $SPNEGO $LIBS + +Copy the helper squid_kerb_auth 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 + +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/krb-squid5.conf +export KRB5_CONFIG + +4 Miscellaneous + +The -i options creates informational messages whereas -d creates full debug output + +If squid_kerb_auth doesn't determine for some reason the right service principal you can provide +it with -s HTTP/fqdn. + +If you serve multiple Kerberos realms add a HTTP/fqdn@REALM service principal per realm to the +HTTP.keytab file and use the -s GSS_C_NO_NAME option with squid_kerb_auth. + + + + + diff --git a/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/Makefile b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/Makefile new file mode 100644 index 0000000000..7fd352c45a --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/Makefile @@ -0,0 +1,51 @@ +# +# Linux: +# -D__LITTLE_ENDIAN__ +# Solaris: +# -D__BIG_ENDIAN__ +# + +CFLAGS = -fpic + +LIB = libspnegohelp.a +SLIB = libspnegohelp.so + +OBJS = derparse.o spnego.o spnegohelp.o spnegoparse.o + +all: + make `uname` + +debug: + make CFLAGS="$(CFLAGS) -DDEBUG" `uname` + +SunOS: + make CFLAGS="$(CFLAGS) -D__BIG_ENDIAN__" libs + +AIX: + make CFLAGS="$(CFLAGS) -D__BIG_ENDIAN__" libs + +Linux: + make CFLAGS="$(CFLAGS) -D__LITTLE_ENDIAN__" libs + +libs: $(LIB) $(SLIB) + +$(LIB): $(OBJS) + ar -r $(LIB) $(OBJS) + +$(SLIB): $(OBJS) + gcc --shared -o $(SLIB) $(OBJS) + +derparse.o: derparse.c derparse.h spnego.h Makefile + gcc -c $(CFLAGS) derparse.c -o $@ + +spnego.o: spnego.c derparse.h spnego.h spnegoparse.h Makefile + gcc -c $(CFLAGS) spnego.c -o $@ + +spnegoparse.o: spnegoparse.c derparse.h spnego.h spnegoparse.h Makefile + gcc -c $(CFLAGS) spnegoparse.c -o $@ + +spnegohelp.o: spnegohelp.c spnego.h spnegohelp.h Makefile + gcc -c $(CFLAGS) spnegohelp.c -o $@ + +clean: + rm $(OBJS) $(LIB) $(SLIB) diff --git a/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/derparse.c b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/derparse.c new file mode 100644 index 0000000000..1cac0a1b1b --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/derparse.c @@ -0,0 +1,732 @@ +// Copyright (C) 2002 Microsoft Corporation +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" +// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +// OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY +// AND/OR FITNESS FOR A PARTICULAR PURPOSE. +// +// Date - 10/08/2002 +// Author - Sanj Surati + + +///////////////////////////////////////////////////////////// +// +// DERPARSE.C +// +// SPNEGO Token Handler Source File +// +// Contains implementation of ASN.1 DER read/write functions +// as defined in DERPARSE.H. +// +///////////////////////////////////////////////////////////// + +#include +#include +#include +#include "spnego.h" +#include "derparse.h" + +// +// The GSS Mechanism OID enumeration values (SPNEGO_MECH_OID) control which offset in +// the array below, that a mechanism can be found. +// +MECH_OID g_stcMechOIDList [] = +{ + { (unsigned char*) "\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02", 11, 9, spnego_mech_oid_Kerberos_V5_Legacy }, // 1.2.840.48018.1.2.2 + { (unsigned char*) "\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02", 11, 9, spnego_mech_oid_Kerberos_V5 }, // 1.2.840.113554.1.2.2 + { (unsigned char*) "\x06\x06\x2b\x06\x01\x05\x05\x02", 8, 6, spnego_mech_oid_Spnego }, // 1.3.6.1.1.5.5.2 + { (unsigned char*) "", 0, 0, spnego_mech_oid_NotUsed } // Placeholder +}; + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerGetLength +// +// Parameters: +// [in] pbLengthData - DER Length Data +// [in] nBoundaryLength - Length that value must not exceed. +// [out] pnLength - Filled out with length value +// [out] pnNumLengthBytes - Filled out with number of bytes +// consumed by DER length. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Interprets the data at pbLengthData as a DER length. The length must +// fit within the bounds of nBoundary length. We do not currently +// process lengths that take more than 4 bytes. +// +//////////////////////////////////////////////////////////////////////////// + +int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength, + long* pnNumLengthBytes ) +{ + int nReturn = SPNEGO_E_INVALID_LENGTH; + int nNumLengthBytes = 0; + + // First check if the extended length bit is set + + if ( *pbLengthData & LEN_XTND ) + { + // Lower 7 bits contain the number of trailing bytes that describe the length + nNumLengthBytes = *pbLengthData & LEN_MASK; + + // Check that the number of bytes we are about to read is within our boundary + // constraints + + if ( nNumLengthBytes <= nBoundaryLength - 1 ) + { + + // For now, our handler won't deal with lengths greater than 4 bytes + if ( nNumLengthBytes >= 1 && nNumLengthBytes <= 4 ) + { + // 0 out the initial length + *pnLength = 0L; + + // Bump by 1 byte + pbLengthData++; + + #ifdef __LITTLE_ENDIAN__ + + // There may be a cleaner way to do this, but for now, this seems to be + // an easy way to do the transformation + switch ( nNumLengthBytes ) + { + case 1: + { + *( ( (unsigned char*) pnLength ) ) = *pbLengthData; + break; + } + + case 2: + { + *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 1); + *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData); + + break; + } + + case 3: + { + *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 2); + *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1); + *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData); + break; + } + + case 4: + { + *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 3); + *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData + 2); + *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1); + *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData); + break; + } + + } // SWITCH ( nNumLengthBytes ) + + #else + // We are Big-Endian, so the length can be copied in from the source + // as is. Ensure that we adjust for the number of bytes we actually + // copy. + + memcpy( ( (unsigned char *) pnLength ) + ( 4 - nNumLengthBytes ), + pbLengthData, nNumLengthBytes ); + #endif + + // Account for the initial length byte + *pnNumLengthBytes = nNumLengthBytes + 1; + nReturn = SPNEGO_E_SUCCESS; + + } // IF Valid Length + + } // IF num bytes to read is within the boundary length + + } // IF xtended length + else + { + + // Extended bit is not set, so the length is in the value and the one + // byte describes the length + *pnLength = *pbLengthData & LEN_MASK; + *pnNumLengthBytes = 1; + nReturn = SPNEGO_E_SUCCESS; + + } + LOG(("ASNDerGetLength returned %d\n",nReturn)); + return nReturn; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerCheckToken +// +// Parameters: +// [in] pbTokenData - Token Data +// [in] nToken - Token identifier to check for +// [in] nLengthWithToken - Expected token length (with data) +// [in] nBoundaryLength - Length that value must not exceed. +// [out] pnLength - Filled out with data length +// [out] pnTokenLength - Filled out with number of bytes +// consumed by token identifier and length. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Checks the data pointed to by pbTokenData for the specified token +// identifier and the length that immediately follows. If +// nLengthWithToken is > 0, the calculated length must match. The +// length must also not exceed the specified boundary length . +// +//////////////////////////////////////////////////////////////////////////// + +int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken, + long nLengthWithToken, long nBoundaryLength, + long* pnLength, long* pnTokenLength ) +{ + + int nReturn = SPNEGO_E_INVALID_LENGTH; + long nNumLengthBytes = 0L; + + // Make sure that we've at least got 2 bytes of room to work with + + if ( nBoundaryLength >= 2 ) + { + // The first byte of the token data MUST match the specified token + if ( *pbTokenData == nToken ) + { + // Next byte indicates the length + pbTokenData++; + + // Get the length described by the token + if ( ( nReturn = ASNDerGetLength( pbTokenData, nBoundaryLength, pnLength, + &nNumLengthBytes ) ) == SPNEGO_E_SUCCESS ) + { + // Verify that the length is LESS THAN the boundary length + // (this should prevent us walking out of our buffer) + if ( ( nBoundaryLength - ( nNumLengthBytes + 1 ) < *pnLength ) ) + { + + nReturn = SPNEGO_E_INVALID_LENGTH; + + } + + // If we were passed a length to check, do so now + if ( nLengthWithToken > 0L ) + { + + // Check that the expected length matches + if ( ( nLengthWithToken - ( nNumLengthBytes + 1 ) ) != *pnLength ) + { + + nReturn = SPNEGO_E_INVALID_LENGTH; + + } + + } // IF need to validate length + + if ( SPNEGO_E_SUCCESS == nReturn ) + { + *pnTokenLength = nNumLengthBytes + 1; + } + + } // IF ASNDerGetLength + + } // IF token matches + else + { + nReturn = SPNEGO_E_TOKEN_NOT_FOUND; + } + + } // IF Boundary Length is at least 2 bytes + + LOG(("ASNDerCheckToken returned %d\n",nReturn)); + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerCheckOID +// +// Parameters: +// [in] pbTokenData - Token Data +// [in] nMechOID - OID we are looking for +// [in] nBoundaryLength - Length that value must not exceed. +// [out] pnTokenLength - Filled out with number of bytes +// consumed by token and data. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Checks the data pointed to by pbTokenData for the specified OID. +// +//////////////////////////////////////////////////////////////////////////// + +int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength, + long* pnTokenLength ) +{ + int nReturn = 0L; + long nLength = 0L; + + // Verify that we have an OID token + if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID, 0L, nBoundaryLength, + &nLength, pnTokenLength ) ) == SPNEGO_E_SUCCESS ) + { + // Add the data length to the Token Length + *pnTokenLength += nLength; + + // Token Lengths plus the actual length must match the length in our OID list element. + // If it doesn't, we're done + if ( *pnTokenLength == g_stcMechOIDList[nMechOID].iLen ) + { + // Memcompare the token and the expected field + if ( memcmp( pbTokenData, g_stcMechOIDList[nMechOID].ucOid, *pnTokenLength ) != 0 ) + { + LOG(("ASNDerCheckOID memcmp failed\n")); + nReturn = SPNEGO_E_UNEXPECTED_OID; + } + } + else + { + LOG(("ASNDerCheckOID token length failed\n")); + nReturn = SPNEGO_E_UNEXPECTED_OID; + } + + } // IF OID Token CHecks + + LOG(("ASNDerCheckOID returned %d\n",nReturn)); + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerCalcNumLengthBytes +// +// Parameters: +// [in] nLength - Length to calculate length bytes for. +// +// Returns: +// int Number of bytes necessary to represent length +// +// Comments : +// Helper function to calculate the number of length bytes necessary to +// represent a length value. For our purposes, a 32-bit value should be +// enough to describea length. +// +//////////////////////////////////////////////////////////////////////////// + +int ASNDerCalcNumLengthBytes( long nLength ) +{ + if ( nLength <= 0x7F ) + { + // A single byte will be sufficient for describing this length. + // The byte will simply contain the length + return 1; + } + else if ( nLength <= 0xFF ) + { + // Two bytes are necessary, one to say how many following bytes + // describe the length, and one to give the length + return 2; + } + else if ( nLength <= 0xFFFF ) + { + // Three bytes are necessary, one to say how many following bytes + // describe the length, and two to give the length + return 3; + } + else if ( nLength <= 0xFFFFFF ) + { + // Four bytes are necessary, one to say how many following bytes + // describe the length, and three to give the length + return 4; + } + else + { + // Five bytes are necessary, one to say how many following bytes + // describe the length, and four to give the length + return 5; + } +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerCalcTokenLength +// +// Parameters: +// [in] nLength - Length to calculate length bytes for. +// [in] nDataLength - Actual Data length value. +// +// Returns: +// long Number of bytes necessary to represent a token, length and data +// +// Comments : +// Helper function to calculate a token and value size, based on a +// supplied length value, and any binary data that will need to be +// written out. +// +//////////////////////////////////////////////////////////////////////////// + +long ASNDerCalcTokenLength( long nLength, long nDataLength ) +{ + // Add a byte to the length size to account for a single byte to + // hold the token type. + long nTotalLength = ASNDerCalcNumLengthBytes( nLength ) + 1; + + return nTotalLength + nDataLength; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerCalcElementLength +// +// Parameters: +// [in] nDataLength - Length of data. +// [out] pnInternalLength - Filled out with length of element +// without sequence info. +// +// Returns: +// long Number of bytes necessary to represent an element +// +// Comments : +// Helper function to calculate an element length. An element consists +// of a sequence token, a type token and then the data. +// +//////////////////////////////////////////////////////////////////////////// + +long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength ) +{ + // First the type token and the actual data + long nTotalLength = ASNDerCalcTokenLength( nDataLength, nDataLength ); + + // Internal length is the length without the element sequence token + if ( NULL != pnInternalLength ) + { + *pnInternalLength = nTotalLength; + } + + // Next add in the element's sequence token (remember that its + // length is the total length of the type token and data) + nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + return nTotalLength; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerCalcMechListLength +// +// Parameters: +// [in] mechoid - Mech OID to put in list. +// [out] pnInternalLength - Filled out with length of element +// without the primary sequence token. +// +// Returns: +// long Number of bytes necessary to represent a mechList +// +// Comments : +// Helper function to calculate a MechList length. A mechlist consists +// of a NegTokenInit sequence token, a sequence token for the MechList +// and finally a list of OIDs. In our case, we only really have one +// OID. +// +//////////////////////////////////////////////////////////////////////////// + +long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength ) +{ + // First the OID + long nTotalLength = g_stcMechOIDList[mechoid].iLen; + + // Next add in a sequence token + nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + // Internal length is the length without the element sequence token + if ( NULL != pnInternalLength ) + { + *pnInternalLength = nTotalLength; + } + + // Finally add in the element's sequence token + nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + return nTotalLength; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerWriteLength +// +// Parameters: +// [out] pbData - Buffer to write into. +// [in] nLength - Length to write out. +// +// Returns: +// int Number of bytes written out +// +// Comments : +// Helper function to write out a length value following DER rules . +// +//////////////////////////////////////////////////////////////////////////// + +int ASNDerWriteLength( unsigned char* pbData, long nLength ) +{ + int nNumBytesRequired = ASNDerCalcNumLengthBytes( nLength ); + int nNumLengthBytes = nNumBytesRequired - 1; + + + if ( nNumBytesRequired > 1 ) + { + + // Write out the number of bytes following which will be used + *pbData = (unsigned char ) ( LEN_XTND | nNumLengthBytes ); + + // Point to where we'll actually write the length + pbData++; + +#ifdef __LITTLE_ENDIAN__ + + // There may be a cleaner way to do this, but for now, this seems to be + // an easy way to do the transformation + switch ( nNumLengthBytes ) + { + case 1: + { + // Cast the length to a single byte, since we know that it + // is 0x7F or less (or we wouldn't only need a single byte). + + *pbData = (unsigned char) nLength; + break; + } + + case 2: + { + *pbData = *( ( (unsigned char*) &nLength ) + 1 ); + *( pbData + 1) = *( ( (unsigned char*) &nLength ) ); + break; + } + + case 3: + { + *pbData = *( ( (unsigned char*) &nLength ) + 3 ); + *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 ); + *( pbData + 2) = *( ( (unsigned char*) &nLength ) ); + break; + } + + case 4: + { + *pbData = *( ( (unsigned char*) &nLength ) + 3 ); + *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 ); + *( pbData + 2) = *( ( (unsigned char*) &nLength ) + 1 ); + *( pbData + 3) = *( ( (unsigned char*) &nLength ) ); + break; + } + + } // SWITCH ( nNumLengthBytes ) + +#else + // We are Big-Endian, so the length can be copied in from the source + // as is. Ensure that we adjust for the number of bytes we actually + // copy. + + memcpy( pbData, + ( (unsigned char *) &nLength ) + ( 4 - nNumLengthBytes ), nNumLengthBytes ); +#endif + + } // IF > 1 byte for length + else + { + // Cast the length to a single byte, since we know that it + // is 0x7F or less (or we wouldn't only need a single byte). + + *pbData = (unsigned char) nLength; + } + + return nNumBytesRequired; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerWriteToken +// +// Parameters: +// [out] pbData - Buffer to write into. +// [in] ucType - Token Type +// [in] pbTokenValue - Actual Value +// [in] nLength - Length of Data. +// +// Returns: +// int Number of bytes written out +// +// Comments : +// Helper function to write out a token and any associated data. If +// pbTokenValue is non-NULL, then it is written out in addition to the +// token identifier and the length bytes. +// +//////////////////////////////////////////////////////////////////////////// + +int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType, + unsigned char* pbTokenValue, long nLength ) +{ + int nTotalBytesWrittenOut = 0L; + int nNumLengthBytesWritten = 0L; + + // Write out the type + *pbData = ucType; + + // Wrote 1 byte, and move data pointer + nTotalBytesWrittenOut++; + pbData++; + + // Now write out the length and adjust the number of bytes written out + nNumLengthBytesWritten = ASNDerWriteLength( pbData, nLength ); + + nTotalBytesWrittenOut += nNumLengthBytesWritten; + pbData += nNumLengthBytesWritten; + + // Write out the token value if we got one. The assumption is that the + // nLength value indicates how many bytes are in pbTokenValue. + + if ( NULL != pbTokenValue ) + { + memcpy( pbData, pbTokenValue, nLength ); + nTotalBytesWrittenOut += nLength; + } + + return nTotalBytesWrittenOut; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerWriteOID +// +// Parameters: +// [out] pbData - Buffer to write into. +// [in] eMechOID - OID to write out. +// +// Returns: +// int Number of bytes written out +// +// Comments : +// Helper function to write out an OID. For these we have the raw bytes +// listed in a global structure. The caller simply indicates which OID +// should be written and we will splat out the data. +// +//////////////////////////////////////////////////////////////////////////// + +int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID ) +{ + + memcpy( pbData, g_stcMechOIDList[eMechOID].ucOid, g_stcMechOIDList[eMechOID].iLen ); + + return g_stcMechOIDList[eMechOID].iLen; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerWriteMechList +// +// Parameters: +// [out] pbData - Buffer to write into. +// [in] eMechOID - OID to put in MechList. +// +// Returns: +// int Number of bytes written out +// +// Comments : +// Helper function to write out a MechList. A MechList consists of the +// Init Token Sequence, a sequence token and then the list of OIDs. In +// our case the OID is from a global array of known OIDs. +// +//////////////////////////////////////////////////////////////////////////// + +long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid ) +{ + // First get the length + long nInternalLength = 0L; + long nMechListLength = ASNDerCalcMechListLength( mechoid, &nInternalLength ); + long nTempLength = 0L; + + nTempLength = ASNDerWriteToken( pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES, + NULL, nInternalLength ); + + // Adjust the data pointer + pbData += nTempLength; + + // Now write the Sequence token and the OID (the OID is a BLOB in the global + // structure. + + nTempLength = ASNDerWriteToken( pbData, SPNEGO_CONSTRUCTED_SEQUENCE, + g_stcMechOIDList[mechoid].ucOid, + g_stcMechOIDList[mechoid].iLen ); + + return nMechListLength; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerWriteElement +// +// Parameters: +// [out] pbData - Buffer to write into. +// [in] ucElementSequence - Sequence Token +// [in] ucType - Token Type +// [in] pbTokenValue - Actual Value +// [in] nLength - Length of Data. +// +// Returns: +// int Number of bytes written out +// +// Comments : +// Helper function to write out a SPNEGO Token element. An element +// consists of a sequence token, a type token and the associated data. +// +//////////////////////////////////////////////////////////////////////////// + +int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence, + unsigned char ucType, unsigned char* pbTokenValue, long nLength ) +{ + // First get the length + long nInternalLength = 0L; + long nElementLength = ASNDerCalcElementLength( nLength, &nInternalLength ); + long nTempLength = 0L; + + // Write out the sequence byte and the length of the type and data + nTempLength = ASNDerWriteToken( pbData, ucElementSequence, NULL, nInternalLength ); + + // Adjust the data pointer + pbData += nTempLength; + + // Now write the type and the data. + nTempLength = ASNDerWriteToken( pbData, ucType, pbTokenValue, nLength ); + + return nElementLength; +} + diff --git a/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/derparse.h b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/derparse.h new file mode 100644 index 0000000000..cdca9b45cb --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/derparse.h @@ -0,0 +1,207 @@ +// Copyright (C) 2002 Microsoft Corporation +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" +// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +// OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY +// AND/OR FITNESS FOR A PARTICULAR PURPOSE. +// +// Date - 10/08/2002 +// Author - Sanj Surati + +///////////////////////////////////////////////////////////// +// +// DERPARSE.H +// +// SPNEGO Token Handler Header File +// +// Contains the definitions required to properly parse the +// SPNEGO DER encoding. +// +///////////////////////////////////////////////////////////// + +#ifndef __DERPARSE_H__ +#define __DERPARSE_H__ + +// C++ Specific +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* Identifier Types */ +#define IDENTIFIER_MASK 0xC0 // Bits 7 and 8 +#define IDENTIFIER_UNIVERSAL 0x00 // 00 = universal +#define IDENTIFIER_APPLICATION 0x40 // 01 = application +#define IDENTIFIER_CONTEXT_SPECIFIC 0x80 // 10 = context specific +#define IDENTIFIER_PRIVATE 0xC0 // 11 = Private + +/* Encoding type */ + +#define FORM_MASK 0x20 /* Bit 6 */ +#define PRIMITIVE 0x00 /* 0 = primitive */ +#define CONSTRUCTED 0x20 /* 1 = constructed */ + +/* Universal tags */ + +#define TAG_MASK 0x1F /* Bits 5 - 1 */ +#define BOOLEAN 0x01 /* 1: TRUE or FALSE */ +#define INTEGER 0x02 /* 2: Arbitrary precision integer */ +#define BITSTRING 0x03 /* 2: Sequence of bits */ +#define OCTETSTRING 0x04 /* 4: Sequence of bytes */ +#define NULLTAG 0x05 /* 5: NULL */ +#define OID 0x06 /* 6: Object Identifier (numeric sequence) */ +#define OBJDESCRIPTOR 0x07 /* 7: Object Descriptor (human readable) */ +#define EXTERNAL 0x08 /* 8: External / Instance Of */ +#define REAL 0x09 /* 9: Real (Mantissa * Base^Exponent) */ +#define ENUMERATED 0x0A /* 10: Enumerated */ +#define EMBEDDED_PDV 0x0B /* 11: Embedded Presentation Data Value */ +#define SEQUENCE 0x10 /* 16: Constructed Sequence / Sequence Of */ +#define SET 0x11 /* 17: Constructed Set / Set Of */ +#define NUMERICSTR 0x12 /* 18: Numeric String (digits only) */ +#define PRINTABLESTR 0x13 /* 19: Printable String */ +#define T61STR 0x14 /* 20: T61 String (Teletex) */ +#define VIDEOTEXSTR 0x15 /* 21: Videotex String */ +#define IA5STR 0x16 /* 22: IA5 String */ +#define UTCTIME 0x17 /* 23: UTC Time */ +#define GENERALIZEDTIME 0x18 /* 24: Generalized Time */ +#define GRAPHICSTR 0x19 /* 25: Graphic String */ +#define VISIBLESTR 0x1A /* 26: Visible String (ISO 646) */ +#define GENERALSTR 0x1B /* 27: General String */ +#define UNIVERSALSTR 0x1C /* 28: Universal String */ +#define BMPSTR 0x1E /* 30: Basic Multilingual Plane String */ + +/* Length encoding */ + +#define LEN_XTND 0x80 /* Indefinite or long form */ +#define LEN_MASK 0x7f /* Bits 7 - 1 */ + +// +// SPNEGO Token Parsing Constants +// + + +// Fixed Length of NegTokenInit ReqFlags field +#define SPNEGO_NEGINIT_MAXLEN_REQFLAGS 2 + +// Difference in bits for ReqFlags token +#define SPNEGO_NEGINIT_REQFLAGS_BITDIFF 1 + +// Fixed Length of NegTokenTarg NegResult field +#define SPNEGO_NEGTARG_MAXLEN_NEGRESULT 1 + +// Application Specific Construct - Always at the start of a NegTokenInit +#define SPNEGO_NEGINIT_APP_CONSTRUCT ( IDENTIFIER_APPLICATION | CONSTRUCTED ) // 0x60 + +// Constructed Sequence token - after the actual token identifier token +#define SPNEGO_CONSTRUCTED_SEQUENCE ( SEQUENCE | CONSTRUCTED ) + +// MechList Type Identifier +#define SPNEGO_MECHLIST_TYPE ( SEQUENCE | CONSTRUCTED | OID ) + +// +// NegTokenInit - Token Identifier and Elements +// + +// NegTokenInit - 0xa0 +#define SPNEGO_NEGINIT_TOKEN_IDENTIFIER ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ + SPNEGO_TOKEN_INIT ) + +// Structure elements for NegTokenInit +#define SPNEGO_NEGINIT_MECHTYPES 0x0 // MechTypes is element 0 +#define SPNEGO_NEGINIT_REQFLAGS 0x1 // ReqFlags is element 1 +#define SPNEGO_NEGINIT_MECHTOKEN 0x2 // MechToken is element 2 +#define SPNEGO_NEGINIT_MECHLISTMIC 0x3 // MechListMIC is element 3 + +// MechTypes element is 0xa0 +#define SPNEGO_NEGINIT_ELEMENT_MECHTYPES ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ + SPNEGO_NEGINIT_MECHTYPES ) + +// ReqFlags element is 0xa1 +#define SPNEGO_NEGINIT_ELEMENT_REQFLAGS ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ + SPNEGO_NEGINIT_REQFLAGS ) + +// MechToken element is 0xa2 +#define SPNEGO_NEGINIT_ELEMENT_MECHTOKEN ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ + SPNEGO_NEGINIT_MECHTOKEN ) + +// MechListMIC element is 0xa3 +#define SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ + SPNEGO_NEGINIT_MECHLISTMIC ) + +// +// NegTokenTarg - Token Identifier and Elements +// + +// NegTokenTarg - 0xa1 +#define SPNEGO_NEGTARG_TOKEN_IDENTIFIER ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ + SPNEGO_TOKEN_TARG ) + +// Structure elements for NegTokenTarg +#define SPNEGO_NEGTARG_NEGRESULT 0x0 // NegResult is element 0 +#define SPNEGO_NEGTARG_SUPPORTEDMECH 0x1 // SupportedMech is element 1 +#define SPNEGO_NEGTARG_RESPONSETOKEN 0x2 // ResponseToken is element 2 +#define SPNEGO_NEGTARG_MECHLISTMIC 0x3 // MechListMIC is element 3 + +// NegResult element is 0xa0 +#define SPNEGO_NEGTARG_ELEMENT_NEGRESULT ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ + SPNEGO_NEGTARG_NEGRESULT ) + +// SupportedMech element is 0xa1 +#define SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ + SPNEGO_NEGTARG_SUPPORTEDMECH ) + +// ResponseToken element is 0xa2 +#define SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ + SPNEGO_NEGTARG_RESPONSETOKEN ) + +// MechListMIC element is 0xa3 +#define SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ + SPNEGO_NEGTARG_MECHLISTMIC ) + +// +// Defines a GSS Mechanism OID. We keep a single static array +// of these which we'll use for validation/searches/parsing. +// + +typedef struct _mechOID +{ + unsigned char* ucOid; // Byte representation of OID + int iLen; // Length of the OID, length and identifier + int iActualDataLen; // Length of the actual OID + SPNEGO_MECH_OID eMechanismOID; // Which OID is this? +} MECH_OID; + + +// +// ASN Der functions +// + +int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength, + long* pnNumLengthBytes ); +int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken, + long nCheckLength, long nBoundaryLength, long* pnLength, + long* pnTokenLength ); +int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength, + long* pnTokenLength ); +int ASNDerCalcNumLengthBytes( long nLength ); +long ASNDerCalcTokenLength( long nLength, long nDataLength ); +long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength ); +long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength ); +int ASNDerWriteLength( unsigned char* pbData, long nLength ); +int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType, + unsigned char* pbTokenValue, long nLength ); +int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID ); +long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid ); +int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence, + unsigned char ucType, unsigned char* pbTokenValue, long nLength ); + + + // C++ Specific +#if defined(__cplusplus) +} +#endif + +#endif + diff --git a/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnego.c b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnego.c new file mode 100644 index 0000000000..deb4cd3e31 --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnego.c @@ -0,0 +1,806 @@ +// Copyright (C) 2002 Microsoft Corporation +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" +// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +// OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY +// AND/OR FITNESS FOR A PARTICULAR PURPOSE. +// +// Date - 10/08/2002 +// Author - Sanj Surati + +///////////////////////////////////////////////////////////// +// +// SPNEGO.C +// +// SPNEGO Token Handler Source File +// +// Contains implementation of SPNEGO Token Handling API +// as defined in SPNEGO.H. +// +///////////////////////////////////////////////////////////// + +#include +#include +#include +#include "spnego.h" +#include "derparse.h" +#include "spnegoparse.h" + +// +// Defined in DERPARSE.C +// + +extern MECH_OID g_stcMechOIDList []; + + +/**********************************************************************/ +/** **/ +/** **/ +/** **/ +/** **/ +/** SPNEGO Token Handler API implementation **/ +/** **/ +/** **/ +/** **/ +/** **/ +/**********************************************************************/ + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoInitFromBinary +// +// Parameters: +// [in] pbTokenData - Binary Token Data +// [in] ulLength - Length of binary Token Data +// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Initializes a SPNEGO_TOKEN_HANDLE from the supplied +// binary data. Data is copied locally. Returned data structure +// must be freed by calling spnegoFreeData(). +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoInitFromBinary( unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken; + + // Pass off to a handler function that allows tighter control over how the token structure + // is handled. In this case, we want the token data copied and we want the associated buffer + // freed. + nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYDATA, + SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, pbTokenData, + ulLength, ppSpnegoToken ); + + LOG(("spnegoInitFromBinary returned %d\n",nReturn)); + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoCreateNegTokenInit +// +// Parameters: +// [in] MechType - MechType to specify in MechTypeList element +// [in] ucContextFlags - Context Flags element value +// [in] pbMechToken - Pointer to binary MechToken Data +// [in] ulMechTokenLen - Length of MechToken Data +// [in] pbMechListMIC - Pointer to binary MechListMIC Data +// [in] ulMechListMICLen - Length of MechListMIC Data +// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenInit type +// from the supplied parameters. ucContextFlags may be 0 or must be +// a valid flag combination. MechToken data can be NULL - if not, it +// must correspond to the MechType. MechListMIC can also be NULL. +// Returned data structure must be freed by calling spnegoFreeData(). +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType, + unsigned char ucContextFlags, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + long nTokenLength = 0L; + long nInternalTokenLength = 0L; + unsigned char* pbTokenData = NULL; + SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken; + + if ( NULL != ppSpnegoToken && + IsValidMechOid( MechType ) && + IsValidContextFlags( ucContextFlags ) ) + { + // Get the actual token size + + if ( ( nReturn = CalculateMinSpnegoInitTokenSize( ulMechTokenLen, ulMechListMICLen, + MechType, ( ucContextFlags != 0L ), + &nTokenLength, &nInternalTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Allocate a buffer to hold the data. + pbTokenData = calloc( 1, nTokenLength ); + + if ( NULL != pbTokenData ) + { + + // Now write the token + if ( ( nReturn = CreateSpnegoInitToken( MechType, + ucContextFlags, pbMechToken, + ulMechTokenLen, pbMechListMIC, + ulMechListMICLen, pbTokenData, + nTokenLength, nInternalTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + + // This will copy our allocated pointer, and ensure that the sructure cleans + // up the data later + nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYPTR, + SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, + pbTokenData, nTokenLength, ppSpnegoToken ); + + } + + // Cleanup on failure + if ( SPNEGO_E_SUCCESS != nReturn ) + { + free( pbTokenData ); + } + + } // IF alloc succeeded + else + { + nReturn = SPNEGO_E_OUT_OF_MEMORY; + } + + } // If calculated token size + + } // IF Valid Parameters + + LOG(("spnegoCreateNegTokenInit returned %d\n",nReturn)); + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoCreateNegTokenTarg +// +// Parameters: +// [in] MechType - MechType to specify in supported MechType element +// [in] spnegoNegResult - NegResult value +// [in] pbMechToken - Pointer to response MechToken Data +// [in] ulMechTokenLen - Length of MechToken Data +// [in] pbMechListMIC - Pointer to binary MechListMIC Data +// [in] ulMechListMICLen - Length of MechListMIC Data +// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenTarg type +// from the supplied parameters. MechToken data can be NULL - if not, +// it must correspond to the MechType. MechListMIC can also be NULL. +// Returned data structure must be freed by calling spnegoFreeData(). +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoCreateNegTokenTarg( SPNEGO_MECH_OID MechType, + SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + long nTokenLength = 0L; + long nInternalTokenLength = 0L; + unsigned char* pbTokenData = NULL; + SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken; + + // + // spnego_mech_oid_NotUsed and spnego_negresult_NotUsed + // are okay here, however a valid MechOid is required + // if spnego_negresult_success or spnego_negresult_incomplete + // is specified. + // + + if ( NULL != ppSpnegoToken && + + ( IsValidMechOid( MechType ) || + spnego_mech_oid_NotUsed == MechType ) && + + ( IsValidNegResult( spnegoNegResult ) || + spnego_negresult_NotUsed == spnegoNegResult ) && + + !( !IsValidMechOid( MechType ) && + ( spnego_negresult_success == spnegoNegResult || + spnego_negresult_incomplete == spnegoNegResult ) ) ) + { + + // Get the actual token size + + if ( ( nReturn = CalculateMinSpnegoTargTokenSize( MechType, spnegoNegResult, ulMechTokenLen, + ulMechListMICLen, &nTokenLength, + &nInternalTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Allocate a buffer to hold the data. + pbTokenData = calloc( 1, nTokenLength ); + + if ( NULL != pbTokenData ) + { + + // Now write the token + if ( ( nReturn = CreateSpnegoTargToken( MechType, + spnegoNegResult, pbMechToken, + ulMechTokenLen, pbMechListMIC, + ulMechListMICLen, pbTokenData, + nTokenLength, nInternalTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + + // This will copy our allocated pointer, and ensure that the sructure cleans + // up the data later + nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYPTR, + SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, + pbTokenData, nTokenLength, ppSpnegoToken ); + + } + + // Cleanup on failure + if ( SPNEGO_E_SUCCESS != nReturn ) + { + free( pbTokenData ); + } + + } // IF alloc succeeded + else + { + nReturn = SPNEGO_E_OUT_OF_MEMORY; + } + + } // If calculated token size + + } // IF Valid Parameters + + LOG(("spnegoCreateNegTokenTarg returned %d\n",nReturn)); + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoTokenGetBinary +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] pbTokenData - Buffer to copy token into +// [in/out] pulDataLen - Length of pbTokenData buffer, filled out +// with actual size used upon function return. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Copies binary SPNEGO token data from hSpnegoToken into the user +// supplied buffer. If pbTokenData is NULL, or the value in pulDataLen +// is too small, the function will return SPNEGO_E_BUFFER_TOO_SMALL and +// fill out pulDataLen with the minimum required buffer size. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoTokenGetBinary( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, + unsigned long * pulDataLen ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + + // Check parameters - pbTokenData is optional + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != pulDataLen ) + { + + // Check for Buffer too small conditions + if ( NULL == pbTokenData || + pSpnegoToken->ulBinaryDataLen > *pulDataLen ) + { + *pulDataLen = pSpnegoToken->ulBinaryDataLen; + nReturn = SPNEGO_E_BUFFER_TOO_SMALL; + } + else + { + memcpy( pbTokenData, pSpnegoToken->pbBinaryData, pSpnegoToken->ulBinaryDataLen ); + *pulDataLen = pSpnegoToken->ulBinaryDataLen; + nReturn = SPNEGO_E_SUCCESS; + } + + } // IF parameters OK + + LOG(("spnegoTokenGetBinary returned %d\n",nReturn)); + return nReturn;; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoFreeData +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// +// Returns: +// void +// +// Comments : +// Frees up resources consumed by hSpnegoToken. The supplied data +// pointer is invalidated by this function. +// +//////////////////////////////////////////////////////////////////////////// + +void spnegoFreeData( SPNEGO_TOKEN_HANDLE hSpnegoToken ) +{ + FreeSpnegoToken( (SPNEGO_TOKEN*) hSpnegoToken); + return; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoGetTokenType +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] piTokenType - Filled out with token type value. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// The function will analyze hSpnegoToken and return the appropriate +// type in piTokenType. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoGetTokenType( SPNEGO_TOKEN_HANDLE hSpnegoToken, int * piTokenType ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != piTokenType && + pSpnegoToken) + { + + // Check that the type in the structure makes sense + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType || + SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType ) + { + *piTokenType = pSpnegoToken->ucTokenType; + nReturn = SPNEGO_E_SUCCESS; + } + + } // IF parameters OK + + LOG(("spnegoGetTokenType returned %d\n",nReturn)); + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoIsMechTypeAvailable +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [in] MechOID - MechOID to search MechTypeList for +// [out] piMechTypeIndex - Filled out with index in MechTypeList +// element if MechOID is found. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// hSpnegoToken must reference a token of type NegTokenInit. The +// function will search the MechTypeList element for an OID corresponding +// to the specified MechOID. If one is found, the index (0 based) will +// be passed into the piMechTypeIndex parameter. +// +//////////////////////////////////////////////////////////////////////////// + +// Returns the Initial Mech Type in the MechList element in the NegInitToken. +int spnegoIsMechTypeAvailable( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int * piMechTypeIndex ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != piMechTypeIndex && + IsValidMechOid( MechOID ) && + SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + + // Check if MechList is available + if ( pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT].iElementPresent + == SPNEGO_TOKEN_ELEMENT_AVAILABLE ) + { + // Locate the MechOID in the list element + nReturn = FindMechOIDInMechList( + &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT], + MechOID, piMechTypeIndex ); + } + else + { + nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; + } + + } // IF parameters OK + + LOG(("spnegoIsMechTypeAvailable returned %d\n",nReturn)); + return nReturn;; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoGetContextFlags +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] pucContextFlags - Filled out with ContextFlags value. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// hSpnegoToken must reference a token of type NegTokenInit. The +// function will copy data from the ContextFlags element into the +// location pucContextFlags points to. Note that the function will +// fail if the actual ContextFlags data appears invalid. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoGetContextFlags( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != pucContextFlags && + SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + + // Check if ContextFlags is available + if ( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].iElementPresent + == SPNEGO_TOKEN_ELEMENT_AVAILABLE ) + { + // The length should be two, the value should show a 1 bit difference in the difference byte, and + // the value must be valid + if ( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].nDatalength == SPNEGO_NEGINIT_MAXLEN_REQFLAGS && + pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[0] == SPNEGO_NEGINIT_REQFLAGS_BITDIFF && + IsValidContextFlags( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1] ) ) + { + *pucContextFlags = pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1]; + nReturn = SPNEGO_E_SUCCESS; + } + else + { + nReturn = SPNEGO_E_INVALID_ELEMENT; + } + + } + else + { + nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; + } + + } // IF parameters OK + + LOG(("spnegoGetContextFlags returned %d\n",nReturn)); + return nReturn;; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoGetNegotiationResult +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] pnegResult - Filled out with NegResult value. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// hSpnegoToken must reference a token of type NegTokenTarg. The +// function will copy data from the NegResult element into the +// location pointed to by pnegResult. Note that the function will +// fail if the actual NegResult data appears invalid. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoGetNegotiationResult( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != pnegResult && + SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType ) + { + + // Check if NegResult is available + if ( pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].iElementPresent + == SPNEGO_TOKEN_ELEMENT_AVAILABLE ) + { + // Must be 1 byte long and a valid value + if ( pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].nDatalength == SPNEGO_NEGTARG_MAXLEN_NEGRESULT && + IsValidNegResult( *pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData ) ) + { + *pnegResult = *pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData; + nReturn = SPNEGO_E_SUCCESS; + } + else + { + nReturn = SPNEGO_E_INVALID_ELEMENT; + } + } + else + { + nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; + } + + } // IF parameters OK + + LOG(("spnegoGetNegotiationResult returned %d\n",nReturn)); + return nReturn;; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoGetSupportedMechType +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] pMechOID - Filled out with Supported MechType value. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// hSpnegoToken must reference a token of type NegTokenTarg. The +// function will check the Supported MechType element, and if it +// corresponds to a supported MechType ( spnego_mech_oid_Kerberos_V5_Legacy +// or spnego_mech_oid_Kerberos_V5 ), will set the location pointed +// to by pMechOID equal to the appropriate value. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoGetSupportedMechType( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + int nCtr = 0L; + long nLength = 0L; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != pMechOID && + SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType ) + { + + // Check if MechList is available + if ( pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].iElementPresent + == SPNEGO_TOKEN_ELEMENT_AVAILABLE ) + { + + for ( nCtr = 0; + nReturn != SPNEGO_E_SUCCESS && + g_stcMechOIDList[nCtr].eMechanismOID != spnego_mech_oid_NotUsed; + nCtr++ ) + { + + if ( ( nReturn = ASNDerCheckOID( + pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].pbData, + nCtr, + pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].nDatalength, + &nLength ) ) == SPNEGO_E_SUCCESS ) + { + *pMechOID = nCtr; + } + + } // For enum MechOIDs + + + } + else + { + nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; + } + + } // IF parameters OK + + LOG(("spnegoGetSupportedMechType returned %d\n",nReturn)); + return nReturn;; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoTokenGetMechToken +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] pbTokenData - Buffer to copy MechToken into +// [in/out] pulDataLen - Length of pbTokenData buffer, filled out +// with actual size used upon function return. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token. +// The function will copy the MechToken (the initial MechToken if +// NegTokenInit, the response MechToken if NegTokenTarg) from the +// underlying token into the buffer pointed to by pbTokenData. If +// pbTokenData is NULL, or the value in pulDataLen is too small, the +// function will return SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen +// with the minimum required buffer size. The token can then be passed +// to a GSS-API function for processing. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoGetMechToken( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned long* pulDataLen ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + SPNEGO_ELEMENT* pSpnegoElement = NULL; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != pulDataLen ) + { + + // Point at the proper Element + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTOKEN_ELEMENT]; + } + else + { + pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_RESPTOKEN_ELEMENT]; + } + + // Check if MechType is available + if ( SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent ) + { + // Check for Buffer too small conditions + if ( NULL == pbTokenData || + pSpnegoElement->nDatalength > *pulDataLen ) + { + *pulDataLen = pSpnegoElement->nDatalength; + nReturn = SPNEGO_E_BUFFER_TOO_SMALL; + } + else + { + // Copy Memory + memcpy( pbTokenData, pSpnegoElement->pbData, pSpnegoElement->nDatalength ); + *pulDataLen = pSpnegoElement->nDatalength; + nReturn = SPNEGO_E_SUCCESS; + } + } + else + { + nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; + } + + } // IF parameters OK + + LOG(("spnegoGetMechToken returned %d\n",nReturn)); + return nReturn;; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoTokenGetMechListMIC +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] pbTokenData - Buffer to copy MechListMIC data into +// [in/out] pulDataLen - Length of pbTokenData buffer, filled out +// with actual size used upon function return. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token. +// The function will copy the MechListMIC data from the underlying token +// into the buffer pointed to by pbTokenData. If pbTokenData is NULL, +// or the value in pulDataLen is too small, the function will return +// SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen with the minimum +// required buffer size. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoGetMechListMIC( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned long* pulDataLen ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + SPNEGO_ELEMENT* pSpnegoElement = NULL; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != pulDataLen ) + { + + // Point at the proper Element + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHLISTMIC_ELEMENT]; + } + else + { + pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_MECHLISTMIC_ELEMENT]; + } + + // Check if MechType is available + if ( SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent ) + { + // Check for Buffer too small conditions + if ( NULL == pbMICData || + pSpnegoElement->nDatalength > *pulDataLen ) + { + *pulDataLen = pSpnegoElement->nDatalength; + nReturn = SPNEGO_E_BUFFER_TOO_SMALL; + } + else + { + // Copy Memory + memcpy( pbMICData, pSpnegoElement->pbData, pSpnegoElement->nDatalength ); + *pulDataLen = pSpnegoElement->nDatalength; + nReturn = SPNEGO_E_SUCCESS; + } + } + else + { + nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; + } + + } // IF parameters OK + + LOG(("spnegoGetMechListMIC returned %d\n",nReturn)); + return nReturn;; +} + diff --git a/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnego.h b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnego.h new file mode 100644 index 0000000000..a49b220cdf --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnego.h @@ -0,0 +1,247 @@ +// Copyright (C) 2002 Microsoft Corporation +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" +// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +// OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY +// AND/OR FITNESS FOR A PARTICULAR PURPOSE. +// +// Date - 10/08/2002 +// Author - Sanj Surati + +///////////////////////////////////////////////////////////// +// +// SPNEGO.H +// +// SPNEGO Token Handler Header File +// +// Contains the definitions required to interpret and create +// SPNEGO tokens so that Kerberos GSS tokens can be +// Unpackaged/packaged. +// +///////////////////////////////////////////////////////////// + +#ifndef __SPNEGO_H__ +#define __SPNEGO_H__ + +// C++ Specific +#if defined(__cplusplus) +extern "C" +{ +#endif + +// Type Definitions + +// +// Users of SPNEGO Token Handler API will request +// these as well as free them, +// +typedef void* SPNEGO_TOKEN_HANDLE; + +// +// Defines the element types that are found +// in each of the tokens. +// + +typedef enum spnego_element_type +{ + spnego_element_min, // Lower bound + + // Init token elements + spnego_init_mechtypes, + spnego_init_reqFlags, + spnego_init_mechToken, + spnego_init_mechListMIC, + + // Targ token elements + spnego_targ_negResult, + spnego_targ_supportedMech, + spnego_targ_responseToken, + spnego_targ_mechListMIC, + + spnego_element_max // Upper bound + +} SPNEGO_ELEMENT_TYPE; + +// +// Token Element Availability. Elements in both +// token types are optional. Since there are only +// 4 elements in each Token, we will allocate space +// to hold the information, but we need a way to +// indicate whether or not an element is available +// + +#define SPNEGO_TOKEN_ELEMENT_UNAVAILABLE 0 +#define SPNEGO_TOKEN_ELEMENT_AVAILABLE 1 + +// +// Token type values. SPNEGO has 2 token types: +// NegTokenInit and NegTokenTarg +// + +#define SPNEGO_TOKEN_INIT 0 +#define SPNEGO_TOKEN_TARG 1 + +// +// GSS Mechanism OID enumeration. We only really handle +// 3 different OIDs. These are stored in an array structure +// defined in the parsing code. +// + +typedef enum spnego_mech_oid +{ + // Init token elements + spnego_mech_oid_Kerberos_V5_Legacy, // Really V5, but OID off by 1 bit + spnego_mech_oid_Kerberos_V5, + spnego_mech_oid_Spnego, + spnego_mech_oid_NotUsed = -1 + +} SPNEGO_MECH_OID; + +// +// Defines the negResult values. +// + +typedef enum spnego_negResult +{ + spnego_negresult_success, + spnego_negresult_incomplete, + spnego_negresult_rejected, + spnego_negresult_NotUsed = -1 +} SPNEGO_NEGRESULT; + +// +// Context Flags in NegTokenInit +// + +// +// ContextFlags values MUST be zero or a combination +// of the below +// + +#define SPNEGO_NEGINIT_CONTEXT_DELEG_FLAG 0x80 +#define SPNEGO_NEGINIT_CONTEXT_MUTUAL_FLAG 0x40 +#define SPNEGO_NEGINIT_CONTEXT_REPLAY_FLAG 0x20 +#define SPNEGO_NEGINIT_CONTEXT_SEQUENCE_FLAG 0x10 +#define SPNEGO_NEGINIT_CONTEXT_ANON_FLAG 0x8 +#define SPNEGO_NEGINIT_CONTEXT_CONF_FLAG 0x4 +#define SPNEGO_NEGINIT_CONTEXT_INTEG_FLAG 0x2 + +// +// Mask to retrieve valid values. +// + +#define SPNEGO_NEGINIT_CONTEXT_MASK 0xFE // Logical combination of above flags + +// +// SPNEGO API return codes. +// + +// API function was successful +#define SPNEGO_E_SUCCESS 0 + +// The supplied Token was invalid +#define SPNEGO_E_INVALID_TOKEN -1 + +// An invalid length was encountered +#define SPNEGO_E_INVALID_LENGTH -2 + +// The Token Parse failed +#define SPNEGO_E_PARSE_FAILED -3 + +// The requested value was not found +#define SPNEGO_E_NOT_FOUND -4 + +// The requested element is not available +#define SPNEGO_E_ELEMENT_UNAVAILABLE -5 + +// Out of Memory +#define SPNEGO_E_OUT_OF_MEMORY -6 + +// Not Implemented +#define SPNEGO_E_NOT_IMPLEMENTED -7 + +// Invalid Parameter +#define SPNEGO_E_INVALID_PARAMETER -8 + +// Token Handler encountered an unexpected OID +#define SPNEGO_E_UNEXPECTED_OID -9 + +// The requested token was not found +#define SPNEGO_E_TOKEN_NOT_FOUND -10 + +// An unexpected type was encountered in the encoding +#define SPNEGO_E_UNEXPECTED_TYPE -11 + +// The buffer was too small +#define SPNEGO_E_BUFFER_TOO_SMALL -12 + +// A Token Element was invalid (e.g. improper length or value) +#define SPNEGO_E_INVALID_ELEMENT -13 + +/* Miscelaneous API Functions */ + +// Frees opaque data +void spnegoFreeData( SPNEGO_TOKEN_HANDLE hSpnegoToken ); + +// Initializes SPNEGO_TOKEN structure from DER encoded binary data +int spnegoInitFromBinary( unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken ); + +// Initializes SPNEGO_TOKEN structure for a NegTokenInit type using the +// supplied parameters +int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType, + unsigned char ucContextFlags, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechTokenMIC, + unsigned long ulMechTokenMIC, SPNEGO_TOKEN_HANDLE* phSpnegoToken ); + +// Initializes SPNEGO_TOKEN structure for a NegTokenTarg type using the +// supplied parameters +int spnegoCreateNegTokenTarg( SPNEGO_MECH_OID MechType, + SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken ); + +// Copies binary representation of SPNEGO Data into user supplied buffer +int spnegoTokenGetBinary( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, + unsigned long * pulDataLen ); + +// Returns SPNEGO Token Type +int spnegoGetTokenType( SPNEGO_TOKEN_HANDLE hSpnegoToken, int * piTokenType ); + +/* Reading an Init Token */ + +// Returns the Initial Mech Type in the MechList element in the NegInitToken. +int spnegoIsMechTypeAvailable( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int * piMechTypeIndex ); + +// Returns the value from the context flags element in the NegInitToken as an unsigned long +int spnegoGetContextFlags( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags ); + +/* Reading a Response Token */ + +// Returns the value from the negResult element (Status code of GSS call - 0,1,2) +int spnegoGetNegotiationResult( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult ); + +// Returns the Supported Mech Type from the NegTokenTarg. +int spnegoGetSupportedMechType( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID ); + +/* Reading either Token Type */ + +// Returns the actual Mechanism data from the token (this is what is passed into GSS-API functions +int spnegoGetMechToken( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned long* pulDataLen ); + +// Returns the Message Integrity BLOB in the token +int spnegoGetMechListMIC( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned long* pulDataLen ); + +// C++ Specific +#if defined(__cplusplus) +} +#endif +#ifdef DEBUG +#include + #define PRERR(...) fprintf(stderr, __VA_ARGS__) + #define LOG(x) PRERR x +#else + #define LOG(x) +#endif +#endif diff --git a/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegohelp.c b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegohelp.c new file mode 100644 index 0000000000..a10bc25c92 --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegohelp.c @@ -0,0 +1,263 @@ +/* ----------------------------------------------------------------------------- + * spnegohelp.c defines RFC 2478 SPNEGO GSS-API mechanism APIs. + * + * Author: Frank Balluffi + * + * Copyright (C) 2002-2003 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 "spnegohelp.h" +#include "spnego.h" + +#include + +int makeNegTokenTarg (const unsigned char * kerberosToken, + size_t kerberosTokenLength, + const unsigned char ** negTokenTarg, + size_t * negTokenTargLength) +{ + SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL; + int rc1 = 1; + int rc2 = SPNEGO_E_SUCCESS; + + /* Check arguments. */ + + if (!kerberosToken || + !negTokenTarg || + !negTokenTargLength) + return 10; + + /* Does IIS reply with 1.2.840.48018.1.2.2 or 1.2.840.113554.1.2.2? */ + + /* Does IIS always reply with accept_completed? */ + + /* IIS does not include a MIC. */ + + rc2 = spnegoCreateNegTokenTarg (spnego_mech_oid_Kerberos_V5_Legacy, + spnego_negresult_success, + (unsigned char *) kerberosToken, + kerberosTokenLength, + NULL, + 0, + &hSpnegoToken); + + if (rc2 != SPNEGO_E_SUCCESS) + { + rc1 = abs(rc2)+100; + goto cleanup; + } + + /* Get NegTokenTarg length. */ + + rc2 = spnegoTokenGetBinary (hSpnegoToken, + NULL, + (unsigned long*) negTokenTargLength); + + if (rc2 != SPNEGO_E_BUFFER_TOO_SMALL) + { + rc1 = abs(rc2)+200; + goto cleanup; + } + + *negTokenTarg = malloc (*negTokenTargLength); + + if (!*negTokenTarg) + { + rc1 = abs(rc2)+300; + goto cleanup; + } + + /* Get NegTokenTarg data. */ + + rc2 = spnegoTokenGetBinary (hSpnegoToken, + (unsigned char *) *negTokenTarg, + (unsigned long*) negTokenTargLength); + + + if (rc2 != SPNEGO_E_SUCCESS) + { + rc1 = abs(rc2)+400; + goto error; + } + + rc1 = 0; + + goto cleanup; + +error: + + if (*negTokenTarg) + { + free ((unsigned char *) *negTokenTarg); + *negTokenTarg = NULL; + *negTokenTargLength = 0; + } + +cleanup: + + if (hSpnegoToken) + spnegoFreeData (hSpnegoToken); + + LOG(("makeNegTokenTarg returned %d\n",rc1)); + return rc1; +} + +int parseNegTokenInit (const unsigned char * negTokenInit, + size_t negTokenInitLength, + const unsigned char ** kerberosToken, + size_t * kerberosTokenLength) +{ + SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL; + int pindex = -1; + int rc1 = 1; + int rc2 = SPNEGO_E_SUCCESS; + unsigned char reqFlags = 0; + int tokenType = 0; + + /* Check arguments. */ + + if (!negTokenInit || + !kerberosToken || + !kerberosTokenLength) + return 10; + + /* Decode SPNEGO token. */ + + rc2 = spnegoInitFromBinary ((unsigned char *) negTokenInit, + negTokenInitLength, + &hSpnegoToken); + + if (rc2 != SPNEGO_E_SUCCESS) + { + rc1 = abs(rc2)+100; + goto cleanup; + } + + /* Check for negTokenInit choice. */ + + rc2 = spnegoGetTokenType (hSpnegoToken, + &tokenType); + + if (rc2 != SPNEGO_E_SUCCESS) + { + rc1 = abs(rc2)+200; + goto cleanup; + } + + if (tokenType != SPNEGO_TOKEN_INIT) + { + rc1 = abs(rc2)+300; + goto cleanup; + } + + /* + Check that first mechType is 1.2.840.113554.1.2.2 or 1.2.840.48018.1.2.2. + */ + + /* + IE seems to reply with 1.2.840.48018.1.2.2 and then 1.2.840.113554.1.2.2. + */ + + rc2 = spnegoIsMechTypeAvailable (hSpnegoToken, + spnego_mech_oid_Kerberos_V5_Legacy, + &pindex); + + if (rc2 != SPNEGO_E_SUCCESS || + pindex != 0) + { + rc2 = spnegoIsMechTypeAvailable (hSpnegoToken, + spnego_mech_oid_Kerberos_V5, + &pindex); + + if (rc2 != SPNEGO_E_SUCCESS || + pindex != 0) + { + rc1 = abs(rc2)+400; + goto cleanup; + } + } + + /* Check for no reqFlags. */ + + /* Does IE ever send reqFlags? */ + + rc2 = spnegoGetContextFlags (hSpnegoToken, + &reqFlags); + + if (rc2 == SPNEGO_E_SUCCESS) + { + rc1 = abs(rc2)+500; + goto cleanup; + } + + /* Get mechanism token length. */ + + rc2 = spnegoGetMechToken (hSpnegoToken, + NULL, + (unsigned long*) kerberosTokenLength); + + if (rc2 != SPNEGO_E_BUFFER_TOO_SMALL) + { + rc1 = abs(rc2)+600; + goto cleanup; + } + + *kerberosToken = malloc (*kerberosTokenLength); + + if (!*kerberosToken) + { + rc1 = abs(rc2)+700; + goto cleanup; + } + + /* Get mechanism token data. */ + + rc2 = spnegoGetMechToken (hSpnegoToken, + (unsigned char *) *kerberosToken, + (unsigned long*) kerberosTokenLength); + + if (rc2 != SPNEGO_E_SUCCESS) + { + rc1 = abs(rc2)+800; + goto error; + } + + /* According to Microsoft, IE does not send a MIC. */ + + rc1 = 0; + + goto cleanup; + +error: + + if (*kerberosToken) + { + free ((unsigned char *) *kerberosToken); + *kerberosToken = NULL; + *kerberosTokenLength = 0; + } + +cleanup: + + if (hSpnegoToken) + spnegoFreeData (hSpnegoToken); + + LOG(("parseNegTokenInit returned %d\n",rc1)); + return rc1; +} diff --git a/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegohelp.h b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegohelp.h new file mode 100644 index 0000000000..5bcbabea64 --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegohelp.h @@ -0,0 +1,58 @@ +/* ----------------------------------------------------------------------------- + * spnegohelp.c declares RFC 2478 SPNEGO GSS-API mechanism APIs. + * + * Author: Frank Balluffi + * + * Copyright (C) 2002-2003. All rights reserved. + * ----------------------------------------------------------------------------- + */ + +#ifndef SPNEGOHELP_H +#define SPNEGOHELP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* ----------------------------------------------------------------------------- + * makeNegTokenTarg makes an RFC 2478 SPNEGO NegTokenTarg (token) from an + * RFC 1964 Kerberos GSS-API token. + * + * If makeNegTokenTarg is successful, call free (*negTokenTarg) to free the + * memory allocated by parseNegTokenInit. + * + * Returns 0 if successful, 1 otherwise. + * ----------------------------------------------------------------------------- + */ + +int makeNegTokenTarg (const unsigned char * kerberosToken, + size_t kerberosTokenLength, + const unsigned char ** negTokenTarg, + size_t * negTokenTargLength); + +/* ----------------------------------------------------------------------------- + * parseNegTokenInit parses an RFC 2478 SPNEGO NegTokenInit (token) to extract + * an RFC 1964 Kerberos GSS-API token. + * + * If the NegTokenInit does cotain a Kerberos GSS-API token, parseNegTokenInit + * returns an error. + * + * If parseNegTokenInit is successful, call free (*kerberosToken) to + * free the memory allocated by parseNegTokenInit. + * + * Returns 0 if successful, 1 otherwise. + * ----------------------------------------------------------------------------- + */ + +int parseNegTokenInit (const unsigned char * negTokenInit, + size_t negTokenInitLength, + const unsigned char ** kerberosToken, + size_t * kerberosTokenLength); + +#ifdef __cplusplus +} +#endif + +#endif /* SPNEGOHELP_H */ diff --git a/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegoparse.c b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegoparse.c new file mode 100644 index 0000000000..e300af5be6 --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegoparse.c @@ -0,0 +1,1880 @@ +// Copyright (C) 2002 Microsoft Corporation +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" +// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +// OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY +// AND/OR FITNESS FOR A PARTICULAR PURPOSE. +// +// Date - 10/08/2002 +// Author - Sanj Surati + +///////////////////////////////////////////////////////////// +// +// SPNEGOPARSE.C +// +// SPNEGO Token Handler Source File +// +// Contains implementation of SPNEGO Token parsing functions. +// +///////////////////////////////////////////////////////////// + +#include +#include +#include +#include "spnego.h" +#include "derparse.h" +#include "spnegoparse.h" + +// +// Defined in DERPARSE.C +// + +extern MECH_OID g_stcMechOIDList []; + +/**********************************************************************/ +/** **/ +/** **/ +/** **/ +/** **/ +/** Local SPNEGO Helper definitions **/ +/** **/ +/** **/ +/** **/ +/** **/ +/**********************************************************************/ + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// CalculateMinSpnegoInitTokenSize +// +// Parameters: +// [in] nMechTokenLength - Length of the MechToken Element +// [in] nMechListMICLength - Length of the MechListMIC Element +// [in] mechOID - OID for MechList +// [in] nReqFlagsAvailable - Is ContextFlags element available +// [out] pnTokenSize - Filled out with total size of token +// [out] pnInternalTokenLength - Filled out with length minus length +// for initial token. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Calculates the required length for a SPNEGO NegTokenInit token based +// on the supplied variable length values and which elements are present. +// Note that because the lengths can be represented by an arbitrary +// number of bytes in DER encodings, we actually calculate the lengths +// backwards, so we always know how many bytes we will potentially be +// writing out. +// +//////////////////////////////////////////////////////////////////////////// + +int CalculateMinSpnegoInitTokenSize( long nMechTokenLength, + long nMechListMICLength, SPNEGO_MECH_OID mechOid, + int nReqFlagsAvailable, long* pnTokenSize, + long* pnInternalTokenLength ) +{ + int nReturn = SPNEGO_E_INVALID_LENGTH; + + // Start at 0. + long nTotalLength = 0; + long nTempLength= 0L; + + // We will calculate this by walking the token backwards + + // Start with MIC Element + if ( nMechListMICLength > 0L ) + { + nTempLength = ASNDerCalcElementLength( nMechListMICLength, NULL ); + + // Check for rollover error + if ( nTempLength < nMechListMICLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength += nTempLength; + } + + // Next is the MechToken + if ( nMechTokenLength > 0L ) + { + nTempLength += ASNDerCalcElementLength( nMechTokenLength, NULL ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength = nTempLength; + } + + // Next is the ReqFlags + if ( nReqFlagsAvailable ) + { + nTempLength += ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, NULL ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength = nTempLength; + } + + // Next is the MechList - This is REQUIRED + nTempLength += ASNDerCalcMechListLength( mechOid, NULL ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength = nTempLength; + + // Following four fields are the basic header tokens + + // Sequence Token + nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength = nTempLength; + + // Neg Token Identifier Token + nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength = nTempLength; + + // SPNEGO OID Token + nTempLength += g_stcMechOIDList[spnego_mech_oid_Spnego].iLen; + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength = nTempLength; + + // App Constructed Token + nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + // The internal length doesn't include the number of bytes + // for the initial token + *pnInternalTokenLength = nTotalLength; + nTotalLength = nTempLength; + + // We're done + *pnTokenSize = nTotalLength; + nReturn = SPNEGO_E_SUCCESS; + +xEndTokenInitLength: + + LOG(("CalculateMinSpnegoInitTokenSize returned %d\n",nReturn)); + return nReturn; + +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// CreateSpnegoInitToken +// +// Parameters: +// [in] MechType - OID in MechList +// [in] ucContextFlags - ContextFlags value +// [in] pbMechToken - Mech Token Binary Data +// [in] ulMechTokenLen - Length of Mech Token +// [in] pbMechListMIC - MechListMIC Binary Data +// [in] ulMechListMICn - Length of MechListMIC +// [out] pbTokenData - Buffer to write token into. +// [in] nTokenLength - Length of pbTokenData buffer +// [in] nInternalTokenLength - Length of full token without leading +// token bytes. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Uses DER to fill out pbTokenData with a SPNEGO NegTokenInit Token +// Note that because the lengths can be represented by an arbitrary +// number of bytes in DER encodings, we actually calculate the lengths +// backwards, so we always know how many bytes we will potentially be +// writing out. +// +//////////////////////////////////////////////////////////////////////////// + +int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType, + unsigned char ucContextFlags, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, unsigned char* pbTokenData, + long nTokenLength, long nInternalTokenLength ) +{ + int nReturn = SPNEGO_E_INVALID_LENGTH; + + // Start at 0. + long nTempLength= 0L; + long nTotalBytesWritten = 0L; + long nInternalLength = 0L; + + unsigned char* pbWriteTokenData = pbTokenData + nTokenLength; + + // Temporary buffer to hold the REQ Flags as BIT String Data + unsigned char abTempReqFlags[SPNEGO_NEGINIT_MAXLEN_REQFLAGS]; + + + // We will write the token out backwards to properly handle the cases + // where the length bytes become adjustable + + // Start with MIC Element + if ( ulMechListMICLen > 0L ) + { + nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC, + OCTETSTRING, pbMechListMIC, ulMechListMICLen ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + } // IF MechListMIC is present + + // Next is the MechToken + if ( ulMechTokenLen > 0L ) + { + nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, + OCTETSTRING, pbMechToken, ulMechTokenLen ); + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + } // IF MechToken Length is present + + // Next is the ReqFlags + if ( ucContextFlags > 0L ) + { + + nTempLength = ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, &nInternalLength ); + + // We need a byte that indicates how many bits difference between the number + // of bits used in final octet (we only have one) and the max (8) + + abTempReqFlags[0] = SPNEGO_NEGINIT_REQFLAGS_BITDIFF; + abTempReqFlags[1] = ucContextFlags; + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_REQFLAGS, + BITSTRING, abTempReqFlags, SPNEGO_NEGINIT_MAXLEN_REQFLAGS ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + } // IF ContextFlags + + // Next is the MechList - This is REQUIRED + nTempLength = ASNDerCalcMechListLength( MechType, &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteMechList( pbWriteTokenData, MechType ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + // The next tokens we're writing out reflect the total number of bytes + // we have actually written out. + + // Sequence Token + nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, + NULL, nTotalBytesWritten ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + // Neg Init Token Identifier Token + nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER, + NULL, nTotalBytesWritten ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + // SPNEGO OID Token + nTempLength = g_stcMechOIDList[spnego_mech_oid_Spnego].iLen; + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteOID( pbWriteTokenData, spnego_mech_oid_Spnego ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + // App Constructed Token + nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT, + NULL, nTotalBytesWritten ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + + // Don't adjust the internal token length here, it doesn't account + // the initial bytes written out (we really don't need to keep + // a running count here, but for debugging, it helps to be able + // to see the total number of bytes written out as well as the + // number of bytes left to write). + + if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 && + pbWriteTokenData == pbTokenData ) + { + nReturn = SPNEGO_E_SUCCESS; + } + +xEndWriteNegTokenInit: + + LOG(("CreateSpnegoInitToken returned %d\n",nReturn)); + return nReturn; + +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// CalculateMinSpnegoTargTokenSize +// +// Parameters: +// [in] MechType - Supported MechType +// [in] spnegoNegResult - Neg Result +// [in] nMechTokenLength - Length of the MechToken Element +// [in] nMechListMICLength - Length of the MechListMIC Element +// [out] pnTokenSize - Filled out with total size of token +// [out] pnInternalTokenLength - Filled out with length minus length +// for initial token. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Calculates the required length for a SPNEGO NegTokenTarg token based +// on the supplied variable length values and which elements are present. +// Note that because the lengths can be represented by an arbitrary +// number of bytes in DER encodings, we actually calculate the lengths +// backwards, so we always know how many bytes we will potentially be +// writing out. +// +//////////////////////////////////////////////////////////////////////////// + +int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType, + SPNEGO_NEGRESULT spnegoNegResult, long nMechTokenLen, + long nMechListMICLen, long* pnTokenSize, + long* pnInternalTokenLength ) +{ + int nReturn = SPNEGO_E_INVALID_LENGTH; + + // Start at 0. + long nTotalLength = 0; + long nTempLength= 0L; + + // We will calculate this by walking the token backwards + + // Start with MIC Element + if ( nMechListMICLen > 0L ) + { + nTempLength = ASNDerCalcElementLength( nMechListMICLen, NULL ); + + // Check for rollover error + if ( nTempLength < nMechListMICLen ) + { + goto xEndTokenTargLength; + } + + nTotalLength += nTempLength; + } + + // Next is the MechToken + if ( nMechTokenLen > 0L ) + { + nTempLength += ASNDerCalcElementLength( nMechTokenLen, NULL ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenTargLength; + } + + nTotalLength = nTempLength; + } + + // Supported MechType + if ( spnego_mech_oid_NotUsed != MechType ) + { + // Supported MechOID element - we use the token function since + // we already know the size of the OID token and value + nTempLength += ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen, + NULL ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenTargLength; + } + + nTotalLength = nTempLength; + + } // IF MechType is available + + // NegResult Element + if ( spnego_negresult_NotUsed != spnegoNegResult ) + { + nTempLength += ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, NULL ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenTargLength; + } + + nTotalLength = nTempLength; + + } // IF negResult is available + + // Following two fields are the basic header tokens + + // Sequence Token + nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenTargLength; + } + + nTotalLength = nTempLength; + + // Neg Token Identifier Token + nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenTargLength; + } + + // The internal length doesn't include the number of bytes + // for the initial token + *pnInternalTokenLength = nTotalLength; + nTotalLength = nTempLength; + + // We're done + *pnTokenSize = nTotalLength; + nReturn = SPNEGO_E_SUCCESS; + +xEndTokenTargLength: + + LOG(("CalculateMinSpnegoTargTokenSize returned %d\n",nReturn)); + return nReturn; + +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// CreateSpnegoTargToken +// +// Parameters: +// [in] MechType - Supported MechType +// [in] eNegResult - NegResult value +// [in] pbMechToken - Mech Token Binary Data +// [in] ulMechTokenLen - Length of Mech Token +// [in] pbMechListMIC - MechListMIC Binary Data +// [in] ulMechListMICn - Length of MechListMIC +// [out] pbTokenData - Buffer to write token into. +// [in] nTokenLength - Length of pbTokenData buffer +// [in] nInternalTokenLength - Length of full token without leading +// token bytes. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Uses DER to fill out pbTokenData with a SPNEGO NegTokenTarg Token +// Note that because the lengths can be represented by an arbitrary +// number of bytes in DER encodings, we actually calculate the lengths +// backwards, so we always know how many bytes we will potentially be +// writing out. +// +//////////////////////////////////////////////////////////////////////////// + +int CreateSpnegoTargToken( SPNEGO_MECH_OID MechType, + SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, unsigned char* pbTokenData, + long nTokenLength, long nInternalTokenLength ) +{ + int nReturn = SPNEGO_E_INVALID_LENGTH; + + // Start at 0. + long nTempLength= 0L; + long nTotalBytesWritten = 0L; + long nInternalLength = 0L; + + unsigned char ucTemp = 0; + + // We will write the token out backwards to properly handle the cases + // where the length bytes become adjustable, so the write location + // is initialized to point *just* past the end of the buffer. + + unsigned char* pbWriteTokenData = pbTokenData + nTokenLength; + + + // Start with MIC Element + if ( ulMechListMICLen > 0L ) + { + nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC, + OCTETSTRING, pbMechListMIC, ulMechListMICLen ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenTarg; + } + + } // IF MechListMIC is present + + // Next is the MechToken + if ( ulMechTokenLen > 0L ) + { + nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, + OCTETSTRING, pbMechToken, ulMechTokenLen ); + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenTarg; + } + + } // IF MechToken Length is present + + // Supported Mech Type + if ( spnego_mech_oid_NotUsed != MechType ) + { + + nTempLength = ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen, + &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH, + g_stcMechOIDList[MechType].ucOid, + g_stcMechOIDList[MechType].iLen ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenTarg; + } + + } // IF MechType is present + + // Neg Result + // NegResult Element + if ( spnego_negresult_NotUsed != eNegResult ) + { + ucTemp = (unsigned char) eNegResult; + + nTempLength = ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_NEGRESULT, + ENUMERATED, &ucTemp, SPNEGO_NEGTARG_MAXLEN_NEGRESULT ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenTarg; + } + + } // If eNegResult is available + + // The next tokens we're writing out reflect the total number of bytes + // we have actually written out. + + // Sequence Token + nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, + NULL, nTotalBytesWritten ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenTarg; + } + + // Neg Targ Token Identifier Token + nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER, + NULL, nTotalBytesWritten ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + + // Don't adjust the internal token length here, it doesn't account + // the initial bytes written out (we really don't need to keep + // a running count here, but for debugging, it helps to be able + // to see the total number of bytes written out as well as the + // number of bytes left to write). + + if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 && + pbWriteTokenData == pbTokenData ) + { + nReturn = SPNEGO_E_SUCCESS; + } + + +xEndWriteNegTokenTarg: + + LOG(("CreateSpnegoTargToken returned %d\n",nReturn)); + return nReturn; + + +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// AllocEmptySpnegoToken +// +// Parameters: +// [in] ucCopyData - Flag to copy data or pointer. +// [in] ulFlags - Flags for SPNEGO_TOKEN data member. +// [in] pbTokenData - Binary token data. +// [in] ulTokenSize - Size of pbTokenData. +// +// Returns: +// SPNEGO_TOKEN* Success - Pointer to initialized SPNEGO_TOKEN struct +// Failure - NULL +// +// Comments : +// Allocates a SPNEGO_TOKEN data structure and initializes it. Based on +// the value of ucCopyData, if non-zero, we copy the data into a buffer +// we allocate in this function, otherwise, we copy the data pointer +// direcly. +// +//////////////////////////////////////////////////////////////////////////// + +SPNEGO_TOKEN* AllocEmptySpnegoToken( unsigned char ucCopyData, unsigned long ulFlags, + unsigned char * pbTokenData, unsigned long ulTokenSize ) +{ + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) calloc( 1, sizeof(SPNEGO_TOKEN) ); + + if ( NULL != pSpnegoToken ) + { + // Set the token size + pSpnegoToken->nStructSize = SPNEGO_TOKEN_SIZE; + + // Initialize the element array + InitSpnegoTokenElementArray( pSpnegoToken ); + + // Assign the flags value + pSpnegoToken->ulFlags = ulFlags; + + // + // IF ucCopyData is TRUE, we will allocate a buffer and copy data into it. + // Otherwise, we will just copy the pointer and the length. This is so we + // can cut out additional allocations for performance reasons + // + + if ( SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA == ucCopyData ) + { + // Alloc the internal buffer. Cleanup on failure. + pSpnegoToken->pbBinaryData = (unsigned char*) calloc( ulTokenSize, sizeof(unsigned char) ); + + if ( NULL != pSpnegoToken->pbBinaryData ) + { + // We must ALWAYS free this buffer + pSpnegoToken->ulFlags |= SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA; + + // Copy the data locally + memcpy( pSpnegoToken->pbBinaryData, pbTokenData, ulTokenSize ); + pSpnegoToken->ulBinaryDataLen = ulTokenSize; + } + else + { + free( pSpnegoToken ); + pSpnegoToken = NULL; + } + + } // IF ucCopyData + else + { + // Copy the pointer and the length directly - ulFlags will control whether or not + // we are allowed to free the value + + pSpnegoToken->pbBinaryData = pbTokenData; + pSpnegoToken->ulBinaryDataLen = ulTokenSize; + } + + } + + return pSpnegoToken; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// FreeSpnegoToken +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN to free. +// +// Returns: +// void +// +// Comments : +// If non-NULL, interprets pSpnegoToken, freeing any internal allocations +// and finally the actual structure. +// +//////////////////////////////////////////////////////////////////////////// + +void FreeSpnegoToken( SPNEGO_TOKEN* pSpnegoToken ) +{ + if ( NULL != pSpnegoToken ) + { + + // Cleanup internal allocation per the flags + if ( pSpnegoToken->ulFlags & SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA && + NULL != pSpnegoToken->pbBinaryData ) + { + free( pSpnegoToken->pbBinaryData ); + pSpnegoToken->pbBinaryData = NULL; + } + + free ( pSpnegoToken ); + } +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// InitSpnegoTokenElementArray +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN structure. +// +// Returns: +// void +// +// Comments : +// Initializes the element array data member of a SPNEGO_TOKEN data +// structure. +// +//////////////////////////////////////////////////////////////////////////// + +void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken ) +{ + int nCtr; + + // Set the number of elemnts + pSpnegoToken->nNumElements = MAX_NUM_TOKEN_ELEMENTS; + + // + // Initially, all elements are unavailable + // + + for ( nCtr = 0; nCtr < MAX_NUM_TOKEN_ELEMENTS; nCtr++ ) + { + // Set the element size as well + pSpnegoToken->aElementArray[ nCtr ].nStructSize = SPNEGO_ELEMENT_SIZE; + pSpnegoToken->aElementArray[ nCtr ].iElementPresent = SPNEGO_TOKEN_ELEMENT_UNAVAILABLE; + } + +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// InitSpnegoTokenType +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN structure. +// [out] pnTokenLength - Filled out with total token length +// [out] pnRemainingTokenLength - Filled out with remaining length +// after header is parsed +// [out] ppbFirstElement - Filled out with pointer to first +// element after header info. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Walks the underlying binary data for a SPNEGO_TOKEN data structure +// and determines the type of the underlying token based on token header +// information. +// +//////////////////////////////////////////////////////////////////////////// + +int InitSpnegoTokenType( SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength, + long* pnRemainingTokenLength, unsigned char** ppbFirstElement ) +{ + int nReturn = SPNEGO_E_INVALID_TOKEN; + long nActualTokenLength = 0L; + long nBoundaryLength = pSpnegoToken->ulBinaryDataLen; + unsigned char* pbTokenData = pSpnegoToken->pbBinaryData; + + // + // First byte MUST be either an APP_CONSTRUCT or the NEGTARG_TOKEN_TARG + // + + if ( SPNEGO_NEGINIT_APP_CONSTRUCT == *pbTokenData ) + { + // Validate the above token - this will tell us the actual length of the token + // per the encoding (minus the actual token bytes) + if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT, 0L, nBoundaryLength, + pnTokenLength, &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Initialize the remaining token length value. This will be used + // to tell the caller how much token there is left once we've parsed + // the header (they could calculate it from the other values, but this + // is a bit friendlier) + *pnRemainingTokenLength = *pnTokenLength; + + // Make adjustments to next token + pbTokenData += nActualTokenLength; + nBoundaryLength -= nActualTokenLength; + + // The next token should be an OID + if ( ( nReturn = ASNDerCheckOID( pbTokenData, spnego_mech_oid_Spnego, nBoundaryLength, + &nActualTokenLength ) ) == SPNEGO_E_SUCCESS ) + { + // Make adjustments to next token + pbTokenData += nActualTokenLength; + nBoundaryLength -= nActualTokenLength; + *pnRemainingTokenLength -= nActualTokenLength; + + // The next token should specify the NegTokenInit + if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER, + *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, + &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Make adjustments to next token + pbTokenData += nActualTokenLength; + nBoundaryLength -= nActualTokenLength; + *pnRemainingTokenLength -= nActualTokenLength; + + // The next token should specify the start of a sequence + if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, + *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, + &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // NegTokenInit header is now checked out! + + // Make adjustments to next token + *pnRemainingTokenLength -= nActualTokenLength; + + // Store pointer to first element + *ppbFirstElement = pbTokenData + nActualTokenLength; + pSpnegoToken->ucTokenType = SPNEGO_TOKEN_INIT; + } // IF Check Sequence Token + + } // IF Check NegTokenInit token + + + } // IF Check for SPNEGO OID + + + } // IF check app construct token + + } + else if ( SPNEGO_NEGTARG_TOKEN_IDENTIFIER == *pbTokenData ) + { + + // The next token should specify the NegTokenInit + if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER, + *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, + &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Initialize the remaining token length value. This will be used + // to tell the caller how much token there is left once we've parsed + // the header (they could calculate it from the other values, but this + // is a bit friendlier) + *pnRemainingTokenLength = *pnTokenLength; + + // Make adjustments to next token + pbTokenData += nActualTokenLength; + nBoundaryLength -= nActualTokenLength; + + // The next token should specify the start of a sequence + if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, + *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, + &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // NegTokenInit header is now checked out! + + // Make adjustments to next token + *pnRemainingTokenLength -= nActualTokenLength; + + // Store pointer to first element + *ppbFirstElement = pbTokenData + nActualTokenLength; + pSpnegoToken->ucTokenType = SPNEGO_TOKEN_TARG; + } // IF Check Sequence Token + + } // IF Check NegTokenInit token + + } // ELSE IF it's a NegTokenTarg + + LOG(("InitSpnegoTokenType returned %d\n",nReturn)); + return nReturn; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// GetSpnegoInitTokenMechList +// +// Parameters: +// [in] pbTokenData - Points to binary MechList element +// in NegTokenInit. +// [in] nMechListLength - Length of the MechList +// [out] pSpnegoElement - Filled out with MechList Element +// data. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Checks that pbTokenData is pointing at something that at least +// *looks* like a MechList and then fills out the supplied +// SPNEGO_ELEMENT structure. +// +//////////////////////////////////////////////////////////////////////////// + +int GetSpnegoInitTokenMechList( unsigned char* pbTokenData, int nMechListLength, + SPNEGO_ELEMENT* pSpnegoElement ) +{ + int nReturn = SPNEGO_E_INVALID_TOKEN; + long nLength = 0L; + long nActualTokenLength = 0L; + + // Actual MechList is prepended by a Constructed Sequence Token + if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, + nMechListLength, nMechListLength, + &nLength, &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Adjust for this token + nMechListLength -= nActualTokenLength; + pbTokenData += nActualTokenLength; + + // Perform simple validation of the actual MechList (i.e. ensure that + // the OIDs in the MechList are reasonable). + + if ( ( nReturn = ValidateMechList( pbTokenData, nLength ) ) == SPNEGO_E_SUCCESS ) + { + // Initialize the element now + pSpnegoElement->eElementType = spnego_init_mechtypes; + pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; + pSpnegoElement->type = SPNEGO_MECHLIST_TYPE; + pSpnegoElement->nDatalength = nLength; + pSpnegoElement->pbData = pbTokenData; + } + + } // IF Check Token + + LOG(("GetSpnegoInitTokenMechList returned %d\n",nReturn)); + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// InitSpnegoTokenElementFromBasicType +// +// Parameters: +// [in] pbTokenData - Points to binary element data in +// a SPNEGO token. +// [in] nElementLength - Length of the element +// [in] ucExpectedType - Expected DER type. +// [in] spnegoElementType - Which element is this? +// [out] pSpnegoElement - Filled out with element data. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Checks that pbTokenData is pointing at the specified DER type. If so, +// then we verify that lengths are proper and then fill out the +// SPNEGO_ELEMENT data structure. +// +//////////////////////////////////////////////////////////////////////////// + +int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData, int nElementLength, + unsigned char ucExpectedType, + SPNEGO_ELEMENT_TYPE spnegoElementType, + SPNEGO_ELEMENT* pSpnegoElement ) +{ + int nReturn = SPNEGO_E_UNEXPECTED_TYPE; + long nLength = 0L; + long nActualTokenLength = 0L; + + // The type BYTE must match our token data or something is badly wrong + if ( *pbTokenData == ucExpectedType ) + { + + // Check that we are pointing at the specified type + if ( ( nReturn = ASNDerCheckToken( pbTokenData, ucExpectedType, + nElementLength, nElementLength, + &nLength, &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Adjust for this token + nElementLength -= nActualTokenLength; + pbTokenData += nActualTokenLength; + + // Initialize the element now + pSpnegoElement->eElementType = spnegoElementType; + pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; + pSpnegoElement->type = ucExpectedType; + pSpnegoElement->nDatalength = nLength; + pSpnegoElement->pbData = pbTokenData; + } + + } // IF type makes sense + + LOG(("InitSpnegoTokenElementFromBasicType returned %d\n",nReturn)); + return nReturn; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// InitSpnegoTokenElementFromOID +// +// Parameters: +// [in] pbTokenData - Points to binary element data in +// a SPNEGO token. +// [in] nElementLength - Length of the element +// [in] spnegoElementType - Which element is this? +// [out] pSpnegoElement - Filled out with element data. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Initializes a SpnegoElement from an OID - normally, this would have +// used the Basic Type function above, but since we do binary compares +// on the OIDs against the DER information as well as the OID, we need +// to account for that. +// +//////////////////////////////////////////////////////////////////////////// + +int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData, int nElementLength, + SPNEGO_ELEMENT_TYPE spnegoElementType, + SPNEGO_ELEMENT* pSpnegoElement ) +{ + int nReturn = SPNEGO_E_UNEXPECTED_TYPE; + long nLength = 0L; + long nActualTokenLength = 0L; + + // The type BYTE must match our token data or something is badly wrong + if ( *pbTokenData == OID ) + { + + // Check that we are pointing at an OID type + if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID, + nElementLength, nElementLength, + &nLength, &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Don't adjust any values for this function + + // Initialize the element now + pSpnegoElement->eElementType = spnegoElementType; + pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; + pSpnegoElement->type = OID; + pSpnegoElement->nDatalength = nElementLength; + pSpnegoElement->pbData = pbTokenData; + } + + } // IF type makes sense + + LOG(("InitSpnegoTokenElementFromBasicType returned %d\n",nReturn)); + return nReturn; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// InitSpnegoTokenElements +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN struct +// [in] pbTokenData - Points to initial binary element +// data in a SPNEGO token. +// [in] nRemainingTokenLength - Length remaining past header +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Interprets the data at pbTokenData based on the TokenType in +// pSpnegoToken. Since some elements are optional (technically all are +// but the token becomes quite useless if this is so), we check if +// an element exists before filling out the element in the array. +// +//////////////////////////////////////////////////////////////////////////// + +int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData, + long nRemainingTokenLength ) +{ + // + // The following arrays contain the token identifiers for the elements + // comprising the actual token. All values are optional, and there are + // no defaults. + // + + static unsigned char abNegTokenInitElements[] = + { SPNEGO_NEGINIT_ELEMENT_MECHTYPES, SPNEGO_NEGINIT_ELEMENT_REQFLAGS, + SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC }; + + static unsigned char abNegTokenTargElements[] = + { SPNEGO_NEGTARG_ELEMENT_NEGRESULT, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH, + SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC }; + + int nReturn = SPNEGO_E_SUCCESS; + int nCtr = 0L; + long nElementLength = 0L; + long nActualTokenLength = 0L; + unsigned char* pbElements = NULL; + + // Point to the correct array + switch( pSpnegoToken->ucTokenType ) + { + case SPNEGO_TOKEN_INIT: + { + pbElements = abNegTokenInitElements; + } + break; + + case SPNEGO_TOKEN_TARG: + { + pbElements = abNegTokenTargElements; + } + break; + + } // SWITCH tokentype + + // + // Enumerate the element arrays and look for the tokens at our current location + // + + for ( nCtr = 0L; + SPNEGO_E_SUCCESS == nReturn && + nCtr < MAX_NUM_TOKEN_ELEMENTS && + nRemainingTokenLength > 0L; + nCtr++ ) + { + + // Check if the token exists + if ( ( nReturn = ASNDerCheckToken( pbTokenData, pbElements[nCtr], + 0L, nRemainingTokenLength, + &nElementLength, &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + + // Token data should skip over the sequence token and then + // call the appropriate function to initialize the element + pbTokenData += nActualTokenLength; + + // Lengths in the elements should NOT go beyond the element + // length + + // Different tokens mean different elements + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + + // Handle each element as appropriate + switch( pbElements[nCtr] ) + { + + case SPNEGO_NEGINIT_ELEMENT_MECHTYPES: + { + // + // This is a Mech List that specifies which OIDs the + // originator of the Init Token supports. + // + + nReturn = GetSpnegoInitTokenMechList( pbTokenData, nElementLength, + &pSpnegoToken->aElementArray[nCtr] ); + + } + break; + + case SPNEGO_NEGINIT_ELEMENT_REQFLAGS: + { + // + // This is a BITSTRING which specifies the flags that the receiver + // pass to the gss_accept_sec_context() function. + // + + nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, + BITSTRING, spnego_init_reqFlags, + &pSpnegoToken->aElementArray[nCtr] ); + } + break; + + case SPNEGO_NEGINIT_ELEMENT_MECHTOKEN: + { + // + // This is an OCTETSTRING which contains a GSSAPI token corresponding + // to the first OID in the MechList. + // + + nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, + OCTETSTRING, spnego_init_mechToken, + &pSpnegoToken->aElementArray[nCtr] ); + } + break; + + case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC: + { + // + // This is an OCTETSTRING which contains a message integrity BLOB. + // + + nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, + OCTETSTRING, spnego_init_mechListMIC, + &pSpnegoToken->aElementArray[nCtr] ); + } + break; + + } // SWITCH Element + } + else + { + + switch( pbElements[nCtr] ) + { + + case SPNEGO_NEGTARG_ELEMENT_NEGRESULT: + { + // + // This is an ENUMERATION which specifies result of the last GSS + // token negotiation call. + // + + nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, + ENUMERATED, spnego_targ_negResult, + &pSpnegoToken->aElementArray[nCtr] ); + } + break; + + case SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH: + { + // + // This is an OID which specifies a supported mechanism. + // + + nReturn = InitSpnegoTokenElementFromOID( pbTokenData, nElementLength, + spnego_targ_mechListMIC, + &pSpnegoToken->aElementArray[nCtr] ); + } + break; + + case SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN: + { + // + // This is an OCTETSTRING which specifies results of the last GSS + // token negotiation call. + // + + nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, + OCTETSTRING, spnego_targ_responseToken, + &pSpnegoToken->aElementArray[nCtr] ); + } + break; + + case SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC: + { + // + // This is an OCTETSTRING which specifies a message integrity BLOB. + // + + nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, + OCTETSTRING, spnego_targ_mechListMIC, + &pSpnegoToken->aElementArray[nCtr] ); + } + break; + + } // SWITCH Element + + } // ELSE !NegTokenInit + + // Account for the entire token and following data + nRemainingTokenLength -= ( nActualTokenLength + nElementLength ); + + // Token data should skip past the element length now + pbTokenData += nElementLength; + + } // IF Token found + else if ( SPNEGO_E_TOKEN_NOT_FOUND == nReturn ) + { + // For now, this is a benign error (remember, all elements are optional, so + // if we don't find one, it's okay). + + nReturn = SPNEGO_E_SUCCESS; + } + + } // FOR enum elements + + // + // We should always run down to 0 remaining bytes in the token. If not, we've got + // a bad token. + // + + if ( SPNEGO_E_SUCCESS == nReturn && nRemainingTokenLength != 0L ) + { + nReturn = SPNEGO_E_INVALID_TOKEN; + } + + LOG(("InitSpnegoTokenElements returned %d\n",nReturn)); + return nReturn; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// FindMechOIDInMechList +// +// Parameters: +// [in] pSpnegoElement - SPNEGO_ELEMENT for MechList +// [in] MechOID - OID we're looking for. +// [out] piMechTypeIndex - Index in the list where OID was +// found +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Walks the MechList for MechOID. When it is found, the index in the +// list is written to piMechTypeIndex. +// +//////////////////////////////////////////////////////////////////////////// + +int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID, + int * piMechTypeIndex ) +{ + int nReturn = SPNEGO_E_NOT_FOUND; + int nCtr = 0; + long nLength = 0L; + long nBoundaryLength = pSpnegoElement->nDatalength; + unsigned char* pbMechListData = pSpnegoElement->pbData; + + while( SPNEGO_E_SUCCESS != nReturn && nBoundaryLength > 0L ) + { + + // Use the helper function to check the OID + if ( ( nReturn = ASNDerCheckOID( pbMechListData, MechOID, nBoundaryLength, &nLength ) ) + == SPNEGO_E_SUCCESS ) + { + *piMechTypeIndex = nCtr; + } + + // Adjust for the current OID + pbMechListData += nLength; + nBoundaryLength -= nLength; + nCtr++; + + } // WHILE enuming OIDs + + LOG(("FindMechOIDInMechList returned %d\n",nReturn)); + return nReturn; + +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ValidateMechList +// +// Parameters: +// [in] pbMechListData - Pointer to binary MechList data +// [in] nBoundaryLength - Length we must not exceed +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Checks the data at pbMechListData to see if it looks like a MechList. +// As part of this, we walk the list and ensure that none of the OIDs +// have a length that takes us outside of nBoundaryLength. +// +//////////////////////////////////////////////////////////////////////////// + +int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength ) +{ + int nReturn = SPNEGO_E_SUCCESS; + long nLength = 0L; + long nTokenLength = 0L; + + while( SPNEGO_E_SUCCESS == nReturn && nBoundaryLength > 0L ) + { + // Verify that we have something that at least *looks* like an OID - in other + // words it has an OID identifier and specifies a length that doesn't go beyond + // the size of the list. + nReturn = ASNDerCheckToken( pbMechListData, OID, 0L, nBoundaryLength, + &nLength, &nTokenLength ); + + // Adjust for the current OID + pbMechListData += ( nLength + nTokenLength ); + nBoundaryLength -= ( nLength + nTokenLength ); + + } // WHILE enuming OIDs + + LOG(("ValidateMechList returned %d\n",nReturn)); + return nReturn; + +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// IsValidMechOid +// +// Parameters: +// [in] mechOid - mechOID id enumeration +// +// Returns: +// int Success - 1 +// Failure - 0 +// +// Comments : +// Checks for a valid mechOid value. +// +//////////////////////////////////////////////////////////////////////////// + +int IsValidMechOid( SPNEGO_MECH_OID mechOid ) +{ + LOG(("IsValidMechOid returned %d\n",mechOid >= spnego_mech_oid_Kerberos_V5_Legacy && + mechOid <= spnego_mech_oid_Spnego)); + return ( mechOid >= spnego_mech_oid_Kerberos_V5_Legacy && + mechOid <= spnego_mech_oid_Spnego ); +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// IsValidContextFlags +// +// Parameters: +// [in] ucContextFlags - ContextFlags value +// +// Returns: +// int Success - 1 +// Failure - 0 +// +// Comments : +// Checks for a valid ContextFlags value. +// +//////////////////////////////////////////////////////////////////////////// + +int IsValidContextFlags( unsigned char ucContextFlags ) +{ + // Mask out our valid bits. If there is anything leftover, this + // is not a valid value for Context Flags + LOG(("IsValidContextFlags returned %d\n",(( ucContextFlags & ~SPNEGO_NEGINIT_CONTEXT_MASK ) == 0))); + return ( ( ucContextFlags & ~SPNEGO_NEGINIT_CONTEXT_MASK ) == 0 ); +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// IsValidNegResult +// +// Parameters: +// [in] negResult - NegResult value +// +// Returns: +// int Success - 1 +// Failure - 0 +// +// Comments : +// Checks for a valid NegResult value. +// +//////////////////////////////////////////////////////////////////////////// + +int IsValidNegResult( SPNEGO_NEGRESULT negResult ) +{ + LOG(("IsValidNegResult returned %d\n",negResult >= spnego_negresult_success && + negResult <= spnego_negresult_rejected )); + return ( negResult >= spnego_negresult_success && + negResult <= spnego_negresult_rejected ); +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// IsValidSpnegoToken +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure +// +// Returns: +// int Success - 1 +// Failure - 0 +// +// Comments : +// Performs simple heuristic on location pointed to by pSpnegoToken. +// +//////////////////////////////////////////////////////////////////////////// + +int IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken ) +{ + int nReturn = 0; + + // Parameter should be non-NULL + if ( NULL != pSpnegoToken ) + { + // Length should be at least the size defined in the header + if ( pSpnegoToken->nStructSize >= SPNEGO_TOKEN_SIZE ) + { + // Number of elements should be >= our maximum - if it's greater, that's + // okay, since we'll only be accessing the elements up to MAX_NUM_TOKEN_ELEMENTS + if ( pSpnegoToken->nNumElements >= MAX_NUM_TOKEN_ELEMENTS ) + { + // Check for proper token type + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType || + SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType ) + { + nReturn = 1; + } + } + + } // IF struct size makes sense + + } // IF non-NULL spnego Token + + LOG(("IsValidSpnegoToken returned %d\n",nReturn)); + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// IsValidSpnegoElement +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure +// [in] spnegoElement - spnegoElement Type from enumeration +// +// Returns: +// int Success - 1 +// Failure - 0 +// +// Comments : +// Checks that spnegoElement has a valid value and is appropriate for +// the SPNEGO token encapsulated by pSpnegoToken. +// +//////////////////////////////////////////////////////////////////////////// + +int IsValidSpnegoElement( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement ) +{ + int nReturn = 0; + + // Check boundaries + if ( spnegoElement > spnego_element_min && + spnegoElement < spnego_element_max ) + { + + // Check for appropriateness to token type + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + nReturn = ( spnegoElement >= spnego_init_mechtypes && + spnegoElement <= spnego_init_mechListMIC ); + } + else + { + nReturn = ( spnegoElement >= spnego_targ_negResult && + spnegoElement <= spnego_targ_mechListMIC ); + } + + } // IF boundary conditions are met + + LOG(("IsValidSpnegoElement returned %d\n",nReturn)); + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// CalculateElementArrayIndex +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure +// [in] spnegoElement - spnegoElement Type from enumeration +// +// Returns: +// int index in the SPNEGO_TOKEN element array that the element can +// can be found +// +// Comments : +// Based on the Token Type, calculates the index in the element array +// at which the specified element can be found. +// +//////////////////////////////////////////////////////////////////////////// + +int CalculateElementArrayIndex( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement ) +{ + int nReturn = 0; + + // Offset is difference between value and initial element identifier + // (these differ based on ucTokenType) + + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + nReturn = spnegoElement - spnego_init_mechtypes; + } + else + { + nReturn = spnegoElement - spnego_targ_negResult; + } + + LOG(("CalculateElementArrayIndex returned %d\n",nReturn)); + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// InitTokenFromBinary +// +// Parameters: +// [in] ucCopyData - Flag indicating if data should be copied +// [in] ulFlags - Flags value for structure +// [in] pnTokenData - Binary Token Data +// [in] ulLength - Length of the data +// [out] ppSpnegoToken - Pointer to call allocated SPNEGO Token +// data structure +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Allocates a SPNEGO_TOKEN data structure and fills it out as +// appropriate based in the flags passed into the function. +// +//////////////////////////////////////////////////////////////////////////// + + +// Initializes SPNEGO_TOKEN structure from DER encoded binary data +int InitTokenFromBinary( unsigned char ucCopyData, unsigned long ulFlags, + unsigned char* pbTokenData, unsigned long ulLength, + SPNEGO_TOKEN** ppSpnegoToken ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = NULL; + unsigned char* pbFirstElement = NULL; + long nTokenLength = 0L; + long nRemainingTokenLength = 0L; + + // Basic Parameter Validation + + if ( NULL != pbTokenData && + NULL != ppSpnegoToken && + 0L != ulLength ) + { + + // + // Allocate the empty token, then initialize the data structure. + // + + pSpnegoToken = AllocEmptySpnegoToken( ucCopyData, ulFlags, pbTokenData, ulLength ); + + if ( NULL != pSpnegoToken ) + { + + // Copy the binary data locally + + + // Initialize the token type + if ( ( nReturn = InitSpnegoTokenType( pSpnegoToken, &nTokenLength, + &nRemainingTokenLength, &pbFirstElement ) ) + == SPNEGO_E_SUCCESS ) + { + + // Initialize the element array + if ( ( nReturn = InitSpnegoTokenElements( pSpnegoToken, pbFirstElement, + nRemainingTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + *ppSpnegoToken = pSpnegoToken; + } + + } // IF Init Token Type + + // Cleanup on error condition + if ( SPNEGO_E_SUCCESS != nReturn ) + { + spnegoFreeData( pSpnegoToken ); + } + + } + else + { + nReturn = SPNEGO_E_OUT_OF_MEMORY; + } + + } // IF Valid parameters + + + LOG(("InitTokenFromBinary returned %d\n",nReturn)); + return nReturn; +} diff --git a/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegoparse.h b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegoparse.h new file mode 100644 index 0000000000..c60ec60493 --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegoparse.h @@ -0,0 +1,169 @@ +// Copyright (C) 2002 Microsoft Corporation +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" +// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +// OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY +// AND/OR FITNESS FOR A PARTICULAR PURPOSE. +// +// Date - 10/08/2002 +// Author - Sanj Surati + +///////////////////////////////////////////////////////////// +// +// SPNEGOPARSE.H +// +// SPNEGO Token Parser Header File +// +// Contains the definitions required to properly parse a +// SPNEGO token using ASN.1 DER helpers. +// +///////////////////////////////////////////////////////////// + +#ifndef __SPNEGOPARSE_H__ +#define __SPNEGOPARSE_H__ + +// C++ Specific +#if defined(__cplusplus) +extern "C" +{ +#endif + +// Indicates if we copy data when creating a SPNEGO_TOKEN structure or not +#define SPNEGO_TOKEN_INTERNAL_COPYPTR 0 +#define SPNEGO_TOKEN_INTERNAL_COPYDATA 0x1 + +// Internal flag dictates whether or not we will free the binary data when +// the SPNEG_TOKEN structure is destroyed +#define SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA 0x1 + + // +// Each SPNEGO Token Type can be broken down into a +// maximum of 4 separate elements. +// + +#define MAX_NUM_TOKEN_ELEMENTS 4 + +// +// Element offsets in the array +// + +// INIT elements +#define SPNEGO_INIT_MECHTYPES_ELEMENT 0 +#define SPNEGO_INIT_REQFLAGS_ELEMENT 1 +#define SPNEGO_INIT_MECHTOKEN_ELEMENT 2 +#define SPNEGO_INIT_MECHLISTMIC_ELEMENT 3 + +// Response elements +#define SPNEGO_TARG_NEGRESULT_ELEMENT 0 +#define SPNEGO_TARG_SUPPMECH_ELEMENT 1 +#define SPNEGO_TARG_RESPTOKEN_ELEMENT 2 +#define SPNEGO_TARG_MECHLISTMIC_ELEMENT 3 + +// +// Defines an individual SPNEGO Token Element. +// + +typedef struct SpnegoElement +{ + size_t nStructSize; // Size of the element structure + int iElementPresent; // Is the field present? Must be either + // SPNEGO_TOKEN_ELEMENT_UNAVAILABLE or + // SPNEGO_TOKEN_ELEMENT_AVAILABLE + + SPNEGO_ELEMENT_TYPE eElementType; // The Element Type + + unsigned char type; // Data Type + + unsigned char* pbData; // Points to actual Data + + unsigned long nDatalength; // Actual Data Length + +} SPNEGO_ELEMENT; + +// Structure size in case we later choose to extend the structure +#define SPNEGO_ELEMENT_SIZE sizeof(SPNEGO_ELEMENT) + +// +// Packages a SPNEGO Token Encoding. There are two types of +// encodings: NegTokenInit and NegTokenTarg. Each encoding can +// contain up to four distinct, optional elements. +// + +typedef struct SpnegoToken +{ + size_t nStructSize; // Size of the Token structure + unsigned long ulFlags; // Internal Structure Flags - Reserved! + int ucTokenType; // Token Type - Must be + // SPNEGO_TOKEN_INIT or + // SPNEGO_TOKEN_TARG + + unsigned char* pbBinaryData; // Points to binary token data + + unsigned long ulBinaryDataLen; // Length of the actual binary data + int nNumElements; // Number of elements + SPNEGO_ELEMENT aElementArray [MAX_NUM_TOKEN_ELEMENTS]; // Holds the elements for the token +} SPNEGO_TOKEN; + +// Structure size in case we later choose to extend the structure +#define SPNEGO_TOKEN_SIZE sizeof(SPNEGO_TOKEN) + +// +// Function definitions +// + +SPNEGO_TOKEN* AllocEmptySpnegoToken( unsigned char ucCopyData, unsigned long ulFlags, + unsigned char * pbTokenData, unsigned long ulTokenSize ); +void FreeSpnegoToken( SPNEGO_TOKEN* pSpnegoToken ); +void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken ); +int InitSpnegoTokenType( SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength, + long* pnRemainingTokenLength, unsigned char** ppbFirstElement ); +int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData, + long nRemainingTokenLength ); +int GetSpnegoInitTokenMechList( unsigned char* pbTokenData, int nMechListLength, + SPNEGO_ELEMENT* pSpnegoElement ); +int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData, int nElementLength, + unsigned char ucExpectedType, + SPNEGO_ELEMENT_TYPE spnegoElementType, + SPNEGO_ELEMENT* pSpnegoElement ); +int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData, int nElementLength, + SPNEGO_ELEMENT_TYPE spnegoElementType, + SPNEGO_ELEMENT* pSpnegoElement ); +int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID, + int * piMechTypeIndex ); +int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength ); +int CalculateMinSpnegoInitTokenSize( long nMechTokenLength, long nMechListMICLength, + SPNEGO_MECH_OID mechOid, int nReqFlagsAvailable, + long* plTokenSize, long* plInternalLength ); +int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType, SPNEGO_NEGRESULT spnegoNegResult, + long nMechTokenLen, + long nMechTokenMIC, long* pnTokenSize, + long* pnInternalTokenLength ); +int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType, + unsigned char ucContextFlags, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, unsigned char* pbTokenData, + long nTokenLength, long nInternalTokenLength ); +int CreateSpnegoTargToken( SPNEGO_MECH_OID MechType, + SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, unsigned char* pbTokenData, + long nTokenLength, long nInternalTokenLength ); +int IsValidMechOid( SPNEGO_MECH_OID mechOid ); +int IsValidContextFlags( unsigned char ucContextFlags ); +int IsValidNegResult( SPNEGO_NEGRESULT negResult ); +int IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken ); +int IsValidSpnegoElement( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement ); +int CalculateElementArrayIndex( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement ); +int InitTokenFromBinary( unsigned char ucCopyData, unsigned long ulFlags, + unsigned char* pbTokenData, unsigned long ulLength, + SPNEGO_TOKEN** ppSpnegoToken ); + + // C++ Specific +#if defined(__cplusplus) +} +#endif + +#endif + diff --git a/helpers/negotiate_auth/squid_kerb_auth/squid_kerb_auth.c b/helpers/negotiate_auth/squid_kerb_auth/squid_kerb_auth.c new file mode 100755 index 0000000000..fa4b4836ce --- /dev/null +++ b/helpers/negotiate_auth/squid_kerb_auth/squid_kerb_auth.c @@ -0,0 +1,515 @@ +/* + * ----------------------------------------------------------------------------- + * + * 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. + * + * ----------------------------------------------------------------------------- + */ +/* + * Hosted at http://sourceforge.net/projects/squidkerbauth + */ +#include +#include +#include +#include +#include +#include +#include + +#include "base64.h" +#ifndef HAVE_SPNEGO +#include "spnegohelp.h" +#endif + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN HOST_NAME_MAX +#endif + +#define PROGRAM "squid_kerb_auth" + +#ifdef HEIMDAL +#include +#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE +#else +#include +#ifndef SOLARIS_11 +#include +#else +#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE +#endif +#endif + +#include +int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status, const char* function, int debug, int loging); +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(&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[MAXHOSTNAMELEN]; + struct addrinfo *hres=NULL, *hres_list; + int rc,count; + + rc = gethostname(hostname,MAXHOSTNAMELEN); + if (rc) + { + fprintf(stderr, "%s| %s: error while resolving hostname '%s'\n", LogTime(), PROGRAM, hostname); + return NULL; + } + rc = getaddrinfo(hostname,NULL,NULL,&hres); + if (rc != 0) { + fprintf(stderr, "%s| %s: error while resolving hostname with getaddrinfo: %s\n", LogTime(), PROGRAM, gai_strerror(rc)); + return NULL; + } + hres_list=hres; + count=0; + while (hres_list) { + count++; + hres_list=hres_list->ai_next; + } + rc = getnameinfo (hres->ai_addr, hres->ai_addrlen,hostname, sizeof (hostname), NULL, 0, 0); + if (rc != 0) { + fprintf(stderr, "%s| %s: error while resolving ip address with getnameinfo: %s\n", LogTime(), PROGRAM, gai_strerror(rc)); + freeaddrinfo(hres); + return NULL ; + } + + freeaddrinfo(hres); + hostname[MAXHOSTNAMELEN]='\0'; + return(strdup(hostname)); +} + +int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status, const char* function, int debug, int loging) { + 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: %s failed: %s\n", LogTime(), PROGRAM, function, buf); + fprintf(stdout, "NA %s failed: %s\n",function, buf); + if (loging) + fprintf(stderr, "%s| %s: User not authenticated\n", LogTime(), PROGRAM); + return(1); + } + return(0); +} + + + +int main(int argc, char * const argv[]) +{ + char buf[6400]; + char *c; + int length=0; + static int err=0; + int opt, rc, debug=0, loging=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_cred_id_t delegated_cred = 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; + size_t kerberosTokenLength = 0; + const unsigned char *spnegoToken = NULL ; + size_t spnegoTokenLength = 0; + + setbuf(stdout,NULL); + setbuf(stdin,NULL); + + while (-1 != (opt = getopt(argc, argv, "dis:h"))) { + switch (opt) { + case 'd': + debug = 1; + break; + case 'i': + loging = 1; + break; + case 's': + service_principal = strdup(optarg); + break; + case 'h': + fprintf(stdout, "Usage: \n"); + fprintf(stdout, "squid_kerb_auth -d [-s SPN]\n"); + fprintf(stdout, "SPN = service principal name\n"); + fprintf(stdout, "Can be set to GSS_C_NO_NAME to allow any entry from keytab\n"); + fprintf(stdout, "default SPN is HTTP/fqdn@DEFAULT_REALM\n"); + break; + default: + fprintf(stderr, "%s| %s: unknown option: -%c.\n", LogTime(), PROGRAM, opt); + } + } + + 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: Local hostname could not be determined. Please specify the service principal\n", LogTime(), PROGRAM); + exit(-1); + } + service.value = malloc(strlen(service_name)+strlen(host_name)+2); + snprintf(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: fgets() failed! dying..... errno=%d (%s)\n", LogTime(), PROGRAM, ferror(stdin), + strerror(ferror(stdin))); + + exit(1); /* BIIG buffer */ + } + exit(0); + } + + c=memchr(buf,'\n',sizeof(buf)-1); + if (c) { + *c = '\0'; + length = c-buf; + } else { + err = 1; + } + if (err) { + if (debug) + fprintf(stderr, "%s| %s: Oversized message\n", LogTime(), PROGRAM); + fprintf(stdout, "NA Oversized message\n"); + err = 0; + continue; + } + + if (debug) + fprintf(stderr, "%s| %s: Got '%s' from squid (length: %d).\n", LogTime(), PROGRAM, buf?buf:"NULL",length); + + if (buf[0] == '\0') { + if (debug) + fprintf(stderr, "%s| %s: Invalid request\n", LogTime(), PROGRAM); + fprintf(stdout, "NA Invalid request\n"); + continue; + } + + if (strlen(buf) < 2) { + if (debug) + fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(), PROGRAM, buf); + fprintf(stdout, "NA 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); + gss_release_cred(&minor_status, &delegated_cred); + gss_release_name(&minor_status, &server_name); + gss_release_name(&minor_status, &client_name); + gss_delete_sec_context(&minor_status, &gss_context, NULL); + if (kerberosToken) { + /* Allocated by parseNegTokenInit, but no matching free function exists.. */ + if (!spnego_flag) + free((char *)kerberosToken); + kerberosToken=NULL; + } + if (spnego_flag) { + /* Allocated by makeNegTokenTarg, but no matching free function exists.. */ + if (spnegoToken) + free((char *)spnegoToken); + spnegoToken=NULL; + } + if (token) { + free(token); + token=NULL; + } + if (host_name) { + free(host_name); + host_name=NULL; + } + exit(0); + } + + if ( !strncmp(buf, "YR", 2) && !strncmp(buf, "KK", 2) ) { + if (debug) + fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(), PROGRAM, buf); + fprintf(stdout, "NA 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: Invalid negotiate request [%s]\n", LogTime(), PROGRAM, buf); + fprintf(stdout, "NA Invalid negotiate request\n"); + continue; + } + + input_token.length = base64_decode_len(buf+3); + input_token.value = malloc(input_token.length); + + base64_decode(input_token.value,buf+3,input_token.length); + + +#ifndef HAVE_SPNEGO + if (( rc=parseNegTokenInit (input_token.value, + input_token.length, + &kerberosToken, + &kerberosTokenLength))!=0 ){ + if (debug) + fprintf(stderr, "%s| %s: parseNegTokenInit failed with rc=%d\n", LogTime(), PROGRAM, rc); + + /* if between 100 and 200 it might be a GSSAPI token and not a SPNEGO token */ + if ( rc < 100 || rc > 199 ) { + if (debug) + fprintf(stderr, "%s| %s: Invalid GSS-SPNEGO query [%s]\n", LogTime(), PROGRAM, buf); + fprintf(stdout, "NA Invalid GSS-SPNEGO query\n"); + goto cleanup; + } + 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", LogTime(), PROGRAM, (int) *((unsigned char *)input_token.value + sizeof ntlmProtocol)); + fprintf(stdout, "NA received type %d NTLM token\n",(int) *((unsigned char *)input_token.value + sizeof ntlmProtocol)); + goto cleanup; + } + spnego_flag=0; + } else { + gss_release_buffer(&minor_status, &input_token); + input_token.length=kerberosTokenLength; + input_token.value=(void *)kerberosToken; + spnego_flag=1; + } +#else + 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", LogTime(), PROGRAM, (int) *((unsigned char *)input_token.value + sizeof ntlmProtocol)); + fprintf(stdout, "NA received type %d NTLM token\n",(int) *((unsigned char *)input_token.value + sizeof ntlmProtocol)); + goto cleanup; + } +#endif + + 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,loging) ) + 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,loging) ) + 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, + &delegated_cred); + + + if (output_token.length) { +#ifndef HAVE_SPNEGO + if (spnego_flag) { + if ((rc=makeNegTokenTarg (output_token.value, + output_token.length, + &spnegoToken, + &spnegoTokenLength))!=0 ) { + if (debug) + fprintf(stderr, "%s| %s: makeNegTokenTarg failed with rc=%d\n", LogTime(), PROGRAM, rc); + fprintf(stdout, "NA makeNegTokenTarg failed with rc=%d\n",rc); + goto cleanup; + } + } else { + spnegoToken = output_token.value; + spnegoTokenLength = output_token.length; + } +#else + spnegoToken = output_token.value; + spnegoTokenLength = output_token.length; +#endif + token = malloc(base64_encode_len(spnegoTokenLength)); + if (token == NULL) { + if (debug) + fprintf(stderr, "%s| %s: Not enough memory\n", LogTime(), PROGRAM); + fprintf(stdout, "NA Not enough memory\n"); + goto cleanup; + } + + base64_encode(token,(const char *)spnegoToken,base64_encode_len(spnegoTokenLength),spnegoTokenLength); + + if (check_gss_err(major_status,minor_status,"gss_accept_sec_context()",debug,loging) ) + goto cleanup; + if (major_status & GSS_S_CONTINUE_NEEDED) { + if (debug) + fprintf(stderr, "%s| %s: 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,loging) ) + goto cleanup; + fprintf(stdout, "AF %s %s\n",token,(char *)output_token.value); + if (debug) + fprintf(stderr, "%s| %s: AF %s %s\n", LogTime(), PROGRAM, token,(char *)output_token.value); + if (loging) + fprintf(stderr, "%s| %s: User %s authenticated\n", LogTime(), PROGRAM, (char *)output_token.value); + goto cleanup; + } else { + if (check_gss_err(major_status,minor_status,"gss_accept_sec_context()",debug,loging) ) + goto cleanup; + if (major_status & GSS_S_CONTINUE_NEEDED) { + if (debug) + fprintf(stderr, "%s| %s: continuation needed\n", LogTime(), PROGRAM); + fprintf(stdout, "NA No token to return to continue\n"); + 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,loging) ) + goto cleanup; + /* + * Return dummy token AA. May need an extra return tag then AF + */ + fprintf(stdout, "AF %s %s\n","AA==",(char *)output_token.value); + if (debug) + fprintf(stderr, "%s| %s: AF %s %s\n", LogTime(), PROGRAM, "AA==", (char *)output_token.value); + if (loging) + fprintf(stderr, "%s| %s: User %s authenticated\n", LogTime(), PROGRAM, (char *)output_token.value); + +cleanup: + gss_release_buffer(&minor_status, &input_token); + gss_release_buffer(&minor_status, &output_token); + gss_release_cred(&minor_status, &server_creds); + gss_release_cred(&minor_status, &delegated_cred); + gss_release_name(&minor_status, &server_name); + gss_release_name(&minor_status, &client_name); + if (kerberosToken) { + /* Allocated by parseNegTokenInit, but no matching free function exists.. */ + if (!spnego_flag) + free((char *)kerberosToken); + kerberosToken=NULL; + } + if (spnego_flag) { + /* Allocated by makeNegTokenTarg, but no matching free function exists.. */ + if (spnegoToken) + free((char *)spnegoToken); + spnegoToken=NULL; + } + if (token) { + free(token); + token=NULL; + } + continue; + } + } +}