]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Author: Markus Moeller <huaraz@moeller.plus.com>
authorhno <>
Mon, 25 Jun 2007 04:34:15 +0000 (04:34 +0000)
committerhno <>
Mon, 25 Jun 2007 04:34:15 +0000 (04:34 +0000)
Kerberos SPNEGO helper

Kerberos-only SPNEGO helper using MIT or Heimdal kerberos
and the refrence SPNEGO parser published by Microsoft

19 files changed:
configure.in
helpers/negotiate_auth/Makefile.am
helpers/negotiate_auth/squid_kerb_auth/COPYING [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/Makefile.am [new file with mode: 0755]
helpers/negotiate_auth/squid_kerb_auth/Makefile.in [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/base64.c [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/base64.h [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/do.sh [new file with mode: 0755]
helpers/negotiate_auth/squid_kerb_auth/readme.txt [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/spnegohelp/Makefile [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/spnegohelp/derparse.c [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/spnegohelp/derparse.h [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnego.c [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnego.h [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegohelp.c [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegohelp.h [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegoparse.c [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/spnegohelp/spnegoparse.h [new file with mode: 0644]
helpers/negotiate_auth/squid_kerb_auth/squid_kerb_auth.c [new file with mode: 0755]

index 81946907365f403b5f1b93bcd6d710220abeec28..14a2bfa41e765a5f18e415c3301f552c721c2b69 100644 (file)
@@ -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 \
index a3c9e1e58d0158b3b9640e9a90a02abc7084a50e..5aa64c4fb9842a3d059f2050abeefad0f25893a9 100755 (executable)
@@ -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 (file)
index 0000000..12d74e6
--- /dev/null
@@ -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.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/helpers/negotiate_auth/squid_kerb_auth/Makefile.am b/helpers/negotiate_auth/squid_kerb_auth/Makefile.am
new file mode 100755 (executable)
index 0000000..44908bc
--- /dev/null
@@ -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 (file)
index 0000000..09852b1
--- /dev/null
@@ -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 (file)
index 0000000..475bcc8
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Markus Moeller has modified the following code from Squid
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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 (file)
index 0000000..ebcb9bc
--- /dev/null
@@ -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 (executable)
index 0000000..c245c8c
--- /dev/null
@@ -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 (file)
index 0000000..6af777e
--- /dev/null
@@ -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 (file)
index 0000000..7fd352c
--- /dev/null
@@ -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 (file)
index 0000000..1cac0a1
--- /dev/null
@@ -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 <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#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 (file)
index 0000000..cdca9b4
--- /dev/null
@@ -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 (file)
index 0000000..deb4cd3
--- /dev/null
@@ -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 <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#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 (file)
index 0000000..a49b220
--- /dev/null
@@ -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 <stdio.h>
+  #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 (file)
index 0000000..a10bc25
--- /dev/null
@@ -0,0 +1,263 @@
+/* -----------------------------------------------------------------------------\r
+ * spnegohelp.c defines RFC 2478 SPNEGO GSS-API mechanism APIs.\r
+ *\r
+ * Author: Frank Balluffi\r
+ *\r
+ * Copyright (C) 2002-2003 All rights reserved.\r
+ *\r
+ *   This program is free software; you can redistribute it and/or modify\r
+ *   it under the terms of the GNU General Public License as published by\r
+ *   the Free Software Foundation; either version 2 of the License, or\r
+ *   (at your option) any later version.\r
+ *\r
+ *   This program is distributed in the hope that it will be useful,\r
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ *   GNU General Public License for more details.\r
+ *\r
+ *   You should have received a copy of the GNU General Public License\r
+ *   along with this program; if not, write to the Free Software\r
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.\r
+ *\r
+ * -----------------------------------------------------------------------------\r
+ */\r
+\r
+#include "spnegohelp.h"\r
+#include "spnego.h"\r
+\r
+#include <stdlib.h>\r
+\r
+int makeNegTokenTarg (const unsigned char *  kerberosToken,\r
+                      size_t                 kerberosTokenLength,\r
+                      const unsigned char ** negTokenTarg,\r
+                      size_t *               negTokenTargLength)\r
+{\r
+    SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL;\r
+    int                 rc1          = 1;\r
+    int                 rc2          = SPNEGO_E_SUCCESS;\r
+\r
+    /* Check arguments. */\r
+\r
+    if (!kerberosToken ||\r
+        !negTokenTarg  ||\r
+        !negTokenTargLength)\r
+        return 10;\r
+\r
+    /* Does IIS reply with 1.2.840.48018.1.2.2 or 1.2.840.113554.1.2.2? */\r
+\r
+    /* Does IIS always reply with accept_completed? */\r
+\r
+    /* IIS does not include a MIC. */\r
+\r
+    rc2 = spnegoCreateNegTokenTarg (spnego_mech_oid_Kerberos_V5_Legacy,\r
+                                    spnego_negresult_success,\r
+                                    (unsigned char *) kerberosToken,\r
+                                    kerberosTokenLength,\r
+                                    NULL,\r
+                                    0,\r
+                                    &hSpnegoToken);\r
+\r
+    if (rc2 != SPNEGO_E_SUCCESS)\r
+    {\r
+        rc1 = abs(rc2)+100;\r
+        goto cleanup;\r
+    }\r
+\r
+    /* Get NegTokenTarg length. */\r
+\r
+    rc2 = spnegoTokenGetBinary (hSpnegoToken,\r
+                                NULL,\r
+                                (unsigned long*) negTokenTargLength);\r
+\r
+    if (rc2 != SPNEGO_E_BUFFER_TOO_SMALL)\r
+    {\r
+        rc1 = abs(rc2)+200;\r
+        goto cleanup;\r
+    }\r
+\r
+    *negTokenTarg = malloc (*negTokenTargLength);\r
+\r
+    if (!*negTokenTarg)\r
+    {\r
+        rc1 = abs(rc2)+300;\r
+        goto cleanup;\r
+    }\r
+\r
+    /* Get NegTokenTarg data. */\r
+\r
+    rc2 = spnegoTokenGetBinary (hSpnegoToken,\r
+                              (unsigned char *) *negTokenTarg,\r
+                              (unsigned long*) negTokenTargLength);\r
+\r
+\r
+    if (rc2 != SPNEGO_E_SUCCESS)\r
+    {\r
+        rc1 = abs(rc2)+400;\r
+        goto error;\r
+    }\r
+\r
+    rc1 = 0;\r
+\r
+    goto cleanup;\r
+\r
+error:\r
+\r
+    if (*negTokenTarg)\r
+    {\r
+        free ((unsigned char *) *negTokenTarg);\r
+        *negTokenTarg = NULL;\r
+        *negTokenTargLength = 0;\r
+    }\r
+\r
+cleanup:\r
+\r
+    if (hSpnegoToken)\r
+        spnegoFreeData (hSpnegoToken);\r
+\r
+    LOG(("makeNegTokenTarg returned %d\n",rc1));\r
+    return rc1;\r
+}\r
+\r
+int parseNegTokenInit (const unsigned char *  negTokenInit,\r
+                       size_t                 negTokenInitLength,\r
+                       const unsigned char ** kerberosToken,\r
+                       size_t *               kerberosTokenLength)\r
+{\r
+    SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL;\r
+    int                 pindex       = -1;\r
+    int                 rc1          = 1;\r
+    int                 rc2          = SPNEGO_E_SUCCESS;\r
+    unsigned char       reqFlags     = 0;\r
+    int                 tokenType    = 0;\r
+\r
+    /* Check arguments. */\r
+\r
+    if (!negTokenInit  ||\r
+        !kerberosToken ||\r
+        !kerberosTokenLength)\r
+        return 10;\r
+\r
+    /* Decode SPNEGO token. */\r
+\r
+    rc2 = spnegoInitFromBinary ((unsigned char *) negTokenInit,\r
+                                negTokenInitLength,\r
+                                &hSpnegoToken);\r
+\r
+    if (rc2 != SPNEGO_E_SUCCESS)\r
+    {\r
+        rc1 = abs(rc2)+100;\r
+        goto cleanup;\r
+    }\r
+\r
+    /* Check for negTokenInit choice. */\r
+\r
+    rc2 = spnegoGetTokenType (hSpnegoToken,\r
+                              &tokenType);\r
+\r
+    if (rc2 != SPNEGO_E_SUCCESS)\r
+    {\r
+        rc1 = abs(rc2)+200;\r
+        goto cleanup;\r
+    }\r
+\r
+    if (tokenType != SPNEGO_TOKEN_INIT)\r
+    {\r
+        rc1 = abs(rc2)+300;\r
+        goto cleanup;\r
+    }\r
+\r
+   /*\r
+    Check that first mechType is 1.2.840.113554.1.2.2 or 1.2.840.48018.1.2.2.\r
+    */\r
+\r
+   /*\r
+    IE seems to reply with 1.2.840.48018.1.2.2 and then 1.2.840.113554.1.2.2.\r
+    */\r
+\r
+    rc2 = spnegoIsMechTypeAvailable (hSpnegoToken,\r
+                                     spnego_mech_oid_Kerberos_V5_Legacy,\r
+                                     &pindex);\r
+\r
+    if (rc2 != SPNEGO_E_SUCCESS ||\r
+        pindex != 0)\r
+    {\r
+        rc2 = spnegoIsMechTypeAvailable (hSpnegoToken,\r
+                                         spnego_mech_oid_Kerberos_V5,\r
+                                         &pindex);\r
+\r
+        if (rc2 != SPNEGO_E_SUCCESS ||\r
+            pindex != 0)\r
+        {\r
+            rc1 = abs(rc2)+400;\r
+            goto cleanup;\r
+        }\r
+    }\r
+\r
+    /* Check for no reqFlags. */\r
+\r
+    /* Does IE ever send reqFlags? */\r
+\r
+    rc2 = spnegoGetContextFlags (hSpnegoToken,\r
+                                 &reqFlags);\r
+\r
+    if (rc2 == SPNEGO_E_SUCCESS)\r
+    {\r
+        rc1 = abs(rc2)+500;\r
+        goto cleanup;\r
+    }\r
+\r
+    /* Get mechanism token length. */\r
+\r
+    rc2 = spnegoGetMechToken (hSpnegoToken,\r
+                              NULL,\r
+                              (unsigned long*) kerberosTokenLength);\r
+\r
+    if (rc2 != SPNEGO_E_BUFFER_TOO_SMALL)\r
+    {\r
+        rc1 = abs(rc2)+600;\r
+        goto cleanup;\r
+    }\r
+\r
+    *kerberosToken = malloc (*kerberosTokenLength);\r
+\r
+    if (!*kerberosToken)\r
+    {\r
+        rc1 = abs(rc2)+700;\r
+        goto cleanup;\r
+    }\r
+\r
+    /* Get mechanism token data. */\r
+\r
+    rc2 = spnegoGetMechToken (hSpnegoToken,\r
+                              (unsigned char *) *kerberosToken,\r
+                              (unsigned long*) kerberosTokenLength);\r
+\r
+    if (rc2 != SPNEGO_E_SUCCESS)\r
+    {\r
+        rc1 = abs(rc2)+800;\r
+        goto error;\r
+    }\r
+\r
+    /* According to Microsoft, IE does not send a MIC. */\r
+\r
+    rc1 = 0;\r
+\r
+    goto cleanup;\r
+\r
+error:\r
+\r
+    if (*kerberosToken)\r
+    {\r
+        free ((unsigned char *) *kerberosToken);\r
+        *kerberosToken = NULL;\r
+        *kerberosTokenLength = 0;\r
+    }\r
+\r
+cleanup:\r
+\r
+    if (hSpnegoToken)\r
+        spnegoFreeData (hSpnegoToken);\r
+\r
+    LOG(("parseNegTokenInit returned %d\n",rc1));\r
+    return rc1;\r
+}\r
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 (file)
index 0000000..5bcbabe
--- /dev/null
@@ -0,0 +1,58 @@
+/* -----------------------------------------------------------------------------\r
+ * spnegohelp.c declares RFC 2478 SPNEGO GSS-API mechanism APIs.\r
+ *\r
+ * Author: Frank Balluffi\r
+ *\r
+ * Copyright (C) 2002-2003. All rights reserved.\r
+ * -----------------------------------------------------------------------------\r
+ */\r
+\r
+#ifndef SPNEGOHELP_H\r
+#define SPNEGOHELP_H\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#include <stddef.h>\r
+\r
+/* -----------------------------------------------------------------------------\r
+ * makeNegTokenTarg makes an RFC 2478 SPNEGO NegTokenTarg (token) from an\r
+ * RFC 1964 Kerberos GSS-API token.\r
+ *\r
+ * If makeNegTokenTarg is successful, call free (*negTokenTarg) to free the\r
+ * memory allocated by parseNegTokenInit.\r
+ *\r
+ * Returns 0 if successful, 1 otherwise.\r
+ * -----------------------------------------------------------------------------\r
+ */\r
+\r
+int makeNegTokenTarg (const unsigned char *  kerberosToken,\r
+                      size_t                 kerberosTokenLength,\r
+                      const unsigned char ** negTokenTarg,\r
+                      size_t *               negTokenTargLength);\r
+\r
+/* -----------------------------------------------------------------------------\r
+ * parseNegTokenInit parses an RFC 2478 SPNEGO NegTokenInit (token) to extract\r
+ * an RFC 1964 Kerberos GSS-API token.\r
+ *\r
+ * If the NegTokenInit does cotain a Kerberos GSS-API token, parseNegTokenInit\r
+ * returns an error.\r
+ *\r
+ * If parseNegTokenInit is successful, call free (*kerberosToken) to\r
+ * free the memory allocated by parseNegTokenInit.\r
+ *\r
+ * Returns 0 if successful, 1 otherwise.\r
+ * -----------------------------------------------------------------------------\r
+ */\r
+\r
+int parseNegTokenInit (const unsigned char *  negTokenInit,\r
+                       size_t                 negTokenInitLength,\r
+                       const unsigned char ** kerberosToken,\r
+                       size_t *               kerberosTokenLength);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* SPNEGOHELP_H */\r
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 (file)
index 0000000..e300af5
--- /dev/null
@@ -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 <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#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 (file)
index 0000000..c60ec60
--- /dev/null
@@ -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 (executable)
index 0000000..fa4b483
--- /dev/null
@@ -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 <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+
+#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 <gssapi.h>
+#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
+#else
+#include <gssapi/gssapi.h>
+#ifndef SOLARIS_11
+#include <gssapi/gssapi_generic.h>
+#else
+#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
+#endif
+#endif
+
+#include <krb5.h>
+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;            
+    }
+  }
+}