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
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
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 \
# 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@
--- /dev/null
+ 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.
--- /dev/null
+#
+# 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
+
--- /dev/null
+# 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:
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+#!/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
--- /dev/null
+--------------------------------------------------------------------------------
+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.
+
+
+
+
+
--- /dev/null
+#
+# 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)
--- /dev/null
+// 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;
+}
+
--- /dev/null
+// 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
+
--- /dev/null
+// 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;;
+}
+
--- /dev/null
+// 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
--- /dev/null
+/* -----------------------------------------------------------------------------\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
--- /dev/null
+/* -----------------------------------------------------------------------------\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
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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
+
--- /dev/null
+/*
+ * -----------------------------------------------------------------------------
+ *
+ * Author: Markus Moeller (markus_moeller at compuserve.com)
+ *
+ * Copyright (C) 2007 Markus Moeller. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * -----------------------------------------------------------------------------
+ */
+/*
+ * 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;
+ }
+ }
+}