summaryrefslogtreecommitdiff
path: root/src/lib/gssapi/krb5
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2017-07-07 17:03:42 +0000
committerCy Schubert <cy@FreeBSD.org>2017-07-07 17:03:42 +0000
commit33a9b234e7087f573ef08cd7318c6497ba08b439 (patch)
treed0ea40ad3bf5463a3c55795977c71bcb7d781b4b /src/lib/gssapi/krb5
Diffstat (limited to 'src/lib/gssapi/krb5')
-rw-r--r--src/lib/gssapi/krb5/Makefile.in259
-rw-r--r--src/lib/gssapi/krb5/accept_sec_context.c1347
-rw-r--r--src/lib/gssapi/krb5/acquire_cred.c1261
-rw-r--r--src/lib/gssapi/krb5/canon_name.c44
-rw-r--r--src/lib/gssapi/krb5/compare_name.c52
-rw-r--r--src/lib/gssapi/krb5/context_time.c63
-rw-r--r--src/lib/gssapi/krb5/copy_ccache.c60
-rw-r--r--src/lib/gssapi/krb5/cred_store.c50
-rw-r--r--src/lib/gssapi/krb5/delete_sec_context.c99
-rw-r--r--src/lib/gssapi/krb5/deps756
-rw-r--r--src/lib/gssapi/krb5/disp_name.c81
-rw-r--r--src/lib/gssapi/krb5/disp_status.c200
-rw-r--r--src/lib/gssapi/krb5/duplicate_name.c59
-rw-r--r--src/lib/gssapi/krb5/export_cred.c481
-rw-r--r--src/lib/gssapi/krb5/export_name.c88
-rw-r--r--src/lib/gssapi/krb5/export_sec_context.c101
-rw-r--r--src/lib/gssapi/krb5/get_tkt_flags.c45
-rw-r--r--src/lib/gssapi/krb5/gssapiP_krb5.h1428
-rw-r--r--src/lib/gssapi/krb5/gssapi_err_krb5.et42
-rw-r--r--src/lib/gssapi/krb5/gssapi_krb5.c1159
-rw-r--r--src/lib/gssapi/krb5/gssapi_krb5.h281
-rw-r--r--src/lib/gssapi/krb5/iakerb.c1329
-rw-r--r--src/lib/gssapi/krb5/import_cred.c648
-rw-r--r--src/lib/gssapi/krb5/import_name.c332
-rw-r--r--src/lib/gssapi/krb5/import_sec_context.c118
-rw-r--r--src/lib/gssapi/krb5/indicate_mechs.c37
-rw-r--r--src/lib/gssapi/krb5/init_sec_context.c1104
-rw-r--r--src/lib/gssapi/krb5/inq_context.c312
-rw-r--r--src/lib/gssapi/krb5/inq_cred.c247
-rw-r--r--src/lib/gssapi/krb5/inq_names.c100
-rw-r--r--src/lib/gssapi/krb5/k5seal.c413
-rw-r--r--src/lib/gssapi/krb5/k5sealiov.c557
-rw-r--r--src/lib/gssapi/krb5/k5sealv3.c512
-rw-r--r--src/lib/gssapi/krb5/k5sealv3iov.c468
-rw-r--r--src/lib/gssapi/krb5/k5unseal.c588
-rw-r--r--src/lib/gssapi/krb5/k5unsealiov.c675
-rw-r--r--src/lib/gssapi/krb5/krb5_gss_glue.c445
-rw-r--r--src/lib/gssapi/krb5/lucid_context.c292
-rw-r--r--src/lib/gssapi/krb5/naming_exts.c684
-rw-r--r--src/lib/gssapi/krb5/prf.c139
-rw-r--r--src/lib/gssapi/krb5/process_context_token.c66
-rw-r--r--src/lib/gssapi/krb5/rel_cred.c101
-rw-r--r--src/lib/gssapi/krb5/rel_name.c47
-rw-r--r--src/lib/gssapi/krb5/rel_oid.c78
-rw-r--r--src/lib/gssapi/krb5/s4u_gss_glue.c308
-rw-r--r--src/lib/gssapi/krb5/ser_sctx.c798
-rw-r--r--src/lib/gssapi/krb5/set_allowable_enctypes.c123
-rw-r--r--src/lib/gssapi/krb5/set_ccache.c101
-rw-r--r--src/lib/gssapi/krb5/store_cred.c234
-rw-r--r--src/lib/gssapi/krb5/util_cksum.c295
-rw-r--r--src/lib/gssapi/krb5/util_crypt.c782
-rw-r--r--src/lib/gssapi/krb5/util_seed.c61
-rw-r--r--src/lib/gssapi/krb5/util_seqnum.c102
-rw-r--r--src/lib/gssapi/krb5/val_cred.c83
-rw-r--r--src/lib/gssapi/krb5/wrap_size_limit.c178
55 files changed, 20313 insertions, 0 deletions
diff --git a/src/lib/gssapi/krb5/Makefile.in b/src/lib/gssapi/krb5/Makefile.in
new file mode 100644
index 000000000000..364a7a4c9b25
--- /dev/null
+++ b/src/lib/gssapi/krb5/Makefile.in
@@ -0,0 +1,259 @@
+mydir=lib$(S)gssapi$(S)krb5
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic -I../mechglue -I$(srcdir)/../mechglue
+DEFINES=-D_GSS_STATIC_LINK=1
+
+#MODULE_INSTALL_DIR = $(GSS_MODULE_DIR)
+#LIBBASE=mech_krb5
+#LIBMAJOR=0
+#LIBMINOR=0
+#LIBINITFUNC=gss_krb5int_init
+#LIBFINIFUNC=gss_krb5int_fini
+#STOBJLISTS=../generic/OBJS.ST OBJS.ST
+#SUBDIROBJLISTS=../generic/OBJS.ST
+#SHLIB_EXPDEPS=$(KRB5_DEPLIB) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB) $(COM_ERR_DEPLIB)
+#SHLIB_EXPLIBS=-lkrb5 -lk5crypto -lcom_err $(SUPPORT_LIB) $(DL_LIB) $(LIBS)
+#RELDIR=gssapi/krb5
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=krb5
+##DOS##OBJFILE = ..\$(OUTPRE)krb5.lst
+
+##DOS##DLL_EXP_TYPE=GSS
+
+ETSRCS= gssapi_err_krb5.c
+ETOBJS= $(OUTPRE)gssapi_err_krb5.$(OBJEXT)
+ETHDRS= gssapi_err_krb5.h
+
+$(OUTPRE)gssapi_err_krb5.$(OBJEXT): gssapi_err_krb5.c
+gssapi_err_krb5.h: gssapi_err_krb5.et
+gssapi_err_krb5.c: gssapi_err_krb5.et
+
+SRCS = \
+ $(srcdir)/accept_sec_context.c \
+ $(srcdir)/acquire_cred.c \
+ $(srcdir)/canon_name.c \
+ $(srcdir)/compare_name.c \
+ $(srcdir)/context_time.c \
+ $(srcdir)/copy_ccache.c \
+ $(srcdir)/cred_store.c \
+ $(srcdir)/delete_sec_context.c \
+ $(srcdir)/disp_name.c \
+ $(srcdir)/disp_status.c \
+ $(srcdir)/duplicate_name.c \
+ $(srcdir)/export_cred.c \
+ $(srcdir)/export_name.c \
+ $(srcdir)/export_sec_context.c \
+ $(srcdir)/get_tkt_flags.c \
+ $(srcdir)/gssapi_krb5.c \
+ $(srcdir)/iakerb.c \
+ $(srcdir)/import_cred.c \
+ $(srcdir)/import_name.c \
+ $(srcdir)/import_sec_context.c \
+ $(srcdir)/indicate_mechs.c \
+ $(srcdir)/init_sec_context.c \
+ $(srcdir)/inq_context.c \
+ $(srcdir)/inq_cred.c \
+ $(srcdir)/inq_names.c \
+ $(srcdir)/k5seal.c \
+ $(srcdir)/k5sealiov.c \
+ $(srcdir)/k5sealv3.c \
+ $(srcdir)/k5sealv3iov.c \
+ $(srcdir)/k5unseal.c \
+ $(srcdir)/k5unsealiov.c \
+ $(srcdir)/krb5_gss_glue.c \
+ $(srcdir)/lucid_context.c \
+ $(srcdir)/naming_exts.c \
+ $(srcdir)/prf.c \
+ $(srcdir)/process_context_token.c \
+ $(srcdir)/rel_cred.c \
+ $(srcdir)/rel_oid.c \
+ $(srcdir)/rel_name.c \
+ $(srcdir)/s4u_gss_glue.c \
+ $(srcdir)/set_allowable_enctypes.c \
+ $(srcdir)/ser_sctx.c \
+ $(srcdir)/set_ccache.c \
+ $(srcdir)/store_cred.c \
+ $(srcdir)/util_cksum.c \
+ $(srcdir)/util_crypt.c \
+ $(srcdir)/util_seed.c \
+ $(srcdir)/util_seqnum.c \
+ $(srcdir)/val_cred.c \
+ $(srcdir)/wrap_size_limit.c
+
+
+OBJS = \
+ $(OUTPRE)accept_sec_context.$(OBJEXT) \
+ $(OUTPRE)acquire_cred.$(OBJEXT) \
+ $(OUTPRE)canon_name.$(OBJEXT) \
+ $(OUTPRE)compare_name.$(OBJEXT) \
+ $(OUTPRE)context_time.$(OBJEXT) \
+ $(OUTPRE)copy_ccache.$(OBJEXT) \
+ $(OUTPRE)cred_store.$(OBJEXT) \
+ $(OUTPRE)delete_sec_context.$(OBJEXT) \
+ $(OUTPRE)disp_name.$(OBJEXT) \
+ $(OUTPRE)disp_status.$(OBJEXT) \
+ $(OUTPRE)duplicate_name.$(OBJEXT) \
+ $(OUTPRE)export_cred.$(OBJEXT) \
+ $(OUTPRE)export_name.$(OBJEXT) \
+ $(OUTPRE)export_sec_context.$(OBJEXT) \
+ $(OUTPRE)get_tkt_flags.$(OBJEXT) \
+ $(OUTPRE)gssapi_krb5.$(OBJEXT) \
+ $(OUTPRE)iakerb.$(OBJEXT) \
+ $(OUTPRE)import_cred.$(OBJEXT) \
+ $(OUTPRE)import_name.$(OBJEXT) \
+ $(OUTPRE)import_sec_context.$(OBJEXT) \
+ $(OUTPRE)indicate_mechs.$(OBJEXT) \
+ $(OUTPRE)init_sec_context.$(OBJEXT) \
+ $(OUTPRE)inq_context.$(OBJEXT) \
+ $(OUTPRE)inq_cred.$(OBJEXT) \
+ $(OUTPRE)inq_names.$(OBJEXT) \
+ $(OUTPRE)k5seal.$(OBJEXT) \
+ $(OUTPRE)k5sealiov.$(OBJEXT) \
+ $(OUTPRE)k5sealv3.$(OBJEXT) \
+ $(OUTPRE)k5sealv3iov.$(OBJEXT) \
+ $(OUTPRE)k5unseal.$(OBJEXT) \
+ $(OUTPRE)k5unsealiov.$(OBJEXT) \
+ $(OUTPRE)krb5_gss_glue.$(OBJEXT) \
+ $(OUTPRE)lucid_context.$(OBJEXT) \
+ $(OUTPRE)naming_exts.$(OBJEXT) \
+ $(OUTPRE)prf.$(OBJEXT) \
+ $(OUTPRE)process_context_token.$(OBJEXT) \
+ $(OUTPRE)rel_cred.$(OBJEXT) \
+ $(OUTPRE)rel_oid.$(OBJEXT) \
+ $(OUTPRE)rel_name.$(OBJEXT) \
+ $(OUTPRE)s4u_gss_glue.$(OBJEXT) \
+ $(OUTPRE)set_allowable_enctypes.$(OBJEXT) \
+ $(OUTPRE)ser_sctx.$(OBJEXT) \
+ $(OUTPRE)set_ccache.$(OBJEXT) \
+ $(OUTPRE)store_cred.$(OBJEXT) \
+ $(OUTPRE)util_cksum.$(OBJEXT) \
+ $(OUTPRE)util_crypt.$(OBJEXT) \
+ $(OUTPRE)util_seed.$(OBJEXT) \
+ $(OUTPRE)util_seqnum.$(OBJEXT) \
+ $(OUTPRE)val_cred.$(OBJEXT) \
+ $(OUTPRE)wrap_size_limit.$(OBJEXT) \
+ $(OUTPRE)gssapi_err_krb5.$(OBJEXT)
+
+# k5mech.$(OBJEXT) \
+# pname_to_uid.$(OBJEXT)
+
+STLIBOBJS = \
+ accept_sec_context.o \
+ acquire_cred.o \
+ canon_name.o \
+ compare_name.o \
+ context_time.o \
+ copy_ccache.o \
+ cred_store.o \
+ delete_sec_context.o \
+ disp_name.o \
+ disp_status.o \
+ duplicate_name.o \
+ export_cred.o \
+ export_name.o \
+ export_sec_context.o \
+ get_tkt_flags.o \
+ gssapi_krb5.o \
+ iakerb.o \
+ import_cred.o \
+ import_name.o \
+ import_sec_context.o \
+ indicate_mechs.o \
+ init_sec_context.o \
+ inq_context.o \
+ inq_cred.o \
+ inq_names.o \
+ k5seal.o \
+ k5sealiov.o \
+ k5sealv3.o \
+ k5sealv3iov.o \
+ k5unseal.o \
+ k5unsealiov.o \
+ krb5_gss_glue.o \
+ lucid_context.o \
+ naming_exts.o \
+ prf.o \
+ process_context_token.o \
+ rel_cred.o \
+ rel_oid.o \
+ rel_name.o \
+ s4u_gss_glue.o \
+ set_allowable_enctypes.o \
+ ser_sctx.o \
+ set_ccache.o \
+ store_cred.o \
+ util_cksum.o \
+ util_crypt.o \
+ util_seed.o \
+ util_seqnum.o \
+ val_cred.o \
+ wrap_size_limit.o \
+ gssapi_err_krb5.o
+
+# k5mech.o \
+# pname_to_uid.o
+
+HDRS= $(ETHDRS)
+
+EHDRDIR=$(BUILDTOP)$(S)include$(S)gssapi
+EXPORTED_HEADERS= gssapi_krb5.h
+
+##DOS##LIBOBJS = $(OBJS)
+
+GSSAPI_KRB5_HDR=$(EHDRDIR)$(S)gssapi_krb5.h
+
+all-windows: $(EHDRDIR) $(GSSAPI_KRB5_HDR) $(SRCS) $(HDRS)
+
+##DOS##$(EHDRDIR):
+##DOS## mkdir $(EHDRDIR)
+
+MK_EHDRDIR=if test -d $(EHDRDIR); then :; else (set -x; mkdir $(EHDRDIR)); fi
+##DOS##MK_EHDRDIR=rem
+
+$(GSSAPI_KRB5_HDR): $(srcdir)$(S)gssapi_krb5.h
+ @$(MK_EHDRDIR)
+ $(CP) $(srcdir)$(S)gssapi_krb5.h "$@"
+
+all-unix: $(SRCS) $(HDRS) $(GSSAPI_KRB5_HDR)
+all-unix: all-libobjs
+
+error_map.h: $(top_srcdir)/util/gen-map.pl \
+ $(top_srcdir)/util/ktemplate.pm Makefile
+ $(PERL) -I$(top_srcdir)/util $(top_srcdir)/util/gen-map.pl \
+ -oerror_map.new \
+ NAME=gsserrmap \
+ KEY=OM_uint32 \
+ VALUE="char *" \
+ COMPARE=compare_OM_uint32 \
+ FREEVALUE=free_string
+ $(RM) $@
+ $(MV) error_map.new $@
+
+clean-unix::
+ $(RM) $(BUILDTOP)/include/gssapi/gssapi_krb5.h
+ -$(RM) error_map.h
+
+clean-unix:: clean-libobjs
+ $(RM) $(ETHDRS) $(ETSRCS)
+
+clean-windows::
+ $(RM) $(EHDRDIR)\gssapi_krb5.h
+ $(RM) error_map.h
+ -if exist $(EHDRDIR)\nul rmdir $(EHDRDIR)
+
+
+generate-files-mac: error_map.h
+
+install-headers-unix install:
+ @set -x; for f in $(EXPORTED_HEADERS) ; \
+ do $(INSTALL_DATA) $(srcdir)/$$f \
+ $(DESTDIR)$(KRB5_INCDIR)/gssapi/$$f ; \
+ done
+
+depend: $(ETSRCS) $(ETHDRS) $(GSSAPI_KRB5_HDR) error_map.h
+
+install:
+
+@libobj_frag@
+
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
new file mode 100644
index 000000000000..580d08cbf53e
--- /dev/null
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -0,0 +1,1347 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2000, 2004, 2007, 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * The copyright holder's name is not used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <assert.h>
+
+#ifdef CFX_EXERCISE
+#define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
+#else
+#define CFX_ACCEPTOR_SUBKEY 1
+#endif
+
+#ifndef LEAN_CLIENT
+
+static OM_uint32
+create_constrained_deleg_creds(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t verifier_cred_handle,
+ krb5_ticket *ticket,
+ krb5_gss_cred_id_t *out_cred,
+ krb5_context context)
+{
+ OM_uint32 major_status;
+ krb5_creds krb_creds;
+ krb5_data *data;
+ krb5_error_code code;
+
+ assert(out_cred != NULL);
+ assert(verifier_cred_handle->usage == GSS_C_BOTH);
+
+ memset(&krb_creds, 0, sizeof(krb_creds));
+ krb_creds.client = ticket->enc_part2->client;
+ krb_creds.server = ticket->server;
+ krb_creds.keyblock = *(ticket->enc_part2->session);
+ krb_creds.ticket_flags = ticket->enc_part2->flags;
+ krb_creds.times = ticket->enc_part2->times;
+ krb_creds.magic = KV5M_CREDS;
+ krb_creds.authdata = NULL;
+
+ code = encode_krb5_ticket(ticket, &data);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ krb_creds.ticket = *data;
+
+ major_status = kg_compose_deleg_cred(minor_status,
+ verifier_cred_handle,
+ &krb_creds,
+ GSS_C_INDEFINITE,
+ out_cred,
+ NULL,
+ context);
+
+ krb5_free_data(context, data);
+
+ return major_status;
+}
+
+/* Decode, decrypt and store the forwarded creds in the local ccache. */
+static krb5_error_code
+rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
+ krb5_context context;
+ krb5_auth_context auth_context;
+ krb5_data *inbuf;
+ krb5_gss_cred_id_t *out_cred;
+{
+ krb5_creds ** creds = NULL;
+ krb5_error_code retval;
+ krb5_ccache ccache = NULL;
+ krb5_gss_cred_id_t cred = NULL;
+ krb5_auth_context new_auth_ctx = NULL;
+ krb5_int32 flags_org;
+
+ if ((retval = krb5_auth_con_getflags(context, auth_context, &flags_org)))
+ return retval;
+ krb5_auth_con_setflags(context, auth_context,
+ 0);
+
+ /*
+ * By the time krb5_rd_cred is called here (after krb5_rd_req has been
+ * called in krb5_gss_accept_sec_context), the "keyblock" field of
+ * auth_context contains a pointer to the session key, and the
+ * "recv_subkey" field might contain a session subkey. Either of
+ * these (the "recv_subkey" if it isn't NULL, otherwise the
+ * "keyblock") might have been used to encrypt the encrypted part of
+ * the KRB_CRED message that contains the forwarded credentials. (The
+ * Java Crypto and Security Implementation from the DSTC in Australia
+ * always uses the session key. But apparently it never negotiates a
+ * subkey, so this code works fine against a JCSI client.) Up to the
+ * present, though, GSSAPI clients linked against the MIT code (which
+ * is almost all GSSAPI clients) don't encrypt the KRB_CRED message at
+ * all -- at this level. So if the first call to krb5_rd_cred fails,
+ * we should call it a second time with another auth context freshly
+ * created by krb5_auth_con_init. All of its keyblock fields will be
+ * NULL, so krb5_rd_cred will assume that the KRB_CRED message is
+ * unencrypted. (The MIT code doesn't actually send the KRB_CRED
+ * message in the clear -- the "authenticator" whose "checksum" ends up
+ * containing the KRB_CRED message does get encrypted.)
+ */
+ if (krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)) {
+ if ((retval = krb5_auth_con_init(context, &new_auth_ctx)))
+ goto cleanup;
+ krb5_auth_con_setflags(context, new_auth_ctx, 0);
+ if ((retval = krb5_rd_cred(context, new_auth_ctx, inbuf,
+ &creds, NULL)))
+ goto cleanup;
+ }
+
+ if ((retval = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) {
+ ccache = NULL;
+ goto cleanup;
+ }
+
+ if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
+ goto cleanup;
+
+ if ((retval = krb5_cc_store_cred(context, ccache, creds[0])))
+ goto cleanup;
+
+ /* generate a delegated credential handle */
+ if (out_cred) {
+ /* allocate memory for a cred_t... */
+ if (!(cred =
+ (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
+ retval = ENOMEM; /* out of memory? */
+ goto cleanup;
+ }
+
+ /* zero it out... */
+ memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
+
+ retval = k5_mutex_init(&cred->lock);
+ if (retval) {
+ xfree(cred);
+ cred = NULL;
+ goto cleanup;
+ }
+
+ /* copy the client principle into it... */
+ if ((retval =
+ kg_init_name(context, creds[0]->client, NULL, NULL, NULL, 0,
+ &cred->name))) {
+ k5_mutex_destroy(&cred->lock);
+ retval = ENOMEM; /* out of memory? */
+ xfree(cred); /* clean up memory on failure */
+ cred = NULL;
+ goto cleanup;
+ }
+
+ cred->usage = GSS_C_INITIATE; /* we can't accept with this */
+ /* cred->name already set */
+ cred->keytab = NULL; /* no keytab associated with this... */
+ cred->expire = creds[0]->times.endtime; /* store the end time */
+ cred->ccache = ccache; /* the ccache containing the credential */
+ cred->destroy_ccache = 1;
+ ccache = NULL; /* cred takes ownership so don't destroy */
+ }
+
+ /* If there were errors, there might have been a memory leak
+ if (!cred)
+ if ((retval = krb5_cc_close(context, ccache)))
+ goto cleanup;
+ */
+cleanup:
+ if (creds)
+ krb5_free_tgt_creds(context, creds);
+
+ if (ccache)
+ (void)krb5_cc_destroy(context, ccache);
+
+ if (out_cred)
+ *out_cred = cred; /* return credential */
+
+ if (new_auth_ctx)
+ krb5_auth_con_free(context, new_auth_ctx);
+
+ krb5_auth_con_setflags(context, auth_context, flags_org);
+
+ return retval;
+}
+
+
+/*
+ * Performs third leg of DCE authentication
+ */
+static OM_uint32
+kg_accept_dce(minor_status, context_handle, verifier_cred_handle,
+ input_token, input_chan_bindings, src_name, mech_type,
+ output_token, ret_flags, time_rec, delegated_cred_handle)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t *context_handle;
+ gss_cred_id_t verifier_cred_handle;
+ gss_buffer_t input_token;
+ gss_channel_bindings_t input_chan_bindings;
+ gss_name_t *src_name;
+ gss_OID *mech_type;
+ gss_buffer_t output_token;
+ OM_uint32 *ret_flags;
+ OM_uint32 *time_rec;
+ gss_cred_id_t *delegated_cred_handle;
+{
+ krb5_error_code code;
+ krb5_gss_ctx_id_rec *ctx = 0;
+ krb5_timestamp now;
+ krb5_gss_name_t name = NULL;
+ krb5_ui_4 nonce = 0;
+ krb5_data ap_rep;
+ OM_uint32 major_status = GSS_S_FAILURE;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if (mech_type)
+ *mech_type = GSS_C_NULL_OID;
+ /* return a bogus cred handle */
+ if (delegated_cred_handle)
+ *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ ctx = (krb5_gss_ctx_id_rec *)*context_handle;
+
+ code = krb5_timeofday(ctx->k5_context, &now);
+ if (code != 0) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ ap_rep.data = input_token->value;
+ ap_rep.length = input_token->length;
+
+ code = krb5_rd_rep_dce(ctx->k5_context,
+ ctx->auth_context,
+ &ap_rep,
+ &nonce);
+ if (code != 0) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ ctx->established = 1;
+
+ if (src_name) {
+ code = kg_duplicate_name(ctx->k5_context, ctx->there, &name);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ *src_name = (gss_name_t) name;
+ }
+
+ if (mech_type)
+ *mech_type = ctx->mech_used;
+
+ if (time_rec)
+ *time_rec = ctx->krb_times.endtime + ctx->k5_context->clockskew - now;
+
+ /* Never return GSS_C_DELEG_FLAG since we don't support DCE credential
+ * delegation yet. */
+ if (ret_flags)
+ *ret_flags = (ctx->gss_flags & ~GSS_C_DELEG_FLAG);
+
+ *minor_status = 0;
+
+ return GSS_S_COMPLETE;
+
+fail:
+ /* real failure code follows */
+
+ (void) krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t *) &ctx,
+ NULL);
+ *context_handle = GSS_C_NO_CONTEXT;
+ *minor_status = code;
+
+ return major_status;
+}
+
+static krb5_error_code
+kg_process_extension(krb5_context context,
+ krb5_auth_context auth_context,
+ int ext_type,
+ krb5_data *ext_data,
+ krb5_gss_ctx_ext_t exts)
+{
+ krb5_error_code code = 0;
+
+ assert(exts != NULL);
+
+ switch (ext_type) {
+ case KRB5_GSS_EXTS_IAKERB_FINISHED:
+ if (exts->iakerb.conv == NULL) {
+ code = KRB5KRB_AP_ERR_MSG_TYPE; /* XXX */
+ } else {
+ krb5_key key;
+
+ code = krb5_auth_con_getrecvsubkey_k(context, auth_context, &key);
+ if (code != 0)
+ break;
+
+ code = iakerb_verify_finished(context, key, exts->iakerb.conv,
+ ext_data);
+ if (code == 0)
+ exts->iakerb.verified = 1;
+
+ krb5_k_free_key(context, key);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return code;
+}
+
+static OM_uint32
+kg_accept_krb5(minor_status, context_handle,
+ verifier_cred_handle, input_token,
+ input_chan_bindings, src_name, mech_type,
+ output_token, ret_flags, time_rec,
+ delegated_cred_handle, exts)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t *context_handle;
+ gss_cred_id_t verifier_cred_handle;
+ gss_buffer_t input_token;
+ gss_channel_bindings_t input_chan_bindings;
+ gss_name_t *src_name;
+ gss_OID *mech_type;
+ gss_buffer_t output_token;
+ OM_uint32 *ret_flags;
+ OM_uint32 *time_rec;
+ gss_cred_id_t *delegated_cred_handle;
+ krb5_gss_ctx_ext_t exts;
+{
+ krb5_context context;
+ unsigned char *ptr, *ptr2;
+ char *sptr;
+ OM_uint32 tmp;
+ size_t md5len;
+ krb5_gss_cred_id_t cred = 0;
+ krb5_data ap_rep, ap_req;
+ unsigned int i;
+ krb5_error_code code;
+ krb5_address addr, *paddr;
+ krb5_authenticator *authdat = 0;
+ krb5_checksum reqcksum;
+ krb5_gss_name_t name = NULL;
+ krb5_ui_4 gss_flags = 0;
+ krb5_gss_ctx_id_rec *ctx = NULL;
+ krb5_timestamp now;
+ gss_buffer_desc token;
+ krb5_auth_context auth_context = NULL;
+ krb5_ticket * ticket = NULL;
+ int option_id;
+ krb5_data option;
+ const gss_OID_desc *mech_used = NULL;
+ OM_uint32 major_status = GSS_S_FAILURE;
+ OM_uint32 tmp_minor_status;
+ krb5_error krb_error_data;
+ krb5_data scratch;
+ gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
+ krb5_gss_cred_id_t deleg_cred = NULL;
+ krb5int_access kaccess;
+ int cred_rcache = 0;
+ int no_encap = 0;
+ int token_deleg_flag = 0;
+ krb5_flags ap_req_options = 0;
+ krb5_enctype negotiated_etype;
+ krb5_authdata_context ad_context = NULL;
+ krb5_principal accprinc = NULL;
+ krb5_ap_req *request = NULL;
+
+ code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+ if (code) {
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ /* set up returns to be freeable */
+
+ if (src_name)
+ *src_name = (gss_name_t) NULL;
+ output_token->length = 0;
+ output_token->value = NULL;
+ token.value = 0;
+ reqcksum.contents = 0;
+ ap_req.data = 0;
+ ap_rep.data = 0;
+
+ if (mech_type)
+ *mech_type = GSS_C_NULL_OID;
+ /* return a bogus cred handle */
+ if (delegated_cred_handle)
+ *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ /* handle default cred handle */
+ if (verifier_cred_handle == GSS_C_NO_CREDENTIAL) {
+ major_status = krb5_gss_acquire_cred(minor_status, GSS_C_NO_NAME,
+ GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
+ GSS_C_ACCEPT, &defcred,
+ NULL, NULL);
+ if (major_status != GSS_S_COMPLETE) {
+ code = *minor_status;
+ goto fail;
+ }
+ verifier_cred_handle = defcred;
+ }
+
+ /* Resolve any initiator state in the verifier cred and lock it. */
+ major_status = kg_cred_resolve(minor_status, context, verifier_cred_handle,
+ GSS_C_NO_NAME);
+ if (GSS_ERROR(major_status)) {
+ code = *minor_status;
+ goto fail;
+ }
+ cred = (krb5_gss_cred_id_t)verifier_cred_handle;
+
+ /* make sure the supplied credentials are valid for accept */
+
+ if ((cred->usage != GSS_C_ACCEPT) &&
+ (cred->usage != GSS_C_BOTH)) {
+ code = 0;
+ major_status = GSS_S_NO_CRED;
+ goto fail;
+ }
+
+ /* verify the token's integrity, and leave the token in ap_req.
+ figure out which mech oid was used, and save it */
+
+ ptr = (unsigned char *) input_token->value;
+
+ if (!(code = g_verify_token_header(gss_mech_krb5,
+ &(ap_req.length),
+ &ptr, KG_TOK_CTX_AP_REQ,
+ input_token->length, 1))) {
+ mech_used = gss_mech_krb5;
+ } else if ((code == G_WRONG_MECH)
+ &&!(code = g_verify_token_header((gss_OID) gss_mech_iakerb,
+ &(ap_req.length),
+ &ptr, KG_TOK_CTX_AP_REQ,
+ input_token->length, 1))) {
+ mech_used = gss_mech_iakerb;
+ } else if ((code == G_WRONG_MECH)
+ &&!(code = g_verify_token_header((gss_OID) gss_mech_krb5_wrong,
+ &(ap_req.length),
+ &ptr, KG_TOK_CTX_AP_REQ,
+ input_token->length, 1))) {
+ mech_used = gss_mech_krb5_wrong;
+ } else if ((code == G_WRONG_MECH) &&
+ !(code = g_verify_token_header(gss_mech_krb5_old,
+ &(ap_req.length),
+ &ptr, KG_TOK_CTX_AP_REQ,
+ input_token->length, 1))) {
+ /*
+ * Previous versions of this library used the old mech_id
+ * and some broken behavior (wrong IV on checksum
+ * encryption). We support the old mech_id for
+ * compatibility, and use it to decide when to use the
+ * old behavior.
+ */
+ mech_used = gss_mech_krb5_old;
+ } else if (code == G_WRONG_TOKID) {
+ major_status = GSS_S_CONTINUE_NEEDED;
+ code = KRB5KRB_AP_ERR_MSG_TYPE;
+ mech_used = gss_mech_krb5;
+ goto fail;
+ } else if (code == G_BAD_TOK_HEADER) {
+ /* DCE style not encapsulated */
+ ap_req.length = input_token->length;
+ ap_req.data = input_token->value;
+ mech_used = gss_mech_krb5;
+ no_encap = 1;
+ } else {
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto fail;
+ }
+
+ sptr = (char *) ptr;
+ TREAD_STR(sptr, ap_req.data, ap_req.length);
+
+ /* construct the sender_addr */
+
+ if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
+ (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
+ /* XXX is this right? */
+ addr.addrtype = ADDRTYPE_INET;
+ addr.length = input_chan_bindings->initiator_address.length;
+ addr.contents = input_chan_bindings->initiator_address.value;
+
+ paddr = &addr;
+ } else {
+ paddr = NULL;
+ }
+
+ /* decode the AP_REQ message */
+ code = decode_krb5_ap_req(&ap_req, &request);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto done;
+ }
+ ticket = request->ticket;
+
+ /* decode the message */
+
+ if ((code = krb5_auth_con_init(context, &auth_context))) {
+ major_status = GSS_S_FAILURE;
+ save_error_info((OM_uint32)code, context);
+ goto fail;
+ }
+ if (cred->rcache) {
+ cred_rcache = 1;
+ if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+ if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* Limit the encryption types negotiated (if requested). */
+ if (cred->req_enctypes) {
+ if ((code = krb5_auth_con_setpermetypes(context, auth_context,
+ cred->req_enctypes))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ if (!cred->default_identity) {
+ if ((code = kg_acceptor_princ(context, cred->name, &accprinc))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ code = krb5_rd_req_decoded(context, &auth_context, request, accprinc,
+ cred->keytab, &ap_req_options, NULL);
+
+ krb5_free_principal(context, accprinc);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ krb5_auth_con_setflags(context, auth_context,
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+
+ krb5_auth_con_getauthenticator(context, auth_context, &authdat);
+
+#if 0
+ /* make sure the necessary parts of the authdat are present */
+
+ if ((authdat->authenticator->subkey == NULL) ||
+ (authdat->ticket->enc_part2 == NULL)) {
+ code = KG_NO_SUBKEY;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+#endif
+
+ if (authdat->checksum == NULL) {
+ /*
+ * Some SMB client implementations use handcrafted GSSAPI code that
+ * does not provide a checksum. MS-KILE documents that the Microsoft
+ * implementation considers a missing checksum acceptable; the server
+ * assumes all flags are unset in this case, and does not check channel
+ * bindings.
+ */
+ gss_flags = 0;
+ } else if (authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) {
+ /* Samba does not send 0x8003 GSS-API checksums */
+ krb5_boolean valid;
+ krb5_key subkey;
+ krb5_data zero;
+
+ code = krb5_auth_con_getkey_k(context, auth_context, &subkey);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ zero.length = 0;
+ zero.data = "";
+
+ code = krb5_k_verify_checksum(context,
+ subkey,
+ KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
+ &zero,
+ authdat->checksum,
+ &valid);
+ krb5_k_free_key(context, subkey);
+ if (code || !valid) {
+ major_status = GSS_S_BAD_SIG;
+ goto fail;
+ }
+
+ /* Use ap_options from the request to guess the mutual flag. */
+ gss_flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
+ if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED)
+ gss_flags |= GSS_C_MUTUAL_FLAG;
+ } else {
+ /* gss krb5 v1 */
+
+ /* stash this now, for later. */
+ code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* verify that the checksum is correct */
+
+ /*
+ The checksum may be either exactly 24 bytes, in which case
+ no options are specified, or greater than 24 bytes, in which case
+ one or more options are specified. Currently, the only valid
+ option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
+ */
+
+ if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
+ (authdat->checksum->length < 24)) {
+ code = 0;
+ major_status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+
+ ptr = (unsigned char *) authdat->checksum->contents;
+
+ TREAD_INT(ptr, tmp, 0);
+
+ if (tmp != md5len) {
+ code = KG_BAD_LENGTH;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /*
+ The following section of code attempts to implement the
+ optional channel binding facility as described in RFC2743.
+
+ Since this facility is optional channel binding may or may
+ not have been provided by either the client or the server.
+
+ If the server has specified input_chan_bindings equal to
+ GSS_C_NO_CHANNEL_BINDINGS then we skip the check. If
+ the server does provide channel bindings then we compute
+ a checksum and compare against those provided by the
+ client. */
+
+ if ((code = kg_checksum_channel_bindings(context,
+ input_chan_bindings,
+ &reqcksum))) {
+ major_status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+
+ /* Always read the clients bindings - eventhough we might ignore them */
+ TREAD_STR(ptr, ptr2, reqcksum.length);
+
+ if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
+ if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
+ xfree(reqcksum.contents);
+ reqcksum.contents = 0;
+ code = 0;
+ major_status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+
+ }
+
+ xfree(reqcksum.contents);
+ reqcksum.contents = 0;
+
+ /* Read the token flags. Remember if GSS_C_DELEG_FLAG was set, but
+ * mask it out until we actually read a delegated credential. */
+ TREAD_INT(ptr, gss_flags, 0);
+ token_deleg_flag = (gss_flags & GSS_C_DELEG_FLAG);
+ gss_flags &= ~GSS_C_DELEG_FLAG;
+
+ /* if the checksum length > 24, there are options to process */
+
+ i = authdat->checksum->length - 24;
+ if (i && token_deleg_flag) {
+ if (i >= 4) {
+ TREAD_INT16(ptr, option_id, 0);
+ TREAD_INT16(ptr, option.length, 0);
+ i -= 4;
+
+ if (i < option.length) {
+ code = KG_BAD_LENGTH;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* have to use ptr2, since option.data is wrong type and
+ macro uses ptr as both lvalue and rvalue */
+
+ TREAD_STR(ptr, ptr2, option.length);
+ option.data = (char *) ptr2;
+
+ i -= option.length;
+
+ if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* store the delegated credential */
+
+ code = rd_and_store_for_creds(context, auth_context, &option,
+ (delegated_cred_handle) ?
+ &deleg_cred : NULL);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ gss_flags |= GSS_C_DELEG_FLAG;
+ } /* if i >= 4 */
+ /* ignore any additional trailing data, for now */
+ }
+ while (i > 0) {
+ /* Process Type-Length-Data options */
+ if (i < 8) {
+ code = KG_BAD_LENGTH;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ TREAD_INT(ptr, option_id, 1);
+ TREAD_INT(ptr, option.length, 1);
+ i -= 8;
+ if (i < option.length) {
+ code = KG_BAD_LENGTH;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ TREAD_STR(ptr, ptr2, option.length);
+ option.data = (char *)ptr2;
+
+ i -= option.length;
+
+ code = kg_process_extension(context, auth_context,
+ option_id, &option, exts);
+ if (code != 0) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+ }
+
+ if (exts->iakerb.conv && !exts->iakerb.verified) {
+ major_status = GSS_S_BAD_SIG;
+ goto fail;
+ }
+
+ /* only DCE_STYLE clients are allowed to send raw AP-REQs */
+ if (no_encap != ((gss_flags & GSS_C_DCE_STYLE) != 0)) {
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto fail;
+ }
+
+ /* create the ctx struct and start filling it in */
+
+ if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
+ == NULL) {
+ code = ENOMEM;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+ ctx->magic = KG_CONTEXT;
+ ctx->mech_used = (gss_OID) mech_used;
+ ctx->auth_context = auth_context;
+ ctx->initiate = 0;
+ ctx->gss_flags = (GSS_C_TRANS_FLAG |
+ ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
+ GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
+ GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
+ GSS_C_EXTENDED_ERROR_FLAG)));
+ ctx->seed_init = 0;
+ ctx->cred_rcache = cred_rcache;
+
+ /* XXX move this into gss_name_t */
+ if ( (code = krb5_merge_authdata(context,
+ ticket->enc_part2->authorization_data,
+ authdat->authorization_data,
+ &ctx->authdata))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ if ((code = kg_init_name(context, ticket->server, NULL, NULL, NULL, 0,
+ &ctx->here))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ if ((code = krb5_auth_con_get_authdata_context(context, auth_context,
+ &ad_context))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ if ((code = kg_init_name(context, authdat->client, NULL, NULL,
+ ad_context, KG_INIT_NAME_NO_COPY, &ctx->there))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ /* Now owned by ctx->there */
+ authdat->client = NULL;
+ krb5_auth_con_set_authdata_context(context, auth_context, NULL);
+
+ if ((code = krb5_auth_con_getrecvsubkey_k(context, auth_context,
+ &ctx->subkey))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* use the session key if the subkey isn't present */
+
+ if (ctx->subkey == NULL) {
+ if ((code = krb5_auth_con_getkey_k(context, auth_context,
+ &ctx->subkey))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ if (ctx->subkey == NULL) {
+ /* this isn't a very good error, but it's not clear to me this
+ can actually happen */
+ major_status = GSS_S_FAILURE;
+ code = KRB5KDC_ERR_NULL_KEY;
+ goto fail;
+ }
+
+ ctx->enc = NULL;
+ ctx->seq = NULL;
+ ctx->have_acceptor_subkey = 0;
+ /* DCE_STYLE implies acceptor_subkey */
+ if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0) {
+ code = kg_setup_keys(context, ctx, ctx->subkey, &ctx->cksumtype);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+ ctx->krb_times = ticket->enc_part2->times; /* struct copy */
+ ctx->krb_flags = ticket->enc_part2->flags;
+
+ if (delegated_cred_handle != NULL &&
+ deleg_cred == NULL && /* no unconstrained delegation */
+ cred->usage == GSS_C_BOTH &&
+ (ticket->enc_part2->flags & TKT_FLG_FORWARDABLE)) {
+ /*
+ * Now, we always fabricate a delegated credentials handle
+ * containing the service ticket to ourselves, which can be
+ * used for S4U2Proxy.
+ */
+ major_status = create_constrained_deleg_creds(minor_status, cred,
+ ticket, &deleg_cred,
+ context);
+ if (GSS_ERROR(major_status))
+ goto fail;
+ ctx->gss_flags |= GSS_C_DELEG_FLAG;
+ }
+
+ {
+ krb5_int32 seq_temp;
+ krb5_auth_con_getremoteseqnumber(context, auth_context, &seq_temp);
+ ctx->seq_recv = seq_temp;
+ }
+
+ if ((code = krb5_timeofday(context, &now))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
+ (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
+ (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
+ ctx->proto);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* DCE_STYLE implies mutual authentication */
+ if (ctx->gss_flags & GSS_C_DCE_STYLE)
+ ctx->gss_flags |= GSS_C_MUTUAL_FLAG;
+
+ /* at this point, the entire context structure is filled in,
+ so it can be released. */
+
+ /* generate an AP_REP if necessary */
+
+ if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
+ unsigned char * ptr3;
+ krb5_int32 seq_temp;
+ int cfx_generate_subkey;
+
+ /*
+ * Do not generate a subkey per RFC 4537 unless we are upgrading to CFX,
+ * because pre-CFX tokens do not indicate which key to use. (Note that
+ * DCE_STYLE implies that we will use a subkey.)
+ */
+ if (ctx->proto == 0 &&
+ (ctx->gss_flags & GSS_C_DCE_STYLE) == 0 &&
+ (ap_req_options & AP_OPTS_USE_SUBKEY)) {
+ code = (*kaccess.auth_con_get_subkey_enctype)(context,
+ auth_context,
+ &negotiated_etype);
+ if (code != 0) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ switch (negotiated_etype) {
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES_CBC_MD4:
+ case ENCTYPE_DES_CBC_CRC:
+ case ENCTYPE_DES3_CBC_SHA1:
+ case ENCTYPE_ARCFOUR_HMAC:
+ case ENCTYPE_ARCFOUR_HMAC_EXP:
+ /* RFC 4121 accidentally omits RC4-HMAC-EXP as a "not-newer"
+ * enctype, even though RFC 4757 treats it as one. */
+ ap_req_options &= ~(AP_OPTS_USE_SUBKEY);
+ break;
+ }
+ }
+
+ if (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) ||
+ (ap_req_options & AP_OPTS_USE_SUBKEY))
+ cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
+ else
+ cfx_generate_subkey = 0;
+
+ if (cfx_generate_subkey) {
+ krb5_int32 acflags;
+ code = krb5_auth_con_getflags(context, auth_context, &acflags);
+ if (code == 0) {
+ acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
+ code = krb5_auth_con_setflags(context, auth_context, acflags);
+ }
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ krb5_auth_con_getlocalseqnumber(context, auth_context, &seq_temp);
+ ctx->seq_send = seq_temp & 0xffffffffL;
+
+ if (cfx_generate_subkey) {
+ /* Get the new acceptor subkey. With the code above, there
+ should always be one if we make it to this point. */
+ code = krb5_auth_con_getsendsubkey_k(context, auth_context,
+ &ctx->acceptor_subkey);
+ if (code != 0) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ ctx->have_acceptor_subkey = 1;
+
+ code = kg_setup_keys(context, ctx, ctx->acceptor_subkey,
+ &ctx->acceptor_subkey_cksumtype);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* the reply token hasn't been sent yet, but that's ok. */
+ if (ctx->gss_flags & GSS_C_DCE_STYLE) {
+ assert(ctx->have_acceptor_subkey);
+
+ /* in order to force acceptor subkey to be used, don't set PROT_READY */
+
+ /* Raw AP-REP is returned */
+ code = data_to_gss(&ap_rep, output_token);
+ if (code)
+ {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ ctx->established = 0;
+
+ *context_handle = (gss_ctx_id_t)ctx;
+ *minor_status = 0;
+ major_status = GSS_S_CONTINUE_NEEDED;
+
+ /* Only last leg should set return arguments */
+ goto fail;
+ } else
+ ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
+
+ ctx->established = 1;
+
+ token.length = g_token_size(mech_used, ap_rep.length);
+
+ if ((token.value = (unsigned char *) gssalloc_malloc(token.length))
+ == NULL) {
+ major_status = GSS_S_FAILURE;
+ code = ENOMEM;
+ goto fail;
+ }
+ ptr3 = token.value;
+ g_make_token_header(mech_used, ap_rep.length,
+ &ptr3, KG_TOK_CTX_AP_REP);
+
+ TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
+
+ ctx->established = 1;
+
+ } else {
+ token.length = 0;
+ token.value = NULL;
+ ctx->seq_send = ctx->seq_recv;
+
+ ctx->established = 1;
+ }
+
+ /* set the return arguments */
+
+ if (src_name) {
+ code = kg_duplicate_name(context, ctx->there, &name);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ if (mech_type)
+ *mech_type = (gss_OID) mech_used;
+
+ /* Add the maximum allowable clock skew as a grace period for context
+ * expiration, just as we do for the ticket. */
+ if (time_rec)
+ *time_rec = ctx->krb_times.endtime + context->clockskew - now;
+
+ if (ret_flags)
+ *ret_flags = ctx->gss_flags;
+
+ *context_handle = (gss_ctx_id_t)ctx;
+ *output_token = token;
+
+ if (src_name)
+ *src_name = (gss_name_t) name;
+
+ if (delegated_cred_handle)
+ *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
+
+ /* finally! */
+
+ *minor_status = 0;
+ major_status = GSS_S_COMPLETE;
+
+fail:
+ if (authdat)
+ krb5_free_authenticator(context, authdat);
+ /* The ctx structure has the handle of the auth_context */
+ if (auth_context && !ctx) {
+ if (cred_rcache)
+ (void)krb5_auth_con_setrcache(context, auth_context, NULL);
+
+ krb5_auth_con_free(context, auth_context);
+ }
+ if (reqcksum.contents)
+ xfree(reqcksum.contents);
+ if (ap_rep.data)
+ krb5_free_data_contents(context, &ap_rep);
+ if (major_status == GSS_S_COMPLETE ||
+ (major_status == GSS_S_CONTINUE_NEEDED && code != KRB5KRB_AP_ERR_MSG_TYPE)) {
+ ctx->k5_context = context;
+ context = NULL;
+ goto done;
+ }
+
+ /* from here on is the real "fail" code */
+
+ if (ctx)
+ (void) krb5_gss_delete_sec_context(&tmp_minor_status,
+ (gss_ctx_id_t *) &ctx, NULL);
+ if (deleg_cred) { /* free memory associated with the deleg credential */
+ if (deleg_cred->ccache)
+ (void)krb5_cc_close(context, deleg_cred->ccache);
+ if (deleg_cred->name)
+ kg_release_name(context, &deleg_cred->name);
+ xfree(deleg_cred);
+ }
+ if (token.value)
+ xfree(token.value);
+ if (name) {
+ (void) kg_release_name(context, &name);
+ }
+
+ *minor_status = code;
+
+ /* We may have failed before being able to read the GSS flags from the
+ * authenticator, so also check the request AP options. */
+ if (cred != NULL && request != NULL &&
+ ((gss_flags & GSS_C_MUTUAL_FLAG) ||
+ (request->ap_options & AP_OPTS_MUTUAL_REQUIRED) ||
+ major_status == GSS_S_CONTINUE_NEEDED)) {
+ unsigned int tmsglen;
+ int toktype;
+
+ /*
+ * The client is expecting a response, so we can send an
+ * error token back
+ */
+ memset(&krb_error_data, 0, sizeof(krb_error_data));
+
+ code -= ERROR_TABLE_BASE_krb5;
+ if (code < 0 || code > KRB_ERR_MAX)
+ code = 60 /* KRB_ERR_GENERIC */;
+
+ krb_error_data.error = code;
+ (void) krb5_us_timeofday(context, &krb_error_data.stime,
+ &krb_error_data.susec);
+
+ krb_error_data.server = ticket->server;
+ code = krb5_mk_error(context, &krb_error_data, &scratch);
+ if (code)
+ goto done;
+
+ tmsglen = scratch.length;
+ toktype = KG_TOK_CTX_ERROR;
+
+ token.length = g_token_size(mech_used, tmsglen);
+ token.value = gssalloc_malloc(token.length);
+ if (!token.value)
+ goto done;
+
+ ptr = token.value;
+ g_make_token_header(mech_used, tmsglen, &ptr, toktype);
+
+ TWRITE_STR(ptr, scratch.data, scratch.length);
+ krb5_free_data_contents(context, &scratch);
+
+ *output_token = token;
+ }
+
+done:
+ krb5_free_ap_req(context, request);
+ if (cred)
+ k5_mutex_unlock(&cred->lock);
+ if (defcred)
+ krb5_gss_release_cred(&tmp_minor_status, &defcred);
+ if (context) {
+ if (major_status && *minor_status)
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ }
+ return (major_status);
+}
+#endif /* LEAN_CLIENT */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_accept_sec_context_ext(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_cred_id_t verifier_cred_handle,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle,
+ krb5_gss_ctx_ext_t exts)
+{
+ krb5_gss_ctx_id_rec *ctx = (krb5_gss_ctx_id_rec *)*context_handle;
+
+ /*
+ * Context handle must be unspecified. Actually, it must be
+ * non-established, but currently, accept_sec_context never returns
+ * a non-established context handle.
+ */
+ /*SUPPRESS 29*/
+ if (ctx != NULL) {
+ if (ctx->established == 0 && (ctx->gss_flags & GSS_C_DCE_STYLE)) {
+ return kg_accept_dce(minor_status, context_handle,
+ verifier_cred_handle, input_token,
+ input_chan_bindings, src_name, mech_type,
+ output_token, ret_flags, time_rec,
+ delegated_cred_handle);
+ } else {
+ *minor_status = EINVAL;
+ save_error_string(EINVAL, "accept_sec_context called with existing context handle");
+ return GSS_S_FAILURE;
+ }
+ }
+
+ return kg_accept_krb5(minor_status, context_handle,
+ verifier_cred_handle, input_token,
+ input_chan_bindings, src_name, mech_type,
+ output_token, ret_flags, time_rec,
+ delegated_cred_handle, exts);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_accept_sec_context(minor_status, context_handle,
+ verifier_cred_handle, input_token,
+ input_chan_bindings, src_name, mech_type,
+ output_token, ret_flags, time_rec,
+ delegated_cred_handle)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t *context_handle;
+ gss_cred_id_t verifier_cred_handle;
+ gss_buffer_t input_token;
+ gss_channel_bindings_t input_chan_bindings;
+ gss_name_t *src_name;
+ gss_OID *mech_type;
+ gss_buffer_t output_token;
+ OM_uint32 *ret_flags;
+ OM_uint32 *time_rec;
+ gss_cred_id_t *delegated_cred_handle;
+{
+ krb5_gss_ctx_ext_rec exts;
+
+ memset(&exts, 0, sizeof(exts));
+
+ return krb5_gss_accept_sec_context_ext(minor_status,
+ context_handle,
+ verifier_cred_handle,
+ input_token,
+ input_chan_bindings,
+ src_name,
+ mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle,
+ &exts);
+}
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
new file mode 100644
index 000000000000..03ee25ec1861
--- /dev/null
+++ b/src/lib/gssapi/krb5/acquire_cred.c
@@ -0,0 +1,1261 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2000, 2007-2010 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifdef USE_LEASH
+#ifdef _WIN64
+#define LEASH_DLL "leashw64.dll"
+#else
+#define LEASH_DLL "leashw32.dll"
+#endif
+static void (*pLeash_AcquireInitialTicketsIfNeeded)(krb5_context,krb5_principal,char*,int) = NULL;
+static HANDLE hLeashDLL = INVALID_HANDLE_VALUE;
+#endif
+
+#ifndef LEAN_CLIENT
+k5_mutex_t gssint_krb5_keytab_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+static char *krb5_gss_keytab = NULL;
+
+/* Heimdal calls this gsskrb5_register_acceptor_identity. */
+OM_uint32
+gss_krb5int_register_acceptor_identity(OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ const gss_OID desired_object,
+ gss_buffer_t value)
+{
+ char *new = NULL, *old;
+ int err;
+
+ err = gss_krb5int_initialize_library();
+ if (err != 0)
+ return GSS_S_FAILURE;
+
+ if (value->value != NULL) {
+ new = strdup((char *)value->value);
+ if (new == NULL)
+ return GSS_S_FAILURE;
+ }
+
+ k5_mutex_lock(&gssint_krb5_keytab_lock);
+ old = krb5_gss_keytab;
+ krb5_gss_keytab = new;
+ k5_mutex_unlock(&gssint_krb5_keytab_lock);
+ free(old);
+ return GSS_S_COMPLETE;
+}
+
+/* Try to verify that keytab contains at least one entry for name. Return 0 if
+ * it does, KRB5_KT_NOTFOUND if it doesn't, or another error as appropriate. */
+static krb5_error_code
+check_keytab(krb5_context context, krb5_keytab kt, krb5_gss_name_t name)
+{
+ krb5_error_code code;
+ krb5_keytab_entry ent;
+ krb5_kt_cursor cursor;
+ krb5_principal accprinc = NULL;
+ krb5_boolean match;
+ char *princname;
+
+ if (name->service == NULL) {
+ code = krb5_kt_get_entry(context, kt, name->princ, 0, 0, &ent);
+ if (code == 0)
+ krb5_kt_free_entry(context, &ent);
+ return code;
+ }
+
+ /* If we can't iterate through the keytab, skip this check. */
+ if (kt->ops->start_seq_get == NULL)
+ return 0;
+
+ /* Get the partial principal for the acceptor name. */
+ code = kg_acceptor_princ(context, name, &accprinc);
+ if (code)
+ return code;
+
+ /* Scan the keytab for host-based entries matching accprinc. */
+ code = krb5_kt_start_seq_get(context, kt, &cursor);
+ if (code)
+ goto cleanup;
+ while ((code = krb5_kt_next_entry(context, kt, &ent, &cursor)) == 0) {
+ match = krb5_sname_match(context, accprinc, ent.principal);
+ (void)krb5_free_keytab_entry_contents(context, &ent);
+ if (match)
+ break;
+ }
+ (void)krb5_kt_end_seq_get(context, kt, &cursor);
+ if (code == KRB5_KT_END) {
+ code = KRB5_KT_NOTFOUND;
+ if (krb5_unparse_name(context, accprinc, &princname) == 0) {
+ k5_setmsg(context, code, _("No key table entry found matching %s"),
+ princname);
+ free(princname);
+ }
+ }
+
+cleanup:
+ krb5_free_principal(context, accprinc);
+ return code;
+}
+
+/* get credentials corresponding to a key in the krb5 keytab.
+ If successful, set the keytab-specific fields in cred
+*/
+
+static OM_uint32
+acquire_accept_cred(krb5_context context, OM_uint32 *minor_status,
+ krb5_keytab req_keytab, const char *rcname,
+ krb5_gss_cred_id_rec *cred)
+{
+ OM_uint32 major;
+ krb5_error_code code;
+ krb5_keytab kt = NULL;
+ krb5_rcache rc = NULL;
+
+ assert(cred->keytab == NULL);
+
+ /* If we have an explicit rcache name, open it. */
+ if (rcname != NULL) {
+ code = krb5_rc_resolve_full(context, &rc, rcname);
+ if (code) {
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ code = krb5_rc_recover_or_initialize(context, rc, context->clockskew);
+ if (code) {
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ }
+
+ if (req_keytab != NULL) {
+ code = krb5_kt_dup(context, req_keytab, &kt);
+ } else {
+ k5_mutex_lock(&gssint_krb5_keytab_lock);
+ if (krb5_gss_keytab != NULL) {
+ code = krb5_kt_resolve(context, krb5_gss_keytab, &kt);
+ k5_mutex_unlock(&gssint_krb5_keytab_lock);
+ } else {
+ k5_mutex_unlock(&gssint_krb5_keytab_lock);
+ code = krb5_kt_default(context, &kt);
+ }
+ }
+ if (code) {
+ major = GSS_S_CRED_UNAVAIL;
+ goto cleanup;
+ }
+
+ if (cred->name != NULL) {
+ /* Make sure we have keys matching the desired name in the keytab. */
+ code = check_keytab(context, kt, cred->name);
+ if (code) {
+ if (code == KRB5_KT_NOTFOUND) {
+ k5_change_error_message_code(context, code, KG_KEYTAB_NOMATCH);
+ code = KG_KEYTAB_NOMATCH;
+ }
+ major = GSS_S_CRED_UNAVAIL;
+ goto cleanup;
+ }
+
+ if (rc == NULL) {
+ /* Open the replay cache for this principal. */
+ code = krb5_get_server_rcache(context, &cred->name->princ->data[0],
+ &rc);
+ if (code) {
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ }
+ } else {
+ /* Make sure we have a keytab with keys in it. */
+ code = krb5_kt_have_content(context, kt);
+ if (code) {
+ major = GSS_S_CRED_UNAVAIL;
+ goto cleanup;
+ }
+ }
+
+ cred->keytab = kt;
+ kt = NULL;
+ cred->rcache = rc;
+ rc = NULL;
+ major = GSS_S_COMPLETE;
+
+cleanup:
+ if (kt != NULL)
+ krb5_kt_close(context, kt);
+ if (rc != NULL)
+ krb5_rc_close(context, rc);
+ *minor_status = code;
+ return major;
+}
+#endif /* LEAN_CLIENT */
+
+#ifdef USE_LEASH
+static krb5_error_code
+get_ccache_leash(krb5_context context, krb5_principal desired_princ,
+ krb5_ccache *ccache_out)
+{
+ krb5_error_code code;
+ krb5_ccache ccache;
+ char ccname[256] = "";
+
+ *ccache_out = NULL;
+
+ if (hLeashDLL == INVALID_HANDLE_VALUE) {
+ hLeashDLL = LoadLibrary(LEASH_DLL);
+ if (hLeashDLL != INVALID_HANDLE_VALUE) {
+ (FARPROC) pLeash_AcquireInitialTicketsIfNeeded =
+ GetProcAddress(hLeashDLL, "not_an_API_Leash_AcquireInitialTicketsIfNeeded");
+ }
+ }
+
+ if (pLeash_AcquireInitialTicketsIfNeeded) {
+ pLeash_AcquireInitialTicketsIfNeeded(context, desired_princ, ccname,
+ sizeof(ccname));
+ if (!ccname[0])
+ return KRB5_CC_NOTFOUND;
+
+ code = krb5_cc_resolve(context, ccname, &ccache);
+ if (code)
+ return code;
+ } else {
+ /* leash dll not available, open the default credential cache. */
+ code = krb5int_cc_default(context, &ccache);
+ if (code)
+ return code;
+ }
+
+ *ccache_out = ccache;
+ return 0;
+}
+#endif /* USE_LEASH */
+
+/* Set fields in cred according to a ccache config entry whose key (in
+ * principal form) is config_princ and whose value is value. */
+static krb5_error_code
+scan_cc_config(krb5_context context, krb5_gss_cred_id_rec *cred,
+ krb5_const_principal config_princ, const krb5_data *value)
+{
+ krb5_error_code code;
+ krb5_data data0 = empty_data();
+
+ if (config_princ->length != 2)
+ return 0;
+ if (data_eq_string(config_princ->data[1], KRB5_CC_CONF_PROXY_IMPERSONATOR)
+ && cred->impersonator == NULL) {
+ code = krb5int_copy_data_contents_add0(context, value, &data0);
+ if (code)
+ return code;
+ code = krb5_parse_name(context, data0.data, &cred->impersonator);
+ krb5_free_data_contents(context, &data0);
+ if (code)
+ return code;
+ } else if (data_eq_string(config_princ->data[1], KRB5_CC_CONF_REFRESH_TIME)
+ && cred->refresh_time == 0) {
+ code = krb5int_copy_data_contents_add0(context, value, &data0);
+ if (code)
+ return code;
+ cred->refresh_time = atol(data0.data);
+ krb5_free_data_contents(context, &data0);
+ }
+ return 0;
+}
+
+/* Return true if it appears that we can non-interactively get initial
+ * tickets for cred. */
+static krb5_boolean
+can_get_initial_creds(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+ krb5_keytab_entry entry;
+
+ if (cred->password != NULL)
+ return TRUE;
+
+ if (cred->client_keytab == NULL)
+ return FALSE;
+
+ /* If we don't know the client principal yet, check for any keytab keys. */
+ if (cred->name == NULL)
+ return !krb5_kt_have_content(context, cred->client_keytab);
+
+ /* Check if we have a keytab key for the client principal. */
+ code = krb5_kt_get_entry(context, cred->client_keytab, cred->name->princ,
+ 0, 0, &entry);
+ if (code) {
+ krb5_clear_error_message(context);
+ return FALSE;
+ }
+ krb5_free_keytab_entry_contents(context, &entry);
+ return TRUE;
+}
+
+/* Scan cred->ccache for name, expiry time, impersonator, refresh time. */
+static krb5_error_code
+scan_ccache(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+ krb5_ccache ccache = cred->ccache;
+ krb5_principal ccache_princ = NULL, tgt_princ = NULL;
+ krb5_data *realm;
+ krb5_cc_cursor cursor;
+ krb5_creds creds;
+ krb5_timestamp endtime;
+ krb5_boolean is_tgt;
+
+ /* Turn on NOTICKET, as we don't need session keys here. */
+ code = krb5_cc_set_flags(context, ccache, KRB5_TC_NOTICKET);
+ if (code)
+ return code;
+
+ /* Credentials cache principal must match the initiator name. */
+ code = krb5_cc_get_principal(context, ccache, &ccache_princ);
+ if (code != 0)
+ goto cleanup;
+ if (cred->name != NULL &&
+ !krb5_principal_compare(context, ccache_princ, cred->name->princ)) {
+ code = KG_CCACHE_NOMATCH;
+ goto cleanup;
+ }
+
+ /* Save the ccache principal as the credential name if not already set. */
+ if (!cred->name) {
+ code = kg_init_name(context, ccache_princ, NULL, NULL, NULL,
+ KG_INIT_NAME_NO_COPY, &cred->name);
+ if (code)
+ goto cleanup;
+ ccache_princ = NULL;
+ }
+
+ assert(cred->name->princ != NULL);
+ realm = krb5_princ_realm(context, cred->name->princ);
+ code = krb5_build_principal_ext(context, &tgt_princ,
+ realm->length, realm->data,
+ KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
+ realm->length, realm->data,
+ 0);
+ if (code)
+ return code;
+
+ /* If there's a tgt for the principal's local realm in here, use its expiry
+ * time. Otherwise use the first key. */
+ code = krb5_cc_start_seq_get(context, ccache, &cursor);
+ if (code) {
+ krb5_free_principal(context, tgt_princ);
+ return code;
+ }
+ while (!(code = krb5_cc_next_cred(context, ccache, &cursor, &creds))) {
+ if (krb5_is_config_principal(context, creds.server)) {
+ code = scan_cc_config(context, cred, creds.server, &creds.ticket);
+ krb5_free_cred_contents(context, &creds);
+ if (code)
+ break;
+ continue;
+ }
+ is_tgt = krb5_principal_compare(context, tgt_princ, creds.server);
+ endtime = creds.times.endtime;
+ krb5_free_cred_contents(context, &creds);
+ if (is_tgt)
+ cred->have_tgt = TRUE;
+ if (is_tgt || cred->expire == 0)
+ cred->expire = endtime;
+ }
+ krb5_cc_end_seq_get(context, ccache, &cursor);
+ if (code && code != KRB5_CC_END)
+ goto cleanup;
+ code = 0;
+
+ if (cred->expire == 0 && !can_get_initial_creds(context, cred)) {
+ code = KG_EMPTY_CCACHE;
+ goto cleanup;
+ }
+
+cleanup:
+ (void)krb5_cc_set_flags(context, ccache, 0);
+ krb5_free_principal(context, ccache_princ);
+ krb5_free_principal(context, tgt_princ);
+ return code;
+}
+
+/* Find an existing or destination ccache for cred->name. */
+static krb5_error_code
+get_cache_for_name(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+ krb5_boolean can_get, have_collection;
+ krb5_ccache defcc = NULL;
+ krb5_principal princ = NULL;
+ const char *cctype;
+
+ assert(cred->name != NULL && cred->ccache == NULL);
+#ifdef USE_LEASH
+ code = get_ccache_leash(context, cred->name->princ, &cred->ccache);
+ return code ? code : scan_ccache(context, cred);
+#else
+ /* Check first whether we can acquire tickets, to avoid overwriting the
+ * extended error message from krb5_cc_cache_match. */
+ can_get = can_get_initial_creds(context, cred);
+
+ /* Look for an existing cache for the client principal. */
+ code = krb5_cc_cache_match(context, cred->name->princ, &cred->ccache);
+ if (code == 0)
+ return scan_ccache(context, cred);
+ if (code != KRB5_CC_NOTFOUND || !can_get)
+ return code;
+ krb5_clear_error_message(context);
+
+ /* There is no existing ccache, but we can acquire credentials. Get the
+ * default ccache to help decide where we should put them. */
+ code = krb5_cc_default(context, &defcc);
+ if (code)
+ return code;
+ cctype = krb5_cc_get_type(context, defcc);
+ have_collection = krb5_cc_support_switch(context, cctype);
+
+ /* We can use an empty default ccache if we're using a password or if
+ * there's no collection. */
+ if (cred->password != NULL || !have_collection) {
+ if (krb5_cc_get_principal(context, defcc, &princ) == KRB5_FCC_NOFILE) {
+ cred->ccache = defcc;
+ defcc = NULL;
+ }
+ krb5_clear_error_message(context);
+ }
+
+ /* Otherwise, try to use a new cache in the collection. */
+ if (cred->ccache == NULL) {
+ if (!have_collection) {
+ code = KG_CCACHE_NOMATCH;
+ goto cleanup;
+ }
+ code = krb5_cc_new_unique(context, cctype, NULL, &cred->ccache);
+ if (code)
+ goto cleanup;
+ }
+
+cleanup:
+ krb5_free_principal(context, princ);
+ if (defcc != NULL)
+ krb5_cc_close(context, defcc);
+ return code;
+#endif /* not USE_LEASH */
+}
+
+/* Try to set cred->name using the client keytab. */
+static krb5_error_code
+get_name_from_client_keytab(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+ krb5_principal princ;
+
+ assert(cred->name == NULL);
+
+ if (cred->client_keytab == NULL)
+ return KRB5_KT_NOTFOUND;
+
+ code = k5_kt_get_principal(context, cred->client_keytab, &princ);
+ if (code)
+ return code;
+ code = kg_init_name(context, princ, NULL, NULL, NULL, KG_INIT_NAME_NO_COPY,
+ &cred->name);
+ if (code) {
+ krb5_free_principal(context, princ);
+ return code;
+ }
+ return 0;
+}
+
+/* Make a note in ccache that we should attempt to refresh it from the client
+ * keytab at refresh_time. */
+static void
+set_refresh_time(krb5_context context, krb5_ccache ccache,
+ krb5_timestamp refresh_time)
+{
+ char buf[128];
+ krb5_data d;
+
+ snprintf(buf, sizeof(buf), "%ld", (long)refresh_time);
+ d = string2data(buf);
+ (void)krb5_cc_set_config(context, ccache, NULL, KRB5_CC_CONF_REFRESH_TIME,
+ &d);
+ krb5_clear_error_message(context);
+}
+
+/* Return true if it's time to refresh cred from the client keytab. If
+ * returning true, avoid retrying for 30 seconds. */
+krb5_boolean
+kg_cred_time_to_refresh(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_timestamp now;
+
+ if (krb5_timeofday(context, &now))
+ return FALSE;
+ if (cred->refresh_time != 0 && now >= cred->refresh_time) {
+ set_refresh_time(context, cred->ccache, cred->refresh_time + 30);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* If appropriate, make a note to refresh cred from the client keytab when it
+ * is halfway to expired. */
+void
+kg_cred_set_initial_refresh(krb5_context context, krb5_gss_cred_id_rec *cred,
+ krb5_ticket_times *times)
+{
+ krb5_timestamp refresh;
+
+ /* For now, we only mark keytab-acquired credentials for refresh. */
+ if (cred->password != NULL)
+ return;
+
+ /* Make a note to refresh these when they are halfway to expired. */
+ refresh = times->starttime + (times->endtime - times->starttime) / 2;
+ set_refresh_time(context, cred->ccache, refresh);
+}
+
+/* Get initial credentials using the supplied password or client keytab. */
+static krb5_error_code
+get_initial_cred(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+ krb5_get_init_creds_opt *opt = NULL;
+ krb5_creds creds;
+
+ code = krb5_get_init_creds_opt_alloc(context, &opt);
+ if (code)
+ return code;
+ code = krb5_get_init_creds_opt_set_out_ccache(context, opt, cred->ccache);
+ if (code)
+ goto cleanup;
+ if (cred->password != NULL) {
+ code = krb5_get_init_creds_password(context, &creds, cred->name->princ,
+ cred->password, NULL, NULL, 0,
+ NULL, opt);
+ } else if (cred->client_keytab != NULL) {
+ code = krb5_get_init_creds_keytab(context, &creds, cred->name->princ,
+ cred->client_keytab, 0, NULL, opt);
+ } else {
+ code = KRB5_KT_NOTFOUND;
+ }
+ if (code)
+ goto cleanup;
+ kg_cred_set_initial_refresh(context, cred, &creds.times);
+ cred->have_tgt = TRUE;
+ cred->expire = creds.times.endtime;
+ krb5_free_cred_contents(context, &creds);
+cleanup:
+ krb5_get_init_creds_opt_free(context, opt);
+ return code;
+}
+
+/* Get initial credentials if we ought to and are able to. */
+static krb5_error_code
+maybe_get_initial_cred(krb5_context context, krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+
+ /* Don't get creds if we don't know the name or are doing IAKERB. */
+ if (cred->name == NULL || cred->iakerb_mech)
+ return 0;
+
+ /* Get creds if we have none or if it's time to refresh. */
+ if (cred->expire == 0 || kg_cred_time_to_refresh(context, cred)) {
+ code = get_initial_cred(context, cred);
+ /* If we were trying to refresh and failed, we can keep going. */
+ if (code && cred->expire == 0)
+ return code;
+ krb5_clear_error_message(context);
+ }
+ return 0;
+}
+
+static OM_uint32
+acquire_init_cred(krb5_context context,
+ OM_uint32 *minor_status,
+ krb5_ccache req_ccache,
+ gss_buffer_t password,
+ krb5_keytab client_keytab,
+ krb5_gss_cred_id_rec *cred)
+{
+ krb5_error_code code;
+ krb5_data pwdata, pwcopy;
+ int caller_ccname = 0;
+
+ /* Get ccache from caller if available. */
+ if (GSS_ERROR(kg_sync_ccache_name(context, minor_status)))
+ return GSS_S_FAILURE;
+ if (GSS_ERROR(kg_caller_provided_ccache_name(minor_status,
+ &caller_ccname)))
+ return GSS_S_FAILURE;
+
+ if (password != GSS_C_NO_BUFFER) {
+ pwdata = make_data(password->value, password->length);
+ code = krb5int_copy_data_contents_add0(context, &pwdata, &pwcopy);
+ if (code)
+ goto error;
+ cred->password = pwcopy.data;
+
+ /* We will fetch the credential into a private memory ccache. */
+ assert(req_ccache == NULL);
+ code = krb5_cc_new_unique(context, "MEMORY", NULL, &cred->ccache);
+ if (code)
+ goto error;
+ cred->destroy_ccache = 1;
+ } else if (req_ccache != NULL) {
+ code = krb5_cc_dup(context, req_ccache, &cred->ccache);
+ if (code)
+ goto error;
+ } else if (caller_ccname) {
+ /* Caller's ccache name has been set as the context default. */
+ code = krb5int_cc_default(context, &cred->ccache);
+ if (code)
+ goto error;
+ }
+
+ if (client_keytab != NULL) {
+ code = krb5_kt_dup(context, client_keytab, &cred->client_keytab);
+ } else {
+ code = krb5_kt_client_default(context, &cred->client_keytab);
+ if (code) {
+ /* Treat resolution failure similarly to a client keytab which
+ * resolves but doesn't exist or has no content. */
+ TRACE_GSS_CLIENT_KEYTAB_FAIL(context, code);
+ krb5_clear_error_message(context);
+ code = 0;
+ }
+ }
+ if (code)
+ goto error;
+
+ if (cred->ccache != NULL) {
+ /* The caller specified a ccache; check what's in it. */
+ code = scan_ccache(context, cred);
+ if (code == KRB5_FCC_NOFILE) {
+ /* See if we can get initial creds. If the caller didn't specify
+ * a name, pick one from the client keytab. */
+ if (cred->name == NULL) {
+ if (!get_name_from_client_keytab(context, cred))
+ code = 0;
+ } else if (can_get_initial_creds(context, cred)) {
+ code = 0;
+ }
+ }
+ if (code)
+ goto error;
+ } else if (cred->name != NULL) {
+ /* The caller specified a name but not a ccache; pick a cache. */
+ code = get_cache_for_name(context, cred);
+ if (code)
+ goto error;
+ }
+
+#ifndef USE_LEASH
+ /* If we haven't picked a name, make sure we have or can get any creds,
+ * unless we're using Leash and might be able to get them interactively. */
+ if (cred->name == NULL && !can_get_initial_creds(context, cred)) {
+ code = krb5_cccol_have_content(context);
+ if (code)
+ goto error;
+ }
+#endif
+
+ code = maybe_get_initial_cred(context, cred);
+ if (code)
+ goto error;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+
+error:
+ *minor_status = code;
+ return GSS_S_CRED_UNAVAIL;
+}
+
+static OM_uint32
+acquire_cred_context(krb5_context context, OM_uint32 *minor_status,
+ gss_name_t desired_name, gss_buffer_t password,
+ OM_uint32 time_req, gss_cred_usage_t cred_usage,
+ krb5_ccache ccache, krb5_keytab client_keytab,
+ krb5_keytab keytab, const char *rcname,
+ krb5_boolean iakerb, gss_cred_id_t *output_cred_handle,
+ OM_uint32 *time_rec)
+{
+ krb5_gss_cred_id_t cred = NULL;
+ krb5_gss_name_t name = (krb5_gss_name_t)desired_name;
+ OM_uint32 ret;
+ krb5_error_code code = 0;
+
+ /* make sure all outputs are valid */
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+ if (time_rec)
+ *time_rec = 0;
+
+ /* create the gss cred structure */
+ cred = k5alloc(sizeof(krb5_gss_cred_id_rec), &code);
+ if (cred == NULL)
+ goto krb_error_out;
+
+ cred->usage = cred_usage;
+ cred->name = NULL;
+ cred->impersonator = NULL;
+ cred->iakerb_mech = iakerb;
+ cred->default_identity = (name == NULL);
+#ifndef LEAN_CLIENT
+ cred->keytab = NULL;
+#endif /* LEAN_CLIENT */
+ cred->destroy_ccache = 0;
+ cred->suppress_ci_flags = 0;
+ cred->ccache = NULL;
+
+ code = k5_mutex_init(&cred->lock);
+ if (code)
+ goto krb_error_out;
+
+ switch (cred_usage) {
+ case GSS_C_INITIATE:
+ case GSS_C_ACCEPT:
+ case GSS_C_BOTH:
+ break;
+ default:
+ ret = GSS_S_FAILURE;
+ *minor_status = (OM_uint32) G_BAD_USAGE;
+ goto error_out;
+ }
+
+ if (name != NULL) {
+ code = kg_duplicate_name(context, name, &cred->name);
+ if (code)
+ goto krb_error_out;
+ }
+
+#ifndef LEAN_CLIENT
+ /*
+ * If requested, acquire credentials for accepting. This will fill
+ * in cred->name if desired_princ is specified.
+ */
+ if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {
+ ret = acquire_accept_cred(context, minor_status, keytab, rcname, cred);
+ if (ret != GSS_S_COMPLETE)
+ goto error_out;
+ }
+#endif /* LEAN_CLIENT */
+
+ /*
+ * If requested, acquire credentials for initiation. This will fill
+ * in cred->name if it wasn't set above.
+ */
+ if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
+ ret = acquire_init_cred(context, minor_status, ccache, password,
+ client_keytab, cred);
+ if (ret != GSS_S_COMPLETE)
+ goto error_out;
+ }
+
+ assert(cred->default_identity || cred->name != NULL);
+
+ /*** at this point, the cred structure has been completely created */
+
+ if (cred_usage == GSS_C_ACCEPT) {
+ if (time_rec)
+ *time_rec = GSS_C_INDEFINITE;
+ } else {
+ krb5_timestamp now;
+
+ code = krb5_timeofday(context, &now);
+ if (code != 0)
+ goto krb_error_out;
+
+ if (time_rec) {
+ /* Resolve cred now to determine the expiration time. */
+ ret = kg_cred_resolve(minor_status, context, (gss_cred_id_t)cred,
+ GSS_C_NO_NAME);
+ if (GSS_ERROR(ret))
+ goto error_out;
+ *time_rec = (cred->expire > now) ? (cred->expire - now) : 0;
+ k5_mutex_unlock(&cred->lock);
+ }
+ }
+
+ *minor_status = 0;
+ *output_cred_handle = (gss_cred_id_t) cred;
+
+ return GSS_S_COMPLETE;
+
+krb_error_out:
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+
+error_out:
+ if (cred != NULL) {
+ if (cred->ccache) {
+ if (cred->destroy_ccache)
+ krb5_cc_destroy(context, cred->ccache);
+ else
+ krb5_cc_close(context, cred->ccache);
+ }
+ if (cred->client_keytab)
+ krb5_kt_close(context, cred->client_keytab);
+#ifndef LEAN_CLIENT
+ if (cred->keytab)
+ krb5_kt_close(context, cred->keytab);
+#endif /* LEAN_CLIENT */
+ if (cred->rcache)
+ krb5_rc_close(context, cred->rcache);
+ if (cred->name)
+ kg_release_name(context, &cred->name);
+ krb5_free_principal(context, cred->impersonator);
+ zapfreestr(cred->password);
+ k5_mutex_destroy(&cred->lock);
+ xfree(cred);
+ }
+ save_error_info(*minor_status, context);
+ return ret;
+}
+
+static OM_uint32
+acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name,
+ gss_buffer_t password, OM_uint32 time_req,
+ gss_cred_usage_t cred_usage, krb5_ccache ccache,
+ krb5_keytab keytab, krb5_boolean iakerb,
+ gss_cred_id_t *output_cred_handle, OM_uint32 *time_rec)
+{
+ krb5_context context = NULL;
+ krb5_error_code code = 0;
+ OM_uint32 ret;
+
+ code = gss_krb5int_initialize_library();
+ if (code) {
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+ goto out;
+ }
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+ goto out;
+ }
+
+ ret = acquire_cred_context(context, minor_status, desired_name, password,
+ time_req, cred_usage, ccache, NULL, keytab,
+ NULL, iakerb, output_cred_handle, time_rec);
+
+out:
+ krb5_free_context(context);
+ return ret;
+}
+
+/*
+ * Resolve the name and ccache for an initiator credential if it has not yet
+ * been done. If specified, use the target name to pick an appropriate ccache
+ * within the collection. Validates cred_handle and leaves it locked on
+ * success.
+ */
+OM_uint32
+kg_cred_resolve(OM_uint32 *minor_status, krb5_context context,
+ gss_cred_id_t cred_handle, gss_name_t target_name)
+{
+ OM_uint32 maj;
+ krb5_error_code code;
+ krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t)cred_handle;
+ krb5_gss_name_t tname = (krb5_gss_name_t)target_name;
+ krb5_principal client_princ;
+
+ *minor_status = 0;
+
+ maj = krb5_gss_validate_cred_1(minor_status, cred_handle, context);
+ if (maj != 0)
+ return maj;
+ k5_mutex_assert_locked(&cred->lock);
+
+ if (cred->usage == GSS_C_ACCEPT || cred->name != NULL)
+ return GSS_S_COMPLETE;
+ /* acquire_init_cred should have set both name and ccache, or neither. */
+ assert(cred->ccache == NULL);
+
+ if (tname != NULL) {
+ /* Use the target name to select an existing ccache or a principal. */
+ code = krb5_cc_select(context, tname->princ, &cred->ccache,
+ &client_princ);
+ if (code && code != KRB5_CC_NOTFOUND)
+ goto kerr;
+ if (client_princ != NULL) {
+ code = kg_init_name(context, client_princ, NULL, NULL, NULL,
+ KG_INIT_NAME_NO_COPY, &cred->name);
+ if (code) {
+ krb5_free_principal(context, client_princ);
+ goto kerr;
+ }
+ }
+ if (cred->ccache != NULL) {
+ code = scan_ccache(context, cred);
+ if (code)
+ goto kerr;
+ }
+ }
+
+ /* If we still haven't picked a client principal, try using an existing
+ * default ccache. (On Windows, this may acquire initial creds.) */
+ if (cred->name == NULL) {
+ code = krb5int_cc_default(context, &cred->ccache);
+ if (code)
+ goto kerr;
+ code = scan_ccache(context, cred);
+ if (code == KRB5_FCC_NOFILE) {
+ /* Default ccache doesn't exist; fall through to client keytab. */
+ krb5_cc_close(context, cred->ccache);
+ cred->ccache = NULL;
+ } else if (code) {
+ goto kerr;
+ }
+ }
+
+ /* If that didn't work, try getting a name from the client keytab. */
+ if (cred->name == NULL) {
+ code = get_name_from_client_keytab(context, cred);
+ if (code) {
+ code = KG_EMPTY_CCACHE;
+ goto kerr;
+ }
+ }
+
+ if (cred->name != NULL && cred->ccache == NULL) {
+ /* Pick a cache for the name we chose (from krb5_cc_select or from the
+ * client keytab). */
+ code = get_cache_for_name(context, cred);
+ if (code)
+ goto kerr;
+ }
+
+ /* Resolve name to ccache and possibly get initial credentials. */
+ code = maybe_get_initial_cred(context, cred);
+ if (code)
+ goto kerr;
+
+ return GSS_S_COMPLETE;
+
+kerr:
+ k5_mutex_unlock(&cred->lock);
+ save_error_info(code, context);
+ *minor_status = code;
+ return GSS_S_CRED_UNAVAIL;
+}
+
+OM_uint32
+gss_krb5int_set_cred_rcache(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_oid,
+ const gss_buffer_t value)
+{
+ krb5_gss_cred_id_t cred;
+ krb5_error_code code;
+ krb5_context context;
+ krb5_rcache rcache;
+
+ assert(value->length == sizeof(rcache));
+
+ if (value->length != sizeof(rcache))
+ return GSS_S_FAILURE;
+
+ rcache = (krb5_rcache)value->value;
+
+ cred = (krb5_gss_cred_id_t)*cred_handle;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+ if (cred->rcache != NULL) {
+ code = krb5_rc_close(context, cred->rcache);
+ if (code) {
+ *minor_status = code;
+ krb5_free_context(context);
+ return GSS_S_FAILURE;
+ }
+ }
+
+ cred->rcache = rcache;
+
+ krb5_free_context(context);
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * krb5 and IAKERB mech API functions follow. The mechglue always passes null
+ * desired_mechs and actual_mechs, so we ignore those parameters.
+ */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name,
+ OM_uint32 time_req, gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs, OM_uint32 *time_rec)
+{
+ return acquire_cred(minor_status, desired_name, NULL, time_req, cred_usage,
+ NULL, NULL, FALSE, output_cred_handle, time_rec);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name,
+ OM_uint32 time_req, gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs, OM_uint32 *time_rec)
+{
+ return acquire_cred(minor_status, desired_name, NULL, time_req, cred_usage,
+ NULL, NULL, TRUE, output_cred_handle, time_rec);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred_with_password(OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ return acquire_cred(minor_status, desired_name, password, time_req,
+ cred_usage, NULL, NULL, FALSE, output_cred_handle,
+ time_rec);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_acquire_cred_with_password(OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ return acquire_cred(minor_status, desired_name, password, time_req,
+ cred_usage, NULL, NULL, TRUE, output_cred_handle,
+ time_rec);
+}
+
+OM_uint32
+gss_krb5int_import_cred(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_oid,
+ const gss_buffer_t value)
+{
+ struct krb5_gss_import_cred_req *req;
+ krb5_gss_name_rec name;
+ OM_uint32 time_rec;
+ krb5_error_code code;
+ gss_cred_usage_t usage;
+ gss_name_t desired_name = GSS_C_NO_NAME;
+
+ assert(value->length == sizeof(*req));
+
+ if (value->length != sizeof(*req))
+ return GSS_S_FAILURE;
+
+ req = (struct krb5_gss_import_cred_req *)value->value;
+
+ if (req->id != NULL) {
+ usage = (req->keytab != NULL) ? GSS_C_BOTH : GSS_C_INITIATE;
+ } else if (req->keytab != NULL) {
+ usage = GSS_C_ACCEPT;
+ } else {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ if (req->keytab_principal != NULL) {
+ memset(&name, 0, sizeof(name));
+ code = k5_mutex_init(&name.lock);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+ name.princ = req->keytab_principal;
+ desired_name = (gss_name_t)&name;
+ }
+
+ code = acquire_cred(minor_status, desired_name, NULL, GSS_C_INDEFINITE,
+ usage, req->id, req->keytab, FALSE, cred_handle,
+ &time_rec);
+ if (req->keytab_principal != NULL)
+ k5_mutex_destroy(&name.lock);
+ return code;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred_from(OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_const_key_value_set_t cred_store,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ krb5_context context = NULL;
+ krb5_error_code code = 0;
+ krb5_keytab client_keytab = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_ccache ccache = NULL;
+ const char *rcname, *value;
+ OM_uint32 ret;
+
+ code = gss_krb5int_initialize_library();
+ if (code) {
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+ goto out;
+ }
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+ goto out;
+ }
+
+ ret = kg_value_from_cred_store(cred_store, KRB5_CS_CCACHE_URN, &value);
+ if (GSS_ERROR(ret))
+ goto out;
+
+ if (value) {
+ code = krb5_cc_resolve(context, value, &ccache);
+ if (code != 0) {
+ *minor_status = code;
+ ret = GSS_S_CRED_UNAVAIL;
+ goto out;
+ }
+ }
+
+ ret = kg_value_from_cred_store(cred_store, KRB5_CS_CLI_KEYTAB_URN, &value);
+ if (GSS_ERROR(ret))
+ goto out;
+
+ if (value) {
+ code = krb5_kt_resolve(context, value, &client_keytab);
+ if (code != 0) {
+ *minor_status = code;
+ ret = GSS_S_CRED_UNAVAIL;
+ goto out;
+ }
+ }
+
+ ret = kg_value_from_cred_store(cred_store, KRB5_CS_KEYTAB_URN, &value);
+ if (GSS_ERROR(ret))
+ goto out;
+
+ if (value) {
+ code = krb5_kt_resolve(context, value, &keytab);
+ if (code != 0) {
+ *minor_status = code;
+ ret = GSS_S_CRED_UNAVAIL;
+ goto out;
+ }
+ }
+
+ ret = kg_value_from_cred_store(cred_store, KRB5_CS_RCACHE_URN, &rcname);
+ if (GSS_ERROR(ret))
+ goto out;
+
+ ret = acquire_cred_context(context, minor_status, desired_name, NULL,
+ time_req, cred_usage, ccache, client_keytab,
+ keytab, rcname, 0, output_cred_handle,
+ time_rec);
+
+out:
+ if (ccache != NULL)
+ krb5_cc_close(context, ccache);
+ if (client_keytab != NULL)
+ krb5_kt_close(context, client_keytab);
+ if (keytab != NULL)
+ krb5_kt_close(context, keytab);
+ krb5_free_context(context);
+ return ret;
+}
diff --git a/src/lib/gssapi/krb5/canon_name.c b/src/lib/gssapi/krb5/canon_name.c
new file mode 100644
index 000000000000..81b08a534ec1
--- /dev/null
+++ b/src/lib/gssapi/krb5/canon_name.c
@@ -0,0 +1,44 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/canon_name.c */
+/*
+ * Copyright 1997 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "gssapiP_krb5.h"
+
+/* This is trivial since we're a single mechanism implementation */
+
+OM_uint32 krb5_gss_canonicalize_name(OM_uint32 *minor_status,
+ const gss_name_t input_name,
+ const gss_OID mech_type,
+ gss_name_t *output_name)
+{
+ if ((mech_type != GSS_C_NULL_OID) &&
+ !g_OID_equal(gss_mech_krb5, mech_type) &&
+ !g_OID_equal(gss_mech_krb5_old, mech_type)) {
+ *minor_status = 0;
+ return(GSS_S_BAD_MECH);
+ }
+
+ return(krb5_gss_duplicate_name(minor_status, input_name, output_name));
+}
diff --git a/src/lib/gssapi/krb5/compare_name.c b/src/lib/gssapi/krb5/compare_name.c
new file mode 100644
index 000000000000..3f3788d2bf1c
--- /dev/null
+++ b/src/lib/gssapi/krb5/compare_name.c
@@ -0,0 +1,52 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_compare_name(minor_status, name1, name2, name_equal)
+ OM_uint32 *minor_status;
+ gss_name_t name1;
+ gss_name_t name2;
+ int *name_equal;
+{
+ krb5_context context;
+ krb5_error_code code;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ *minor_status = 0;
+ *name_equal = kg_compare_name(context,
+ (krb5_gss_name_t)name1,
+ (krb5_gss_name_t)name2);
+ krb5_free_context(context);
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/context_time.c b/src/lib/gssapi/krb5/context_time.c
new file mode 100644
index 000000000000..a18cfb05b743
--- /dev/null
+++ b/src/lib/gssapi/krb5/context_time.c
@@ -0,0 +1,63 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_context_time(minor_status, context_handle, time_rec)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ OM_uint32 *time_rec;
+{
+ krb5_error_code code;
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_timestamp now;
+ krb5_deltat lifetime;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return(GSS_S_NO_CONTEXT);
+ }
+
+ if ((code = krb5_timeofday(ctx->k5_context, &now))) {
+ *minor_status = code;
+ save_error_info(*minor_status, ctx->k5_context);
+ return(GSS_S_FAILURE);
+ }
+
+ if ((lifetime = ctx->krb_times.endtime - now) <= 0) {
+ *time_rec = 0;
+ *minor_status = 0;
+ return(GSS_S_CONTEXT_EXPIRED);
+ } else {
+ *time_rec = lifetime;
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+ }
+}
diff --git a/src/lib/gssapi/krb5/copy_ccache.c b/src/lib/gssapi/krb5/copy_ccache.c
new file mode 100644
index 000000000000..f3d7666135cd
--- /dev/null
+++ b/src/lib/gssapi/krb5/copy_ccache.c
@@ -0,0 +1,60 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#include "gssapiP_krb5.h"
+
+OM_uint32
+gss_krb5int_copy_ccache(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ krb5_gss_cred_id_t k5creds;
+ krb5_cc_cursor cursor;
+ krb5_creds creds;
+ krb5_error_code code;
+ krb5_context context;
+ krb5_ccache out_ccache;
+
+ assert(value->length == sizeof(out_ccache));
+
+ if (value->length != sizeof(out_ccache))
+ return GSS_S_FAILURE;
+
+ out_ccache = (krb5_ccache)value->value;
+
+ /* cred handle will have been validated by gssspi_set_cred_option() */
+ k5creds = (krb5_gss_cred_id_t) *cred_handle;
+ k5_mutex_lock(&k5creds->lock);
+ if (k5creds->usage == GSS_C_ACCEPT) {
+ k5_mutex_unlock(&k5creds->lock);
+ *minor_status = (OM_uint32) G_BAD_USAGE;
+ return(GSS_S_FAILURE);
+ }
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ k5_mutex_unlock(&k5creds->lock);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ code = krb5_cc_start_seq_get(context, k5creds->ccache, &cursor);
+ if (code) {
+ k5_mutex_unlock(&k5creds->lock);
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return(GSS_S_FAILURE);
+ }
+ while (!code && !krb5_cc_next_cred(context, k5creds->ccache, &cursor,
+ &creds)) {
+ code = krb5_cc_store_cred(context, out_ccache, &creds);
+ krb5_free_cred_contents(context, &creds);
+ }
+ krb5_cc_end_seq_get(context, k5creds->ccache, &cursor);
+ k5_mutex_unlock(&k5creds->lock);
+ *minor_status = code;
+ if (code)
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return code ? GSS_S_FAILURE : GSS_S_COMPLETE;
+}
diff --git a/src/lib/gssapi/krb5/cred_store.c b/src/lib/gssapi/krb5/cred_store.c
new file mode 100644
index 000000000000..008dd208bf0c
--- /dev/null
+++ b/src/lib/gssapi/krb5/cred_store.c
@@ -0,0 +1,50 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32
+kg_value_from_cred_store(gss_const_key_value_set_t cred_store,
+ const char *type, const char **value)
+{
+ OM_uint32 i;
+
+ if (value == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+ *value = NULL;
+
+ if (cred_store == GSS_C_NO_CRED_STORE)
+ return GSS_S_COMPLETE;
+
+ for (i = 0; i < cred_store->count; i++) {
+ if (strcmp(cred_store->elements[i].key, type) == 0) {
+ if (*value != NULL)
+ return GSS_S_DUPLICATE_ELEMENT;
+ *value = cred_store->elements[i].value;
+ }
+ }
+
+ return GSS_S_COMPLETE;
+}
diff --git a/src/lib/gssapi/krb5/delete_sec_context.c b/src/lib/gssapi/krb5/delete_sec_context.c
new file mode 100644
index 000000000000..4b9dfae0d515
--- /dev/null
+++ b/src/lib/gssapi/krb5/delete_sec_context.c
@@ -0,0 +1,99 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_delete_sec_context(minor_status, context_handle, output_token)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t *context_handle;
+ gss_buffer_t output_token;
+{
+ krb5_context context;
+ krb5_gss_ctx_id_rec *ctx;
+
+ if (output_token) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+
+ /*SUPPRESS 29*/
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+ }
+
+ ctx = (krb5_gss_ctx_id_t) *context_handle;
+ context = ctx->k5_context;
+
+ /* free all the context state */
+
+ if (ctx->seqstate)
+ g_seqstate_free(ctx->seqstate);
+
+ if (ctx->enc)
+ krb5_k_free_key(context, ctx->enc);
+
+ if (ctx->seq)
+ krb5_k_free_key(context, ctx->seq);
+
+ if (ctx->here)
+ kg_release_name(context, &ctx->here);
+ if (ctx->there)
+ kg_release_name(context, &ctx->there);
+ if (ctx->subkey)
+ krb5_k_free_key(context, ctx->subkey);
+ if (ctx->acceptor_subkey)
+ krb5_k_free_key(context, ctx->acceptor_subkey);
+
+ if (ctx->auth_context) {
+ if (ctx->cred_rcache)
+ (void)krb5_auth_con_setrcache(context, ctx->auth_context, NULL);
+
+ krb5_auth_con_free(context, ctx->auth_context);
+ }
+
+ if (ctx->mech_used)
+ krb5_gss_release_oid(minor_status, &ctx->mech_used);
+
+ if (ctx->authdata)
+ krb5_free_authdata(context, ctx->authdata);
+
+ if (ctx->k5_context)
+ krb5_free_context(ctx->k5_context);
+
+ /* Zero out context */
+ zap(ctx, sizeof(*ctx));
+ xfree(ctx);
+
+ /* zero the handle itself */
+
+ *context_handle = GSS_C_NO_CONTEXT;
+
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/deps b/src/lib/gssapi/krb5/deps
new file mode 100644
index 000000000000..f42f40ae7727
--- /dev/null
+++ b/src/lib/gssapi/krb5/deps
@@ -0,0 +1,756 @@
+#
+# Generated makefile dependencies follow.
+#
+accept_sec_context.so accept_sec_context.po $(OUTPRE)accept_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h accept_sec_context.c \
+ gssapiP_krb5.h gssapi_err_krb5.h gssapi_krb5.h
+acquire_cred.so acquire_cred.po $(OUTPRE)acquire_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h acquire_cred.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+canon_name.so canon_name.po $(OUTPRE)canon_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h canon_name.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+compare_name.so compare_name.po $(OUTPRE)compare_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h compare_name.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+context_time.so context_time.po $(OUTPRE)context_time.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h context_time.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+copy_ccache.so copy_ccache.po $(OUTPRE)copy_ccache.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h copy_ccache.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+cred_store.so cred_store.po $(OUTPRE)cred_store.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h cred_store.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+delete_sec_context.so delete_sec_context.po $(OUTPRE)delete_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h delete_sec_context.c \
+ gssapiP_krb5.h gssapi_err_krb5.h gssapi_krb5.h
+disp_name.so disp_name.po $(OUTPRE)disp_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h disp_name.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+disp_status.so disp_status.po $(OUTPRE)disp_status.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h disp_status.c error_map.h \
+ gssapiP_krb5.h gssapi_err_krb5.h gssapi_krb5.h
+duplicate_name.so duplicate_name.po $(OUTPRE)duplicate_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h duplicate_name.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+export_cred.so export_cred.po $(OUTPRE)export_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-json.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
+ $(top_srcdir)/include/socket-utils.h ../generic/gssapi_err_generic.h \
+ export_cred.c gssapiP_krb5.h gssapi_err_krb5.h gssapi_krb5.h
+export_name.so export_name.po $(OUTPRE)export_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h export_name.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+export_sec_context.so export_sec_context.po $(OUTPRE)export_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h export_sec_context.c \
+ gssapiP_krb5.h gssapi_err_krb5.h gssapi_krb5.h
+get_tkt_flags.so get_tkt_flags.po $(OUTPRE)get_tkt_flags.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h get_tkt_flags.c gssapiP_krb5.h \
+ gssapi_err_krb5.h gssapi_krb5.h
+gssapi_krb5.so gssapi_krb5.po $(OUTPRE)gssapi_krb5.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(srcdir)/../mechglue/mechglue.h $(srcdir)/../mechglue/mglueP.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.c gssapi_krb5.h
+iakerb.so iakerb.po $(OUTPRE)iakerb.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h iakerb.c
+import_cred.so import_cred.po $(OUTPRE)import_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-json.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
+ $(top_srcdir)/include/socket-utils.h ../generic/gssapi_err_generic.h \
+ gssapiP_krb5.h gssapi_err_krb5.h gssapi_krb5.h import_cred.c
+import_name.so import_name.po $(OUTPRE)import_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h import_name.c
+import_sec_context.so import_sec_context.po $(OUTPRE)import_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h import_sec_context.c
+indicate_mechs.so indicate_mechs.po $(OUTPRE)indicate_mechs.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(srcdir)/../mechglue/mechglue.h $(srcdir)/../mechglue/mglueP.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h indicate_mechs.c
+init_sec_context.so init_sec_context.po $(OUTPRE)init_sec_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h init_sec_context.c
+inq_context.so inq_context.po $(OUTPRE)inq_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h inq_context.c
+inq_cred.so inq_cred.po $(OUTPRE)inq_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h inq_cred.c
+inq_names.so inq_names.po $(OUTPRE)inq_names.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h inq_names.c
+k5seal.so k5seal.po $(OUTPRE)k5seal.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h k5seal.c
+k5sealiov.so k5sealiov.po $(OUTPRE)k5sealiov.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h k5sealiov.c
+k5sealv3.so k5sealv3.po $(OUTPRE)k5sealv3.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h k5sealv3.c
+k5sealv3iov.so k5sealv3iov.po $(OUTPRE)k5sealv3iov.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h k5sealv3iov.c
+k5unseal.so k5unseal.po $(OUTPRE)k5unseal.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h k5unseal.c
+k5unsealiov.so k5unsealiov.po $(OUTPRE)k5unsealiov.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h k5unsealiov.c
+krb5_gss_glue.so krb5_gss_glue.po $(OUTPRE)krb5_gss_glue.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h krb5_gss_glue.c
+lucid_context.so lucid_context.po $(OUTPRE)lucid_context.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h lucid_context.c
+naming_exts.so naming_exts.po $(OUTPRE)naming_exts.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h naming_exts.c
+prf.so prf.po $(OUTPRE)prf.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h prf.c
+process_context_token.so process_context_token.po $(OUTPRE)process_context_token.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h process_context_token.c
+rel_cred.so rel_cred.po $(OUTPRE)rel_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h rel_cred.c
+rel_oid.so rel_oid.po $(OUTPRE)rel_oid.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h rel_oid.c
+rel_name.so rel_name.po $(OUTPRE)rel_name.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h rel_name.c
+s4u_gss_glue.so s4u_gss_glue.po $(OUTPRE)s4u_gss_glue.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h s4u_gss_glue.c
+set_allowable_enctypes.so set_allowable_enctypes.po \
+ $(OUTPRE)set_allowable_enctypes.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h set_allowable_enctypes.c
+ser_sctx.so ser_sctx.po $(OUTPRE)ser_sctx.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h ser_sctx.c
+set_ccache.so set_ccache.po $(OUTPRE)set_ccache.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h set_ccache.c
+store_cred.so store_cred.po $(OUTPRE)store_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h store_cred.c
+util_cksum.so util_cksum.po $(OUTPRE)util_cksum.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h util_cksum.c
+util_crypt.so util_crypt.po $(OUTPRE)util_crypt.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h util_crypt.c
+util_seed.so util_seed.po $(OUTPRE)util_seed.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h util_seed.c
+util_seqnum.so util_seqnum.po $(OUTPRE)util_seqnum.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h util_seqnum.c
+val_cred.so val_cred.po $(OUTPRE)val_cred.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h val_cred.c
+wrap_size_limit.so wrap_size_limit.po $(OUTPRE)wrap_size_limit.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_alloc.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../generic/gssapiP_generic.h \
+ $(srcdir)/../generic/gssapi_ext.h $(srcdir)/../generic/gssapi_generic.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ ../generic/gssapi_err_generic.h gssapiP_krb5.h gssapi_err_krb5.h \
+ gssapi_krb5.h wrap_size_limit.c
diff --git a/src/lib/gssapi/krb5/disp_name.c b/src/lib/gssapi/krb5/disp_name.c
new file mode 100644
index 000000000000..b097bf0e2181
--- /dev/null
+++ b/src/lib/gssapi/krb5/disp_name.c
@@ -0,0 +1,81 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_display_name(minor_status, input_name, output_name_buffer,
+ output_name_type)
+ OM_uint32 *minor_status;
+ gss_name_t input_name;
+ gss_buffer_t output_name_buffer;
+ gss_OID *output_name_type;
+{
+ krb5_context context;
+ krb5_error_code code;
+ char *str;
+ krb5_gss_name_t k5name = (krb5_gss_name_t) input_name;
+ gss_OID nametype = (gss_OID) gss_nt_krb5_name;
+
+ output_name_buffer->length = 0;
+ output_name_buffer->value = NULL;
+ if (output_name_type)
+ *output_name_type = GSS_C_NO_OID;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (krb5_princ_type(context, k5name->princ) == KRB5_NT_WELLKNOWN) {
+ if (krb5_principal_compare(context, k5name->princ,
+ krb5_anonymous_principal()))
+ nametype = GSS_C_NT_ANONYMOUS;
+ }
+
+ if ((code = krb5_unparse_name(context,
+ ((krb5_gss_name_t) input_name)->princ,
+ &str))) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return(GSS_S_FAILURE);
+ }
+
+ if (! g_make_string_buffer(str, output_name_buffer)) {
+ krb5_free_unparsed_name(context, str);
+ krb5_free_context(context);
+
+ *minor_status = (OM_uint32) G_BUFFER_ALLOC;
+ return(GSS_S_FAILURE);
+ }
+
+ krb5_free_unparsed_name(context, str);
+ krb5_free_context(context);
+
+ *minor_status = 0;
+ if (output_name_type)
+ *output_name_type = (gss_OID) nametype;
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/disp_status.c b/src/lib/gssapi/krb5/disp_status.c
new file mode 100644
index 000000000000..6ff62a9d8415
--- /dev/null
+++ b/src/lib/gssapi/krb5/disp_status.c
@@ -0,0 +1,200 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+#include "com_err.h"
+
+/* XXXX internationalization!! */
+
+static inline int
+compare_OM_uint32 (OM_uint32 a, OM_uint32 b)
+{
+ if (a < b)
+ return -1;
+ else if (a == b)
+ return 0;
+ else
+ return 1;
+}
+static inline void
+free_string (char *s)
+{
+ free(s);
+}
+#include "error_map.h"
+#include <stdio.h>
+char *get_error_message(OM_uint32 minor_code)
+{
+ gsserrmap *p = k5_getspecific(K5_KEY_GSS_KRB5_ERROR_MESSAGE);
+ char *msg = NULL;
+#ifdef DEBUG
+ fprintf(stderr, "%s(%lu, p=%p)", __FUNCTION__, (unsigned long) minor_code,
+ (void *) p);
+#endif
+ if (p) {
+ char **v = gsserrmap_find(p, minor_code);
+ if (v) {
+ msg = *v;
+#ifdef DEBUG
+ fprintf(stderr, " FOUND!");
+#endif
+ }
+ }
+ if (msg == 0)
+ msg = (char *)error_message((krb5_error_code)minor_code);
+#ifdef DEBUG
+ fprintf(stderr, " -> %p/%s\n", (void *) msg, msg);
+#endif
+ return msg;
+}
+#define save_error_string_nocopy gss_krb5_save_error_string_nocopy
+static int save_error_string_nocopy(OM_uint32 minor_code, char *msg)
+{
+ gsserrmap *p;
+ int ret;
+
+#ifdef DEBUG
+ fprintf(stderr, "%s(%lu, %s)", __FUNCTION__, (unsigned long) minor_code, msg);
+#endif
+ p = k5_getspecific(K5_KEY_GSS_KRB5_ERROR_MESSAGE);
+ if (!p) {
+ p = malloc(sizeof(*p));
+ if (p == NULL) {
+ ret = 1;
+ goto fail;
+ }
+ if (gsserrmap_init(p) != 0) {
+ free(p);
+ p = NULL;
+ ret = 1;
+ goto fail;
+ }
+ if (k5_setspecific(K5_KEY_GSS_KRB5_ERROR_MESSAGE, p) != 0) {
+ gsserrmap_destroy(p);
+ free(p);
+ p = NULL;
+ ret = 1;
+ goto fail;
+ }
+ }
+ ret = gsserrmap_replace_or_insert(p, minor_code, msg);
+fail:
+#ifdef DEBUG
+ fprintf(stderr, " p=%p %s\n", (void *)p, ret ? "FAIL" : "SUCCESS");
+#endif
+ return ret;
+}
+void save_error_string(OM_uint32 minor_code, char *msg)
+{
+ char *s = strdup(msg);
+ if (s) {
+ if (save_error_string_nocopy(minor_code, s) != 0)
+ free(s);
+ }
+}
+void save_error_message(OM_uint32 minor_code, const char *format, ...)
+{
+ char *s;
+ int n;
+ va_list ap;
+
+ va_start(ap, format);
+ n = vasprintf(&s, format, ap);
+ va_end(ap);
+ if (n >= 0) {
+ if (save_error_string_nocopy(minor_code, s) != 0)
+ free(s);
+ }
+}
+void krb5_gss_save_error_info(OM_uint32 minor_code, krb5_context ctx)
+{
+ char *s;
+
+#ifdef DEBUG
+ fprintf(stderr, "%s(%lu, ctx=%p)\n", __FUNCTION__,
+ (unsigned long) minor_code, (void *)ctx);
+#endif
+ s = (char *)krb5_get_error_message(ctx, (krb5_error_code)minor_code);
+#ifdef DEBUG
+ fprintf(stderr, "%s(%lu, ctx=%p) saving: %s\n", __FUNCTION__,
+ (unsigned long) minor_code, (void *)ctx, s);
+#endif
+ save_error_string(minor_code, s);
+ /* The get_error_message call above resets the error message in
+ ctx. Put it back, in case we make this call again *sigh*. */
+ k5_setmsg(ctx, (krb5_error_code)minor_code, "%s", s);
+ krb5_free_error_message(ctx, s);
+}
+void krb5_gss_delete_error_info(void *p)
+{
+ gsserrmap_destroy(p);
+ free(p);
+}
+
+/**/
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_display_status(minor_status, status_value, status_type,
+ mech_type, message_context, status_string)
+ OM_uint32 *minor_status;
+ OM_uint32 status_value;
+ int status_type;
+ gss_OID mech_type;
+ OM_uint32 *message_context;
+ gss_buffer_t status_string;
+{
+ status_string->length = 0;
+ status_string->value = NULL;
+
+ if ((mech_type != GSS_C_NULL_OID) &&
+ !g_OID_equal(gss_mech_krb5, mech_type) &&
+ !g_OID_equal(gss_mech_krb5_old, mech_type) &&
+ !g_OID_equal(gss_mech_iakerb, mech_type)) {
+ *minor_status = 0;
+ return(GSS_S_BAD_MECH);
+ }
+
+ if (status_type == GSS_C_GSS_CODE) {
+ return(g_display_major_status(minor_status, status_value,
+ message_context, status_string));
+ } else if (status_type == GSS_C_MECH_CODE) {
+ (void) gss_krb5int_initialize_library();
+
+ if (*message_context) {
+ *minor_status = (OM_uint32) G_BAD_MSG_CTX;
+ return(GSS_S_FAILURE);
+ }
+
+ /* If this fails, there's not much we can do... */
+ if (!g_make_string_buffer(krb5_gss_get_error_message(status_value),
+ status_string)) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+ } else {
+ *minor_status = 0;
+ return(GSS_S_BAD_STATUS);
+ }
+}
diff --git a/src/lib/gssapi/krb5/duplicate_name.c b/src/lib/gssapi/krb5/duplicate_name.c
new file mode 100644
index 000000000000..b88d97d9d617
--- /dev/null
+++ b/src/lib/gssapi/krb5/duplicate_name.c
@@ -0,0 +1,59 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/duplicate_name.c */
+/*
+ * Copyright 1997,2007 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_duplicate_name(OM_uint32 *minor_status, const gss_name_t input_name,
+ gss_name_t *dest_name)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t princ, outprinc;
+
+ if (minor_status)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ if (minor_status)
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ princ = (krb5_gss_name_t)input_name;
+ code = kg_duplicate_name(context, princ, &outprinc);
+ if (code) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return(GSS_S_FAILURE);
+ }
+ krb5_free_context(context);
+ *dest_name = (gss_name_t) outprinc;
+ return(GSS_S_COMPLETE);
+
+}
diff --git a/src/lib/gssapi/krb5/export_cred.c b/src/lib/gssapi/krb5/export_cred.c
new file mode 100644
index 000000000000..652b2604bda3
--- /dev/null
+++ b/src/lib/gssapi/krb5/export_cred.c
@@ -0,0 +1,481 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/export_cred.c - krb5 export_cred implementation */
+/*
+ * Copyright (C) 2012 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#include "k5-json.h"
+#include "gssapiP_krb5.h"
+
+/* Return a JSON null or array value representing princ. */
+static krb5_error_code
+json_principal(krb5_context context, krb5_principal princ,
+ k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_string str = NULL;
+ char *princname;
+
+ *val_out = NULL;
+ if (princ == NULL)
+ return k5_json_null_create_val(val_out);
+ ret = krb5_unparse_name(context, princ, &princname);
+ if (ret)
+ return ret;
+ ret = k5_json_string_create(princname, &str);
+ krb5_free_unparsed_name(context, princname);
+ *val_out = str;
+ return ret;
+}
+
+/* Return a json null or array value representing etypes. */
+static krb5_error_code
+json_etypes(krb5_enctype *etypes, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_number num;
+ k5_json_array array;
+
+ *val_out = NULL;
+ if (etypes == NULL)
+ return k5_json_null_create_val(val_out);
+ ret = k5_json_array_create(&array);
+ if (ret)
+ return ret;
+ for (; *etypes != 0; etypes++) {
+ ret = k5_json_number_create(*etypes, &num);
+ if (ret)
+ goto err;
+ ret = k5_json_array_add(array, num);
+ k5_json_release(num);
+ if (ret)
+ goto err;
+ }
+ *val_out = array;
+ return 0;
+err:
+ k5_json_release(array);
+ return ret;
+}
+
+/* Return a JSON null or array value representing name. */
+static krb5_error_code
+json_kgname(krb5_context context, krb5_gss_name_t name, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array = NULL;
+ k5_json_value princ;
+
+ *val_out = NULL;
+ if (name == NULL)
+ return k5_json_null_create_val(val_out);
+ ret = json_principal(context, name->princ, &princ);
+ if (ret)
+ return ret;
+ ret = k5_json_array_fmt(&array, "vss", princ, name->service, name->host);
+ k5_json_release(princ);
+ *val_out = array;
+ return ret;
+}
+
+/* Return a JSON null or string value representing keytab. */
+static krb5_error_code
+json_keytab(krb5_context context, krb5_keytab keytab, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_string str;
+ char name[1024];
+
+ *val_out = NULL;
+ if (keytab == NULL)
+ return k5_json_null_create_val(val_out);
+ ret = krb5_kt_get_name(context, keytab, name, sizeof(name));
+ if (ret)
+ return ret;
+ ret = k5_json_string_create(name, &str);
+ *val_out = str;
+ return ret;
+}
+
+/* Return a JSON null or string value representing rcache. */
+static krb5_error_code
+json_rcache(krb5_context context, krb5_rcache rcache, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_string str = NULL;
+ char *name;
+
+ if (rcache == NULL)
+ return k5_json_null_create_val(val_out);
+ if (asprintf(&name, "%s:%s", krb5_rc_get_type(context, rcache),
+ krb5_rc_get_name(context, rcache)) < 0)
+ return ENOMEM;
+ ret = k5_json_string_create(name, &str);
+ free(name);
+ *val_out = str;
+ return ret;
+}
+
+/* Return a JSON array value representing keyblock. */
+static krb5_error_code
+json_keyblock(krb5_keyblock *kb, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+
+ *val_out = NULL;
+ ret = k5_json_array_fmt(&array, "iB", kb->enctype, (void *)kb->contents,
+ (size_t)kb->length);
+ if (ret)
+ return ret;
+ *val_out = array;
+ return 0;
+}
+
+/* Return a JSON array value representing addr. */
+static krb5_error_code
+json_address(krb5_address *addr, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+
+ *val_out = NULL;
+ ret = k5_json_array_fmt(&array, "iB", addr->addrtype,
+ (void *)addr->contents, (size_t)addr->length);
+ if (ret)
+ return ret;
+ *val_out = array;
+ return 0;
+}
+
+/* Return a JSON null or array value representing addrs. */
+static krb5_error_code
+json_addresses(krb5_address **addrs, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+ k5_json_value val;
+
+ *val_out = NULL;
+ if (addrs == NULL)
+ return k5_json_null_create_val(val_out);
+ ret = k5_json_array_create(&array);
+ if (ret)
+ return ret;
+ for (; *addrs != NULL; addrs++) {
+ ret = json_address(*addrs, &val);
+ if (ret)
+ goto err;
+ ret = k5_json_array_add(array, val);
+ k5_json_release(val);
+ if (ret)
+ goto err;
+ }
+ *val_out = array;
+ return 0;
+err:
+ k5_json_release(array);
+ return ret;
+}
+
+/* Return a JSON array value representing ad. */
+static krb5_error_code
+json_authdata_element(krb5_authdata *ad, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+
+ *val_out = NULL;
+ ret = k5_json_array_fmt(&array, "iB", ad->ad_type, (void *)ad->contents,
+ (size_t)ad->length);
+ if (ret)
+ return ret;
+ *val_out = array;
+ return 0;
+}
+
+/* Return a JSON null or array value representing authdata. */
+static krb5_error_code
+json_authdata(krb5_authdata **authdata, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+ k5_json_value val;
+
+ *val_out = NULL;
+ if (authdata == NULL)
+ return k5_json_null_create_val(val_out);
+ ret = k5_json_array_create(&array);
+ if (ret)
+ return ret;
+ for (; *authdata != NULL; authdata++) {
+ ret = json_authdata_element(*authdata, &val);
+ if (ret)
+ goto err;
+ ret = k5_json_array_add(array, val);
+ k5_json_release(val);
+ if (ret)
+ goto err;
+ }
+ *val_out = array;
+ return 0;
+err:
+ k5_json_release(array);
+ return ret;
+}
+
+/* Return a JSON array value representing creds. */
+static krb5_error_code
+json_creds(krb5_context context, krb5_creds *creds, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+ k5_json_value client = NULL, server = NULL, keyblock = NULL, addrs = NULL;
+ k5_json_value authdata = NULL;
+
+ *val_out = NULL;
+ ret = json_principal(context, creds->client, &client);
+ if (ret)
+ goto cleanup;
+ ret = json_principal(context, creds->server, &server);
+ if (ret)
+ goto cleanup;
+ ret = json_keyblock(&creds->keyblock, &keyblock);
+ if (ret)
+ goto cleanup;
+ ret = json_addresses(creds->addresses, &addrs);
+ if (ret)
+ goto cleanup;
+ ret = json_authdata(creds->authdata, &authdata);
+ if (ret)
+ goto cleanup;
+
+ ret = k5_json_array_fmt(&array, "vvviiiibivBBv", client, server, keyblock,
+ creds->times.authtime, creds->times.starttime,
+ creds->times.endtime, creds->times.renew_till,
+ creds->is_skey, creds->ticket_flags, addrs,
+ (void *)creds->ticket.data,
+ (size_t)creds->ticket.length,
+ (void *)creds->second_ticket.data,
+ (size_t)creds->second_ticket.length, authdata);
+ if (ret)
+ goto cleanup;
+ *val_out = array;
+
+cleanup:
+ k5_json_release(client);
+ k5_json_release(server);
+ k5_json_release(keyblock);
+ k5_json_release(addrs);
+ k5_json_release(authdata);
+ return ret;
+}
+
+/* Return a JSON array value representing the contents of ccache. */
+static krb5_error_code
+json_ccache_contents(krb5_context context, krb5_ccache ccache,
+ k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ krb5_principal princ;
+ krb5_cc_cursor cursor;
+ krb5_creds creds;
+ k5_json_array array;
+ k5_json_value val;
+
+ *val_out = NULL;
+ ret = k5_json_array_create(&array);
+ if (ret)
+ return ret;
+
+ /* Put the principal in the first array entry. */
+ ret = krb5_cc_get_principal(context, ccache, &princ);
+ if (ret)
+ goto err;
+ ret = json_principal(context, princ, &val);
+ krb5_free_principal(context, princ);
+ if (ret)
+ goto err;
+ ret = k5_json_array_add(array, val);
+ k5_json_release(val);
+ if (ret)
+ goto err;
+
+ /* Put credentials in the remaining array entries. */
+ ret = krb5_cc_start_seq_get(context, ccache, &cursor);
+ if (ret)
+ goto err;
+ while ((ret = krb5_cc_next_cred(context, ccache, &cursor, &creds)) == 0) {
+ ret = json_creds(context, &creds, &val);
+ krb5_free_cred_contents(context, &creds);
+ if (ret)
+ break;
+ ret = k5_json_array_add(array, val);
+ k5_json_release(val);
+ if (ret)
+ break;
+ }
+ krb5_cc_end_seq_get(context, ccache, &cursor);
+ if (ret != KRB5_CC_END)
+ goto err;
+ *val_out = array;
+ return 0;
+
+err:
+ k5_json_release(array);
+ return ret;
+}
+
+/* Return a JSON null, string, or array value representing ccache. */
+static krb5_error_code
+json_ccache(krb5_context context, krb5_ccache ccache, k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_string str;
+ char *name;
+
+ *val_out = NULL;
+ if (ccache == NULL)
+ return k5_json_null_create_val(val_out);
+ if (strcmp(krb5_cc_get_type(context, ccache), "MEMORY") == 0) {
+ return json_ccache_contents(context, ccache, val_out);
+ } else {
+ ret = krb5_cc_get_full_name(context, ccache, &name);
+ if (ret)
+ return ret;
+ ret = k5_json_string_create(name, &str);
+ free(name);
+ *val_out = str;
+ return ret;
+ }
+}
+
+/* Return a JSON array value representing cred. */
+static krb5_error_code
+json_kgcred(krb5_context context, krb5_gss_cred_id_t cred,
+ k5_json_value *val_out)
+{
+ krb5_error_code ret;
+ k5_json_array array;
+ k5_json_value name = NULL, imp = NULL, keytab = NULL, rcache = NULL;
+ k5_json_value ccache = NULL, ckeytab = NULL, etypes = NULL;
+
+ *val_out = NULL;
+ ret = json_kgname(context, cred->name, &name);
+ if (ret)
+ goto cleanup;
+ ret = json_principal(context, cred->impersonator, &imp);
+ if (ret)
+ goto cleanup;
+ ret = json_keytab(context, cred->keytab, &keytab);
+ if (ret)
+ goto cleanup;
+ ret = json_rcache(context, cred->rcache, &rcache);
+ if (ret)
+ goto cleanup;
+ ret = json_ccache(context, cred->ccache, &ccache);
+ if (ret)
+ goto cleanup;
+ ret = json_keytab(context, cred->client_keytab, &ckeytab);
+ if (ret)
+ goto cleanup;
+ ret = json_etypes(cred->req_enctypes, &etypes);
+ if (ret)
+ goto cleanup;
+
+ ret = k5_json_array_fmt(&array, "ivvbbvvvvbiivs", cred->usage, name, imp,
+ cred->default_identity, cred->iakerb_mech, keytab,
+ rcache, ccache, ckeytab, cred->have_tgt,
+ cred->expire, cred->refresh_time, etypes,
+ cred->password);
+ if (ret)
+ goto cleanup;
+ *val_out = array;
+
+cleanup:
+ k5_json_release(name);
+ k5_json_release(imp);
+ k5_json_release(keytab);
+ k5_json_release(rcache);
+ k5_json_release(ccache);
+ k5_json_release(ckeytab);
+ k5_json_release(etypes);
+ return ret;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_export_cred(OM_uint32 *minor_status, gss_cred_id_t cred_handle,
+ gss_buffer_t token)
+{
+ OM_uint32 status = GSS_S_COMPLETE;
+ krb5_context context;
+ krb5_error_code ret;
+ krb5_gss_cred_id_t cred;
+ k5_json_array array = NULL;
+ k5_json_value jcred = NULL;
+ char *str = NULL;
+ krb5_data d;
+
+ ret = krb5_gss_init_context(&context);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ /* Validate and lock cred_handle. */
+ status = krb5_gss_validate_cred_1(minor_status, cred_handle, context);
+ if (status != GSS_S_COMPLETE)
+ return status;
+ cred = (krb5_gss_cred_id_t)cred_handle;
+
+ if (json_kgcred(context, cred, &jcred))
+ goto oom;
+ if (k5_json_array_fmt(&array, "sv", CRED_EXPORT_MAGIC, jcred))
+ goto oom;
+ if (k5_json_encode(array, &str))
+ goto oom;
+ d = string2data(str);
+ if (data_to_gss(&d, token))
+ goto oom;
+ str = NULL;
+
+cleanup:
+ free(str);
+ k5_mutex_unlock(&cred->lock);
+ k5_json_release(array);
+ k5_json_release(jcred);
+ krb5_free_context(context);
+ return status;
+
+oom:
+ *minor_status = ENOMEM;
+ status = GSS_S_FAILURE;
+ goto cleanup;
+}
diff --git a/src/lib/gssapi/krb5/export_name.c b/src/lib/gssapi/krb5/export_name.c
new file mode 100644
index 000000000000..485ebfb6cdf3
--- /dev/null
+++ b/src/lib/gssapi/krb5/export_name.c
@@ -0,0 +1,88 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/export_name.c */
+/*
+ * Copyright 1997, 2007 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_export_name(OM_uint32 *minor_status, const gss_name_t input_name,
+ gss_buffer_t exported_name)
+{
+ krb5_context context;
+ krb5_error_code code;
+ size_t length;
+ char *str;
+ unsigned char *cp;
+
+ if (minor_status)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ if (minor_status)
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ exported_name->length = 0;
+ exported_name->value = NULL;
+
+ if ((code = krb5_unparse_name(context, ((krb5_gss_name_t) input_name)->princ,
+ &str))) {
+ if (minor_status)
+ *minor_status = code;
+ save_error_info((OM_uint32)code, context);
+ krb5_free_context(context);
+ return(GSS_S_FAILURE);
+ }
+
+ krb5_free_context(context);
+ length = strlen(str);
+ exported_name->length = 10 + length + gss_mech_krb5->length;
+ exported_name->value = gssalloc_malloc(exported_name->length);
+ if (!exported_name->value) {
+ free(str);
+ if (minor_status)
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ cp = exported_name->value;
+
+ /* Note: we assume the OID will be less than 128 bytes... */
+ *cp++ = 0x04; *cp++ = 0x01;
+ store_16_be(gss_mech_krb5->length+2, cp);
+ cp += 2;
+ *cp++ = 0x06;
+ *cp++ = (gss_mech_krb5->length) & 0xFF;
+ memcpy(cp, gss_mech_krb5->elements, gss_mech_krb5->length);
+ cp += gss_mech_krb5->length;
+ store_32_be(length, cp);
+ cp += 4;
+ memcpy(cp, str, length);
+
+ free(str);
+
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/export_sec_context.c b/src/lib/gssapi/krb5/export_sec_context.c
new file mode 100644
index 000000000000..49bd76d2bc21
--- /dev/null
+++ b/src/lib/gssapi/krb5/export_sec_context.c
@@ -0,0 +1,101 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/export_sec_context.c - Externalize a security context */
+/*
+ * Copyright 1995, 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "gssapiP_krb5.h"
+#ifndef LEAN_CLIENT
+OM_uint32 KRB5_CALLCONV
+krb5_gss_export_sec_context(minor_status, context_handle, interprocess_token)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t *context_handle;
+ gss_buffer_t interprocess_token;
+{
+ krb5_context context = NULL;
+ krb5_error_code kret;
+ OM_uint32 retval;
+ size_t bufsize, blen;
+ krb5_gss_ctx_id_t ctx;
+ krb5_octet *obuffer, *obp;
+
+ /* Assume a tragic failure */
+ obuffer = (krb5_octet *) NULL;
+ retval = GSS_S_FAILURE;
+ *minor_status = 0;
+
+ ctx = (krb5_gss_ctx_id_t) *context_handle;
+ if (ctx->terminated) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return (GSS_S_NO_CONTEXT);
+ }
+
+ context = ctx->k5_context;
+ kret = krb5_gss_ser_init(context);
+ if (kret)
+ goto error_out;
+
+ /* Determine size needed for externalization of context */
+ bufsize = 0;
+ if ((kret = kg_ctx_size(context, (krb5_pointer) ctx,
+ &bufsize)))
+ goto error_out;
+
+ /* Allocate the buffer */
+ if ((obuffer = gssalloc_malloc(bufsize)) == NULL) {
+ kret = ENOMEM;
+ goto error_out;
+ }
+
+ obp = obuffer;
+ blen = bufsize;
+ /* Externalize the context */
+ if ((kret = kg_ctx_externalize(context,
+ (krb5_pointer) ctx, &obp, &blen)))
+ goto error_out;
+
+ /* Success! Return the buffer */
+ interprocess_token->length = bufsize - blen;
+ interprocess_token->value = obuffer;
+ *minor_status = 0;
+ retval = GSS_S_COMPLETE;
+
+ /* Now, clean up the context state */
+ (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
+ *context_handle = GSS_C_NO_CONTEXT;
+
+ return (GSS_S_COMPLETE);
+
+error_out:
+ if (retval != GSS_S_COMPLETE)
+ if (kret != 0 && context != 0)
+ save_error_info((OM_uint32)kret, context);
+ if (obuffer && bufsize) {
+ zap(obuffer, bufsize);
+ xfree(obuffer);
+ }
+ if (*minor_status == 0)
+ *minor_status = (OM_uint32) kret;
+ return(retval);
+}
+#endif /* LEAN_CLIENT */
diff --git a/src/lib/gssapi/krb5/get_tkt_flags.c b/src/lib/gssapi/krb5/get_tkt_flags.c
new file mode 100644
index 000000000000..636fc04db44c
--- /dev/null
+++ b/src/lib/gssapi/krb5/get_tkt_flags.c
@@ -0,0 +1,45 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32
+gss_krb5int_get_tkt_flags(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ gss_buffer_desc rep;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ rep.value = &ctx->krb_flags;
+ rep.length = sizeof(ctx->krb_flags);
+
+ return generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
+}
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
new file mode 100644
index 000000000000..d7bdef7e28a3
--- /dev/null
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -0,0 +1,1428 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2000, 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _GSSAPIP_KRB5_H_
+#define _GSSAPIP_KRB5_H_
+
+#include <k5-int.h>
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+/* work around sunos braindamage */
+#ifdef major
+#undef major
+#endif
+#ifdef minor
+#undef minor
+#endif
+
+#include "gssapiP_generic.h"
+
+/* The include of gssapi_krb5.h will dtrt with the above #defines in
+ * effect.
+ */
+#include "gssapi_krb5.h"
+#include "gssapi_err_krb5.h"
+#include "gssapi_ext.h"
+
+/* for debugging */
+#undef CFX_EXERCISE
+
+/** constants **/
+
+#define GSS_MECH_KRB5_OID_LENGTH 9
+#define GSS_MECH_KRB5_OID "\052\206\110\206\367\022\001\002\002"
+
+#define GSS_MECH_KRB5_OLD_OID_LENGTH 5
+#define GSS_MECH_KRB5_OLD_OID "\053\005\001\005\002"
+
+/* Incorrect krb5 mech OID emitted by MS. */
+#define GSS_MECH_KRB5_WRONG_OID_LENGTH 9
+#define GSS_MECH_KRB5_WRONG_OID "\052\206\110\202\367\022\001\002\002"
+
+/* IAKERB variant */
+#define GSS_MECH_IAKERB_OID_LENGTH 6
+#define GSS_MECH_IAKERB_OID "\053\006\001\005\002\005"
+
+extern const gss_OID_set kg_all_mechs;
+
+#define CKSUMTYPE_KG_CB 0x8003
+
+#define KG_TOK_CTX_AP_REQ 0x0100
+#define KG_TOK_CTX_AP_REP 0x0200
+#define KG_TOK_CTX_ERROR 0x0300
+#define KG_TOK_SIGN_MSG 0x0101
+#define KG_TOK_SEAL_MSG 0x0201
+#define KG_TOK_MIC_MSG 0x0101
+#define KG_TOK_WRAP_MSG 0x0201
+#define KG_TOK_DEL_CTX 0x0102
+#define KG2_TOK_MIC_MSG 0x0404
+#define KG2_TOK_WRAP_MSG 0x0504
+#define KG2_TOK_DEL_CTX 0x0405
+#define IAKERB_TOK_PROXY 0x0501
+
+#define KRB5_GSS_FOR_CREDS_OPTION 1
+
+#define KG2_RESP_FLAG_ERROR 0x0001
+#define KG2_RESP_FLAG_DELEG_OK 0x0002
+
+/** CFX flags **/
+#define FLAG_SENDER_IS_ACCEPTOR 0x01
+#define FLAG_WRAP_CONFIDENTIAL 0x02
+#define FLAG_ACCEPTOR_SUBKEY 0x04
+
+/* These are to be stored in little-endian order, i.e., des-mac is
+ stored as 02 00. */
+enum sgn_alg {
+ SGN_ALG_DES_MAC_MD5 = 0x0000,
+ SGN_ALG_MD2_5 = 0x0001,
+ SGN_ALG_DES_MAC = 0x0002,
+ SGN_ALG_3 = 0x0003, /* not published */
+ SGN_ALG_HMAC_MD5 = 0x0011, /* microsoft w2k; */
+ SGN_ALG_HMAC_SHA1_DES3_KD = 0x0004
+};
+enum seal_alg {
+ SEAL_ALG_NONE = 0xffff,
+ SEAL_ALG_DES = 0x0000,
+ SEAL_ALG_1 = 0x0001, /* not published */
+ SEAL_ALG_MICROSOFT_RC4 = 0x0010, /* microsoft w2k; */
+ SEAL_ALG_DES3KD = 0x0002
+};
+
+/* for 3DES */
+#define KG_USAGE_SEAL 22
+#define KG_USAGE_SIGN 23
+#define KG_USAGE_SEQ 24
+
+/* for draft-ietf-krb-wg-gssapi-cfx-01 */
+#define KG_USAGE_ACCEPTOR_SEAL 22
+#define KG_USAGE_ACCEPTOR_SIGN 23
+#define KG_USAGE_INITIATOR_SEAL 24
+#define KG_USAGE_INITIATOR_SIGN 25
+
+enum qop {
+ GSS_KRB5_INTEG_C_QOP_MD5 = 0x0001, /* *partial* MD5 = "MD2.5" */
+ GSS_KRB5_INTEG_C_QOP_DES_MD5 = 0x0002,
+ GSS_KRB5_INTEG_C_QOP_DES_MAC = 0x0003,
+ GSS_KRB5_INTEG_C_QOP_HMAC_SHA1 = 0x0004,
+ GSS_KRB5_INTEG_C_QOP_MASK = 0x00ff,
+ GSS_KRB5_CONF_C_QOP_DES = 0x0100,
+ GSS_KRB5_CONF_C_QOP_DES3_KD = 0x0200,
+ GSS_KRB5_CONF_C_QOP_MASK = 0xff00
+};
+
+/** internal types **/
+
+typedef struct _krb5_gss_name_rec {
+ krb5_principal princ; /* immutable */
+ char *service; /* immutable */
+ char *host; /* immutable */
+ k5_mutex_t lock; /* protects ad_context only for now */
+ krb5_authdata_context ad_context;
+} krb5_gss_name_rec, *krb5_gss_name_t;
+
+typedef struct _krb5_gss_cred_id_rec {
+ /* protect against simultaneous accesses */
+ k5_mutex_t lock;
+
+ /* name/type of credential */
+ gss_cred_usage_t usage;
+ krb5_gss_name_t name;
+ krb5_principal impersonator;
+ unsigned int default_identity : 1;
+ unsigned int iakerb_mech : 1;
+ unsigned int destroy_ccache : 1;
+ unsigned int suppress_ci_flags : 1;
+
+ /* keytab (accept) data */
+ krb5_keytab keytab;
+ krb5_rcache rcache;
+
+ /* ccache (init) data */
+ krb5_ccache ccache;
+ krb5_keytab client_keytab;
+ krb5_boolean have_tgt;
+ krb5_timestamp expire;
+ krb5_timestamp refresh_time;
+ krb5_enctype *req_enctypes; /* limit negotiated enctypes to this list */
+ char *password;
+} krb5_gss_cred_id_rec, *krb5_gss_cred_id_t;
+
+typedef struct _krb5_gss_ctx_ext_rec {
+ struct {
+ krb5_data *conv;
+ int verified;
+ } iakerb;
+} krb5_gss_ctx_ext_rec, *krb5_gss_ctx_ext_t;
+
+typedef struct _krb5_gss_ctx_id_rec {
+ krb5_magic magic;
+ unsigned int initiate : 1; /* nonzero if initiating, zero if accepting */
+ unsigned int established : 1;
+ unsigned int have_acceptor_subkey : 1;
+ unsigned int seed_init : 1; /* XXX tested but never actually set */
+ unsigned int terminated : 1;
+ OM_uint32 gss_flags;
+ unsigned char seed[16];
+ krb5_gss_name_t here;
+ krb5_gss_name_t there;
+ krb5_key subkey; /* One of two potential keys to use with RFC 4121
+ * packets; this key must always be set. */
+ int signalg;
+ size_t cksum_size;
+ int sealalg;
+ krb5_key enc; /* RFC 1964 encryption key; seq xored with a constant
+ * for DES, seq for other RFC 1964 enctypes */
+ krb5_key seq; /* RFC 1964 sequencing key */
+ krb5_ticket_times krb_times;
+ krb5_flags krb_flags;
+ /* XXX these used to be signed. the old spec is inspecific, and
+ the new spec specifies unsigned. I don't believe that the change
+ affects the wire encoding. */
+ uint64_t seq_send;
+ uint64_t seq_recv;
+ g_seqnum_state seqstate;
+ krb5_context k5_context;
+ krb5_auth_context auth_context;
+ gss_OID_desc *mech_used;
+ /* Protocol spec revision for sending packets
+ 0 => RFC 1964 with 3DES and RC4 enhancements
+ 1 => RFC 4121
+ No others defined so far. It is always permitted to receive
+ tokens in RFC 4121 format. If enc is non-null, receiving RFC
+ 1964 tokens is permitted.*/
+ int proto;
+ krb5_cksumtype cksumtype; /* for "main" subkey */
+ krb5_key acceptor_subkey; /* CFX only */
+ krb5_cksumtype acceptor_subkey_cksumtype;
+ int cred_rcache; /* did we get rcache from creds? */
+ krb5_authdata **authdata;
+} krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t;
+
+extern g_set kg_vdb;
+
+#ifndef LEAN_CLIENT
+extern k5_mutex_t gssint_krb5_keytab_lock;
+#endif /* LEAN_CLIENT */
+
+/** helper functions **/
+
+OM_uint32 kg_get_defcred
+(OM_uint32 *minor_status,
+ gss_cred_id_t *cred);
+
+krb5_error_code kg_checksum_channel_bindings
+(krb5_context context, gss_channel_bindings_t cb,
+ krb5_checksum *cksum);
+
+krb5_error_code kg_make_seq_num (krb5_context context,
+ krb5_key key,
+ int direction, krb5_ui_4 seqnum, unsigned char *cksum,
+ unsigned char *buf);
+
+krb5_error_code kg_get_seq_num (krb5_context context,
+ krb5_key key,
+ unsigned char *cksum, unsigned char *buf, int *direction,
+ krb5_ui_4 *seqnum);
+
+krb5_error_code kg_make_seed (krb5_context context,
+ krb5_key key,
+ unsigned char *seed);
+
+krb5_error_code
+kg_setup_keys(krb5_context context,
+ krb5_gss_ctx_id_rec *ctx,
+ krb5_key subkey,
+ krb5_cksumtype *cksumtype);
+
+int kg_confounder_size (krb5_context context, krb5_enctype enctype);
+
+krb5_error_code kg_make_confounder (krb5_context context,
+ krb5_enctype enctype, unsigned char *buf);
+
+krb5_error_code kg_encrypt (krb5_context context,
+ krb5_key key, int usage,
+ krb5_pointer iv,
+ krb5_const_pointer in,
+ krb5_pointer out,
+ unsigned int length);
+
+/* Encrypt length bytes at ptr in place, with the given key and usage. If
+ * iv is not NULL, use it as the cipher state. */
+krb5_error_code kg_encrypt_inplace(krb5_context context, krb5_key key,
+ int usage, krb5_pointer iv,
+ krb5_pointer ptr, unsigned int length);
+
+krb5_error_code kg_encrypt_iov (krb5_context context,
+ int proto, int dce_style,
+ size_t ec, size_t rrc,
+ krb5_key key, int usage,
+ krb5_pointer iv,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+
+krb5_error_code
+kg_arcfour_docrypt (const krb5_keyblock *keyblock, int usage,
+ const unsigned char *kd_data, size_t kd_data_len,
+ const unsigned char *input_buf, size_t input_len,
+ unsigned char *output_buf);
+
+krb5_error_code
+kg_arcfour_docrypt_iov (krb5_context context,
+ const krb5_keyblock *keyblock, int usage,
+ const unsigned char *kd_data, size_t kd_data_len,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+
+krb5_error_code kg_decrypt (krb5_context context,
+ krb5_key key, int usage,
+ krb5_pointer iv,
+ krb5_const_pointer in,
+ krb5_pointer out,
+ unsigned int length);
+
+krb5_error_code kg_decrypt_iov (krb5_context context,
+ int proto, int dce_style,
+ size_t ec, size_t rrc,
+ krb5_key key, int usage,
+ krb5_pointer iv,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+
+OM_uint32 kg_seal (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer,
+ int toktype);
+
+OM_uint32 kg_unseal (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t input_token_buffer,
+ gss_buffer_t message_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ int toktype);
+
+OM_uint32 kg_seal_size (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 output_size,
+ OM_uint32 *input_size);
+
+krb5_error_code kg_ctx_size (krb5_context kcontext,
+ krb5_pointer arg,
+ size_t *sizep);
+
+krb5_error_code kg_ctx_externalize (krb5_context kcontext,
+ krb5_pointer arg,
+ krb5_octet **buffer,
+ size_t *lenremain);
+
+krb5_error_code kg_ctx_internalize (krb5_context kcontext,
+ krb5_pointer *argp,
+ krb5_octet **buffer,
+ size_t *lenremain);
+
+OM_uint32 kg_sync_ccache_name (krb5_context context, OM_uint32 *minor_status);
+
+OM_uint32 kg_caller_provided_ccache_name (OM_uint32 *minor_status,
+ int *out_caller_provided_name);
+
+OM_uint32 kg_get_ccache_name (OM_uint32 *minor_status,
+ const char **out_name);
+
+OM_uint32 kg_set_ccache_name (OM_uint32 *minor_status,
+ const char *name);
+
+/* AEAD */
+
+krb5_error_code gss_krb5int_make_seal_token_v3_iov(krb5_context context,
+ krb5_gss_ctx_id_rec *ctx,
+ int conf_req_flag,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype);
+
+OM_uint32 gss_krb5int_unseal_v3_iov(krb5_context context,
+ OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ int toktype);
+
+gss_iov_buffer_t kg_locate_iov (gss_iov_buffer_desc *iov,
+ int iov_count,
+ OM_uint32 type);
+
+gss_iov_buffer_t kg_locate_header_iov(gss_iov_buffer_desc *iov, int iov_count,
+ int toktype);
+
+void kg_iov_msglen(gss_iov_buffer_desc *iov,
+ int iov_count,
+ size_t *data_length,
+ size_t *assoc_data_length);
+
+void kg_release_iov(gss_iov_buffer_desc *iov,
+ int iov_count);
+
+krb5_error_code kg_make_checksum_iov_v1(krb5_context context,
+ krb5_cksumtype type,
+ size_t token_cksum_len,
+ krb5_key seq,
+ krb5_key enc, /* for conf len */
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype,
+ krb5_checksum *checksum);
+
+krb5_error_code kg_make_checksum_iov_v3(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_key key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype);
+
+krb5_error_code kg_verify_checksum_iov_v3(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_key key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype,
+ krb5_boolean *valid);
+
+OM_uint32 kg_seal_iov (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype);
+
+OM_uint32 kg_unseal_iov (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype);
+
+OM_uint32 kg_seal_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype);
+
+krb5_cryptotype kg_translate_flag_iov(OM_uint32 type);
+
+OM_uint32 kg_fixup_padding_iov(OM_uint32 *minor_status,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+
+krb5_boolean kg_integ_only_iov(gss_iov_buffer_desc *iov, int iov_count);
+
+krb5_error_code kg_allocate_iov(gss_iov_buffer_t iov, size_t size);
+
+krb5_error_code
+krb5_to_gss_cred(krb5_context context,
+ krb5_creds *creds,
+ krb5_gss_cred_id_t *out_cred);
+
+krb5_boolean
+kg_cred_time_to_refresh(krb5_context context, krb5_gss_cred_id_rec *cred);
+
+void
+kg_cred_set_initial_refresh(krb5_context context, krb5_gss_cred_id_rec *cred,
+ krb5_ticket_times *times);
+
+OM_uint32
+kg_cred_resolve(OM_uint32 *minor_status, krb5_context context,
+ gss_cred_id_t cred_handle, gss_name_t target_name);
+
+/** declarations of internal name mechanism functions **/
+
+OM_uint32 KRB5_CALLCONV krb5_gss_acquire_cred
+(OM_uint32*, /* minor_status */
+ gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t*, /* output_cred_handle */
+ gss_OID_set*, /* actual_mechs */
+ OM_uint32* /* time_rec */
+);
+
+OM_uint32 KRB5_CALLCONV iakerb_gss_acquire_cred
+(OM_uint32*, /* minor_status */
+ gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t*, /* output_cred_handle */
+ gss_OID_set*, /* actual_mechs */
+ OM_uint32* /* time_rec */
+);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred_with_password(
+ OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_acquire_cred_with_password(
+ OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_release_cred
+(OM_uint32*, /* minor_status */
+ gss_cred_id_t* /* cred_handle */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_init_sec_context
+(OM_uint32*, /* minor_status */
+ gss_cred_id_t, /* claimant_cred_handle */
+ gss_ctx_id_t*, /* context_handle */
+ gss_name_t, /* target_name */
+ gss_OID, /* mech_type */
+ OM_uint32, /* req_flags */
+ OM_uint32, /* time_req */
+ gss_channel_bindings_t,
+ /* input_chan_bindings */
+ gss_buffer_t, /* input_token */
+ gss_OID*, /* actual_mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32* /* time_rec */
+);
+
+OM_uint32 krb5_gss_init_sec_context_ext
+(OM_uint32*, /* minor_status */
+ gss_cred_id_t, /* claimant_cred_handle */
+ gss_ctx_id_t*, /* context_handle */
+ gss_name_t, /* target_name */
+ gss_OID, /* mech_type */
+ OM_uint32, /* req_flags */
+ OM_uint32, /* time_req */
+ gss_channel_bindings_t,
+ /* input_chan_bindings */
+ gss_buffer_t, /* input_token */
+ gss_OID*, /* actual_mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32*, /* time_rec */
+ krb5_gss_ctx_ext_t /* exts */
+);
+
+#ifndef LEAN_CLIENT
+OM_uint32 KRB5_CALLCONV krb5_gss_accept_sec_context
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t*, /* context_handle */
+ gss_cred_id_t, /* verifier_cred_handle */
+ gss_buffer_t, /* input_token_buffer */
+ gss_channel_bindings_t,
+ /* input_chan_bindings */
+ gss_name_t*, /* src_name */
+ gss_OID*, /* mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32*, /* time_rec */
+ gss_cred_id_t* /* delegated_cred_handle */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_accept_sec_context_ext
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t*, /* context_handle */
+ gss_cred_id_t, /* verifier_cred_handle */
+ gss_buffer_t, /* input_token_buffer */
+ gss_channel_bindings_t,
+ /* input_chan_bindings */
+ gss_name_t*, /* src_name */
+ gss_OID*, /* mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32*, /* time_rec */
+ gss_cred_id_t*, /* delegated_cred_handle */
+ krb5_gss_ctx_ext_t/*exts */
+);
+#endif /* LEAN_CLIENT */
+
+OM_uint32 KRB5_CALLCONV krb5_gss_inquire_sec_context_by_oid
+(OM_uint32*, /* minor_status */
+ const gss_ctx_id_t,
+ /* context_handle */
+ const gss_OID, /* desired_object */
+ gss_buffer_set_t* /* data_set */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_set_sec_context_option
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t*, /* context_handle */
+ const gss_OID, /* desired_object */
+ const gss_buffer_t/* value */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_process_context_token
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t /* token_buffer */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_delete_sec_context
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t*, /* context_handle */
+ gss_buffer_t /* output_token */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_context_time
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ OM_uint32* /* time_rec */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_display_status
+(OM_uint32*, /* minor_status */
+ OM_uint32, /* status_value */
+ int, /* status_type */
+ gss_OID, /* mech_type */
+ OM_uint32*, /* message_context */
+ gss_buffer_t /* status_string */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_indicate_mechs
+(OM_uint32*, /* minor_status */
+ gss_OID_set* /* mech_set */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_compare_name
+(OM_uint32*, /* minor_status */
+ gss_name_t, /* name1 */
+ gss_name_t, /* name2 */
+ int* /* name_equal */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_display_name
+(OM_uint32*, /* minor_status */
+ gss_name_t, /* input_name */
+ gss_buffer_t, /* output_name_buffer */
+ gss_OID* /* output_name_type */
+);
+
+
+OM_uint32 KRB5_CALLCONV krb5_gss_import_name
+(OM_uint32*, /* minor_status */
+ gss_buffer_t, /* input_name_buffer */
+ gss_OID, /* input_name_type */
+ gss_name_t* /* output_name */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_release_name
+(OM_uint32*, /* minor_status */
+ gss_name_t* /* input_name */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_inquire_cred
+(OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* lifetime */
+ gss_cred_usage_t*,/* cred_usage */
+ gss_OID_set * /* mechanisms */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_inquire_context
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_name_t*, /* initiator_name */
+ gss_name_t*, /* acceptor_name */
+ OM_uint32*, /* lifetime_rec */
+ gss_OID*, /* mech_type */
+ OM_uint32*, /* ret_flags */
+ int*, /* locally_initiated */
+ int* /* open */
+);
+
+/* New V2 entry points */
+OM_uint32 KRB5_CALLCONV krb5_gss_get_mic
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t /* message_token */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_get_mic_iov
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_get_mic_iov_length
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_verify_mic
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t, /* message_token */
+ gss_qop_t * /* qop_state */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_verify_mic_iov
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t *, /* qop_state */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_wrap
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ gss_buffer_t, /* input_message_buffer */
+ int *, /* conf_state */
+ gss_buffer_t /* output_message_buffer */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_wrap_iov
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ int *, /* conf_state */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_wrap_iov_length
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ int *, /* conf_state */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_unwrap
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* input_message_buffer */
+ gss_buffer_t, /* output_message_buffer */
+ int *, /* conf_state */
+ gss_qop_t * /* qop_state */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_unwrap_iov
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int *, /* conf_state */
+ gss_qop_t *, /* qop_state */
+ gss_iov_buffer_desc *, /* iov */
+ int /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_wrap_size_limit
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ OM_uint32, /* req_output_size */
+ OM_uint32 * /* max_input_size */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_import_name_object
+(OM_uint32 *, /* minor_status */
+ void *, /* input_name */
+ gss_OID, /* input_name_type */
+ gss_name_t * /* output_name */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_export_name_object
+(OM_uint32 *, /* minor_status */
+ gss_name_t, /* input_name */
+ gss_OID, /* desired_name_type */
+ void * * /* output_name */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_inquire_cred_by_mech
+(OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_OID, /* mech_type */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* initiator_lifetime */
+ OM_uint32 *, /* acceptor_lifetime */
+ gss_cred_usage_t * /* cred_usage */
+);
+#ifndef LEAN_CLIENT
+OM_uint32 KRB5_CALLCONV krb5_gss_export_sec_context
+(OM_uint32 *, /* minor_status */
+ gss_ctx_id_t *, /* context_handle */
+ gss_buffer_t /* interprocess_token */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_import_sec_context
+(OM_uint32 *, /* minor_status */
+ gss_buffer_t, /* interprocess_token */
+ gss_ctx_id_t * /* context_handle */
+);
+#endif /* LEAN_CLIENT */
+
+krb5_error_code krb5_gss_ser_init(krb5_context);
+
+OM_uint32 krb5_gss_release_oid
+(OM_uint32 *, /* minor_status */
+ gss_OID * /* oid */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_internal_release_oid
+(OM_uint32 *, /* minor_status */
+ gss_OID * /* oid */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_inquire_names_for_mech
+(OM_uint32 *, /* minor_status */
+ gss_OID, /* mechanism */
+ gss_OID_set * /* name_types */
+);
+
+OM_uint32 krb5_gss_canonicalize_name
+(OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ const gss_OID, /* mech_type */
+ gss_name_t * /* output_name */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_export_name
+(OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_buffer_t /* exported_name */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_duplicate_name
+(OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_name_t * /* dest_name */
+);
+
+OM_uint32 krb5_gss_validate_cred
+(OM_uint32 *, /* minor_status */
+ gss_cred_id_t /* cred */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_acquire_cred_impersonate_name(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *); /* time_rec */
+
+OM_uint32
+krb5_gss_validate_cred_1(OM_uint32 * /* minor_status */,
+ gss_cred_id_t /* cred_handle */,
+ krb5_context /* context */);
+
+gss_OID krb5_gss_convert_static_mech_oid(gss_OID oid);
+
+krb5_error_code gss_krb5int_make_seal_token_v3(krb5_context,
+ krb5_gss_ctx_id_rec *,
+ const gss_buffer_desc *,
+ gss_buffer_t,
+ int, int);
+
+OM_uint32 gss_krb5int_unseal_token_v3(krb5_context *contextptr,
+ OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ unsigned char *ptr,
+ unsigned int bodysize,
+ gss_buffer_t message_buffer,
+ int *conf_state, gss_qop_t *qop_state,
+ int toktype);
+
+int gss_krb5int_rotate_left (void *ptr, size_t bufsiz, size_t rc);
+
+/* naming_exts.c */
+#define KG_INIT_NAME_NO_COPY 0x1
+
+krb5_error_code
+kg_init_name(krb5_context context, krb5_principal principal,
+ char *service, char *host, krb5_authdata_context ad_context,
+ krb5_flags flags, krb5_gss_name_t *name);
+
+krb5_error_code
+kg_release_name(krb5_context context, krb5_gss_name_t *name);
+
+krb5_error_code
+kg_duplicate_name(krb5_context context, const krb5_gss_name_t src,
+ krb5_gss_name_t *dst);
+
+krb5_boolean
+kg_compare_name(krb5_context context,
+ krb5_gss_name_t name1,
+ krb5_gss_name_t name2);
+
+krb5_boolean
+kg_acceptor_princ(krb5_context context, krb5_gss_name_t name,
+ krb5_principal *princ_out);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_display_name_ext(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_OID display_as_name_type,
+ gss_buffer_t display_name);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_name(OM_uint32 *minor_status,
+ gss_name_t name,
+ int *name_is_MN,
+ gss_OID *MN_mech,
+ gss_buffer_set_t *attrs);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_get_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_set_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ int complete,
+ gss_buffer_t attr,
+ gss_buffer_t value);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_delete_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_export_name_composite(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t exp_composite_name);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_map_name_to_any(OM_uint32 *minor_status,
+ gss_name_t name,
+ int authenticated,
+ gss_buffer_t type_id,
+ gss_any_t *output);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_release_any_name_mapping(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t type_id,
+ gss_any_t *input);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_pseudo_random(OM_uint32 *minor_status,
+ gss_ctx_id_t context,
+ int prf_key,
+ const gss_buffer_t prf_in,
+ ssize_t desired_output_len,
+ gss_buffer_t prf_out);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_store_cred(OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ gss_cred_usage_t cred_usage,
+ const gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_OID_set *elements_stored,
+ gss_cred_usage_t *cred_usage_stored);
+
+/* s4u_gss_glue.c */
+OM_uint32
+kg_compose_deleg_cred(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t impersonator_cred,
+ krb5_creds *subject_creds,
+ OM_uint32 time_req,
+ krb5_gss_cred_id_t *output_cred,
+ OM_uint32 *time_rec,
+ krb5_context context);
+
+/*
+ * These take unglued krb5-mech-specific contexts.
+ */
+
+#define GSS_KRB5_GET_TKT_FLAGS_OID_LENGTH 11
+#define GSS_KRB5_GET_TKT_FLAGS_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x01"
+
+OM_uint32 gss_krb5int_get_tkt_flags
+(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set);
+
+#define GSS_KRB5_COPY_CCACHE_OID_LENGTH 11
+#define GSS_KRB5_COPY_CCACHE_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x02"
+
+OM_uint32 gss_krb5int_copy_ccache
+(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_oid,
+ const gss_buffer_t value);
+
+#define GSS_KRB5_CCACHE_NAME_OID_LENGTH 11
+#define GSS_KRB5_CCACHE_NAME_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x03"
+
+struct krb5_gss_ccache_name_req {
+ const char *name;
+ const char **out_name;
+};
+
+OM_uint32
+gss_krb5int_ccache_name(OM_uint32 *minor_status, const gss_OID, const gss_OID,
+ const gss_buffer_t);
+
+#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH 11
+#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"
+
+OM_uint32
+gss_krb5int_inq_session_key(OM_uint32 *, const gss_ctx_id_t, const gss_OID, gss_buffer_set_t *);
+
+#define GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID_LENGTH 11
+#define GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x04"
+
+struct krb5_gss_set_allowable_enctypes_req {
+ OM_uint32 num_ktypes;
+ krb5_enctype *ktypes;
+};
+
+OM_uint32
+gss_krb5int_set_allowable_enctypes(OM_uint32 *minor_status,
+ gss_cred_id_t *cred,
+ const gss_OID desired_oid,
+ const gss_buffer_t value);
+
+#define GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06"
+
+OM_uint32
+gss_krb5int_export_lucid_sec_context(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set);
+
+#define GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07"
+
+OM_uint32
+gss_krb5int_free_lucid_sec_context(OM_uint32 *, const gss_OID,
+ const gss_OID, gss_buffer_t);
+
+extern k5_mutex_t kg_kdc_flag_mutex;
+krb5_error_code krb5_gss_init_context (krb5_context *ctxp);
+
+#define GSS_KRB5_USE_KDC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_USE_KDC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x08"
+
+OM_uint32 krb5int_gss_use_kdc_context(OM_uint32 *, const gss_OID,
+ const gss_OID, gss_buffer_t);
+
+krb5_error_code krb5_gss_use_kdc_context(void);
+
+#define GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID_LENGTH 11
+#define GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x09"
+
+OM_uint32
+gss_krb5int_register_acceptor_identity(OM_uint32 *, const gss_OID, const gss_OID, gss_buffer_t);
+
+#define GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0a"
+
+OM_uint32
+gss_krb5int_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *ad_data);
+
+#define GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH 11
+#define GSS_KRB5_SET_CRED_RCACHE_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0b"
+
+OM_uint32
+gss_krb5int_set_cred_rcache(OM_uint32 *, gss_cred_id_t *, const gss_OID, const gss_buffer_t);
+
+#define GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH 11
+#define GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0c"
+
+OM_uint32
+gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *,
+ const gss_ctx_id_t,
+ const gss_OID,
+ gss_buffer_set_t *);
+
+#define GSS_KRB5_IMPORT_CRED_OID_LENGTH 11
+#define GSS_KRB5_IMPORT_CRED_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0d"
+
+struct krb5_gss_import_cred_req {
+ krb5_ccache id;
+ krb5_principal keytab_principal;
+ krb5_keytab keytab;
+};
+
+OM_uint32
+gss_krb5int_import_cred(OM_uint32 *minor_status,
+ gss_cred_id_t *cred,
+ const gss_OID desired_oid,
+ const gss_buffer_t value);
+
+#ifdef _GSS_STATIC_LINK
+int gss_krb5int_lib_init(void);
+void gss_krb5int_lib_fini(void);
+#endif /* _GSS_STATIC_LINK */
+
+OM_uint32 gss_krb5int_initialize_library(void);
+void gss_krb5int_cleanup_library(void);
+
+/* For error message handling. */
+/* Returns a shared string, not a private copy! */
+extern char *
+krb5_gss_get_error_message(OM_uint32 minor_code);
+extern void
+krb5_gss_save_error_string(OM_uint32 minor_code, char *msg);
+extern void
+krb5_gss_save_error_message(OM_uint32 minor_code, const char *format, ...)
+#if !defined(__cplusplus) && (__GNUC__ > 2)
+ __attribute__((__format__(__printf__, 2, 3)))
+#endif
+ ;
+ extern void
+ krb5_gss_save_error_info(OM_uint32 minor_code, krb5_context ctx);
+#define get_error_message krb5_gss_get_error_message
+#define save_error_string krb5_gss_save_error_string
+#define save_error_message krb5_gss_save_error_message
+#ifdef KRB5_KERNEL
+/* Error messages aren't needed in the kernel, so reduce dependencies. */
+#define save_error_info(x,y)
+#else
+#define save_error_info krb5_gss_save_error_info
+#endif
+extern void krb5_gss_delete_error_info(void *p);
+
+/* Prefix concatenated with Kerberos encryption type */
+#define GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH 10
+#define GSS_KRB5_SESSION_KEY_ENCTYPE_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04"
+
+/* IAKERB */
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_init_sec_context(OM_uint32 *minor_status,
+ gss_cred_id_t claimant_cred_handle,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_accept_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handler,
+ gss_cred_id_t verifier_cred_handle,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_delete_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token);
+
+krb5_error_code
+iakerb_make_finished(krb5_context context,
+ krb5_key key,
+ const krb5_data *conv,
+ krb5_data **finished);
+
+krb5_error_code
+iakerb_verify_finished(krb5_context context,
+ krb5_key key,
+ const krb5_data *conv,
+ const krb5_data *finished);
+
+/*
+ * Transfer contents of a krb5_data to a gss_buffer and invalidate the source
+ * On unix, this is a simple pointer copy
+ * On windows, memory is reallocated and copied.
+ */
+static inline krb5_error_code
+data_to_gss(krb5_data *input_k5data, gss_buffer_t output_buffer)
+{
+ krb5_error_code code = 0;
+ output_buffer->length = input_k5data->length;
+#if defined(_WIN32) || defined(DEBUG_GSSALLOC)
+ if (output_buffer->length > 0) {
+ output_buffer->value = gssalloc_malloc(output_buffer->length);
+ if (output_buffer->value)
+ memcpy(output_buffer->value, input_k5data->data, output_buffer->length);
+ else
+ code = ENOMEM;
+ } else {
+ output_buffer->value = NULL;
+ }
+ free(input_k5data->data);
+#else
+ output_buffer->value = input_k5data->data;
+#endif
+ *input_k5data = empty_data();
+ return code;
+}
+
+#define KRB5_GSS_EXTS_IAKERB_FINISHED 1
+
+
+/* Credential store extensions */
+
+#define KRB5_CS_CLI_KEYTAB_URN "client_keytab"
+#define KRB5_CS_KEYTAB_URN "keytab"
+#define KRB5_CS_CCACHE_URN "ccache"
+#define KRB5_CS_RCACHE_URN "rcache"
+
+OM_uint32
+kg_value_from_cred_store(gss_const_key_value_set_t cred_store,
+ const char *type, const char **value);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred_from(
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_const_key_value_set_t, /* cred_store */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *); /* time_rec */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_store_cred_into(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ gss_cred_usage_t, /* input_usage */
+ const gss_OID, /* desired_mech */
+ OM_uint32, /* overwrite_cred */
+ OM_uint32, /* default_cred */
+ gss_const_key_value_set_t, /* cred_store */
+ gss_OID_set *, /* elements_stored */
+ gss_cred_usage_t *); /* cred_usage_stored */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_export_cred(OM_uint32 *minor_status, gss_cred_id_t cred_handle,
+ gss_buffer_t token);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_import_cred(OM_uint32 *minor_status, gss_buffer_t token,
+ gss_cred_id_t *cred_handle);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_process_context_token(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t token_buffer);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_context_time(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ OM_uint32 *time_rec);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_inquire_context(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, gss_name_t *src_name,
+ gss_name_t *targ_name, OM_uint32 *lifetime_rec,
+ gss_OID *mech_type, OM_uint32 *ctx_flags,
+ int *locally_initiated, int *opened);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t qop_req, gss_buffer_t message_buffer,
+ gss_buffer_t message_token);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t qop_req, gss_iov_buffer_desc *iov,
+ int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, gss_qop_t qop_req,
+ gss_iov_buffer_desc *iov, int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_verify_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_buffer_t msg_buffer, gss_buffer_t token_buffer,
+ gss_qop_t *qop_state);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
+ int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int conf_req_flag, gss_qop_t qop_req,
+ gss_buffer_t input_message_buffer, int *conf_state,
+ gss_buffer_t output_message_buffer);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int conf_req_flag, gss_qop_t qop_req, int *conf_state,
+ gss_iov_buffer_desc *iov, int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, int conf_req_flag,
+ gss_qop_t qop_req, int *conf_state,
+ gss_iov_buffer_desc *iov, int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_unwrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer, int *conf_state,
+ gss_qop_t *qop_state);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_unwrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int *conf_state, gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov, int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_size_limit(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, int conf_req_flag,
+ gss_qop_t qop_req, OM_uint32 req_output_size,
+ OM_uint32 *max_input_size);
+
+#ifndef LEAN_CLIENT
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_export_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t interprocess_token);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_import_sec_context(OM_uint32 *minor_status,
+ const gss_buffer_t interprocess_token,
+ gss_ctx_id_t *context_handle);
+#endif /* LEAN_CLIENT */
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_inquire_sec_context_by_oid(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_set_sec_context_option(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int prf_key, const gss_buffer_t prf_in,
+ ssize_t desired_output_len, gss_buffer_t prf_out);
+
+/* Magic string to identify exported krb5 GSS credentials. Increment this if
+ * the format changes. */
+#define CRED_EXPORT_MAGIC "K5C1"
+
+#endif /* _GSSAPIP_KRB5_H_ */
diff --git a/src/lib/gssapi/krb5/gssapi_err_krb5.et b/src/lib/gssapi/krb5/gssapi_err_krb5.et
new file mode 100644
index 000000000000..6396d5902009
--- /dev/null
+++ b/src/lib/gssapi/krb5/gssapi_err_krb5.et
@@ -0,0 +1,42 @@
+#
+# Copyright 1993 by OpenVision Technologies, Inc.
+#
+# Permission to use, copy, modify, distribute, and sell this software
+# and its documentation for any purpose is hereby granted without fee,
+# provided that the above copyright notice appears in all copies and
+# that both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of OpenVision not be used
+# in advertising or publicity pertaining to distribution of the software
+# without specific, written prior permission. OpenVision makes no
+# representations about the suitability of this software for any
+# purpose. It is provided "as is" without express or implied warranty.
+#
+# OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+# EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+#
+
+error_table k5g
+
+error_code KG_CCACHE_NOMATCH, "Principal in credential cache does not match desired name"
+error_code KG_KEYTAB_NOMATCH, "No principal in keytab matches desired name"
+error_code KG_TGT_MISSING, "Credential cache has no TGT"
+error_code KG_NO_SUBKEY, "Authenticator has no subkey"
+error_code KG_CONTEXT_ESTABLISHED, "Context is already fully established"
+error_code KG_BAD_SIGN_TYPE, "Unknown signature type in token"
+error_code KG_BAD_LENGTH, "Invalid field length in token"
+error_code KG_CTX_INCOMPLETE, "Attempt to use incomplete security context"
+error_code KG_CONTEXT, "Bad magic number for krb5_gss_ctx_id_t"
+error_code KG_CRED, "Bad magic number for krb5_gss_cred_id_t"
+error_code KG_ENC_DESC, "Bad magic number for krb5_gss_enc_desc"
+error_code KG_BAD_SEQ, "Sequence number in token is corrupt"
+error_code KG_EMPTY_CCACHE, "Credential cache is empty"
+error_code KG_NO_CTYPES, "Acceptor and Initiator share no checksum types"
+error_code KG_LUCID_VERSION, "Requested lucid context version not supported"
+error_code KG_INPUT_TOO_LONG, "PRF input too long"
+error_code KG_IAKERB_CONTEXT, "Bad magic number for iakerb_ctx_id_t"
+end
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
new file mode 100644
index 000000000000..99092ccab16b
--- /dev/null
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -0,0 +1,1159 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * The copyright holder's name is not used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+
+/* For declaration of krb5_ser_context_init */
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#include "mglueP.h"
+
+#ifndef NO_PASSWORD
+#include <pwd.h>
+#endif
+
+/** exported constants defined in gssapi_krb5{,_nx}.h **/
+
+/* these are bogus, but will compile */
+
+/*
+ * The OID of the draft krb5 mechanism, assigned by IETF, is:
+ * iso(1) org(3) dod(5) internet(1) security(5)
+ * kerberosv5(2) = 1.3.5.1.5.2
+ * The OID of the krb5_name type is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_name(1) = 1.2.840.113554.1.2.2.1
+ * The OID of the krb5_principal type is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_principal(2) = 1.2.840.113554.1.2.2.2
+ * The OID of the proposed standard krb5 mechanism is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) = 1.2.840.113554.1.2.2
+ * The OID of the proposed standard krb5 v2 mechanism is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5v2(3) = 1.2.840.113554.1.2.3
+ * Provisionally reserved for Kerberos session key algorithm
+ * identifiers is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_enctype(4) = 1.2.840.113554.1.2.2.4
+ * Provisionally reserved for Kerberos mechanism-specific APIs:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_gssapi_ext(5) = 1.2.840.113554.1.2.2.5
+ */
+
+/*
+ * Encoding rules: The first two values are encoded in one byte as 40
+ * * value1 + value2. Subsequent values are encoded base 128, most
+ * significant digit first, with the high bit (\200) set on all octets
+ * except the last in each value's encoding.
+ */
+
+#define NO_CI_FLAGS_X_OID_LENGTH 6
+#define NO_CI_FLAGS_X_OID "\x2a\x85\x70\x2b\x0d\x1d"
+
+const gss_OID_desc krb5_gss_oid_array[] = {
+ /* this is the official, rfc-specified OID */
+ {GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID},
+ /* this pre-RFC mech OID */
+ {GSS_MECH_KRB5_OLD_OID_LENGTH, GSS_MECH_KRB5_OLD_OID},
+ /* this is the unofficial, incorrect mech OID emitted by MS */
+ {GSS_MECH_KRB5_WRONG_OID_LENGTH, GSS_MECH_KRB5_WRONG_OID},
+ /* IAKERB OID */
+ {GSS_MECH_IAKERB_OID_LENGTH, GSS_MECH_IAKERB_OID},
+ /* this is the v2 assigned OID */
+ {9, "\052\206\110\206\367\022\001\002\003"},
+ /* these two are name type OID's */
+ /* 2.1.1. Kerberos Principal Name Form: (rfc 1964)
+ * This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_name(1)}. The recommended symbolic name for this type
+ * is "GSS_KRB5_NT_PRINCIPAL_NAME". */
+ {10, "\052\206\110\206\367\022\001\002\002\001"},
+ /* gss_nt_krb5_principal. Object identifier for a krb5_principal. Do not use. */
+ {10, "\052\206\110\206\367\022\001\002\002\002"},
+ {NO_CI_FLAGS_X_OID_LENGTH, NO_CI_FLAGS_X_OID},
+ { 0, 0 }
+};
+
+#define kg_oids ((gss_OID)krb5_gss_oid_array)
+
+const gss_OID gss_mech_krb5 = &kg_oids[0];
+const gss_OID gss_mech_krb5_old = &kg_oids[1];
+const gss_OID gss_mech_krb5_wrong = &kg_oids[2];
+const gss_OID gss_mech_iakerb = &kg_oids[3];
+
+
+const gss_OID gss_nt_krb5_name = &kg_oids[5];
+const gss_OID gss_nt_krb5_principal = &kg_oids[6];
+const gss_OID GSS_KRB5_NT_PRINCIPAL_NAME = &kg_oids[5];
+
+const gss_OID GSS_KRB5_CRED_NO_CI_FLAGS_X = &kg_oids[7];
+
+static const gss_OID_set_desc oidsets[] = {
+ {1, &kg_oids[0]}, /* RFC OID */
+ {1, &kg_oids[1]}, /* pre-RFC OID */
+ {3, &kg_oids[0]}, /* all names for krb5 mech */
+ {4, &kg_oids[0]}, /* all krb5 names and IAKERB */
+};
+
+#define kg_oidsets ((gss_OID_set)oidsets)
+
+const gss_OID_set gss_mech_set_krb5 = &kg_oidsets[0];
+const gss_OID_set gss_mech_set_krb5_old = &kg_oidsets[1];
+const gss_OID_set gss_mech_set_krb5_both = &kg_oidsets[2];
+const gss_OID_set kg_all_mechs = &kg_oidsets[3];
+
+g_set kg_vdb = G_SET_INIT;
+
+/** default credential support */
+
+/*
+ * init_sec_context() will explicitly re-acquire default credentials,
+ * so handling the expiration/invalidation condition here isn't needed.
+ */
+OM_uint32
+kg_get_defcred(minor_status, cred)
+ OM_uint32 *minor_status;
+ gss_cred_id_t *cred;
+{
+ OM_uint32 major;
+
+ if ((major = krb5_gss_acquire_cred(minor_status,
+ (gss_name_t) NULL, GSS_C_INDEFINITE,
+ GSS_C_NULL_OID_SET, GSS_C_INITIATE,
+ cred, NULL, NULL)) && GSS_ERROR(major)) {
+ return(major);
+ }
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
+
+OM_uint32
+kg_sync_ccache_name (krb5_context context, OM_uint32 *minor_status)
+{
+ OM_uint32 err = 0;
+
+ /*
+ * Sync up the context ccache name with the GSSAPI ccache name.
+ * If kg_ccache_name is NULL -- normal unless someone has called
+ * gss_krb5_ccache_name() -- then the system default ccache will
+ * be picked up and used by resetting the context default ccache.
+ * This is needed for platforms which support multiple ccaches.
+ */
+
+ if (!err) {
+ /* if NULL, resets the context default ccache */
+ err = krb5_cc_set_default_name(context,
+ (char *) k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME));
+ }
+
+ *minor_status = err;
+ return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
+
+/* This function returns whether or not the caller set a cccache name. Used by
+ * gss_acquire_cred to figure out if the caller wants to only look at this
+ * ccache or search the cache collection for the desired name */
+OM_uint32
+kg_caller_provided_ccache_name (OM_uint32 *minor_status,
+ int *out_caller_provided_name)
+{
+ if (out_caller_provided_name) {
+ *out_caller_provided_name =
+ (k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME) != NULL);
+ }
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+kg_get_ccache_name (OM_uint32 *minor_status, const char **out_name)
+{
+ const char *name = NULL;
+ OM_uint32 err = 0;
+ char *kg_ccache_name;
+
+ kg_ccache_name = k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME);
+
+ if (kg_ccache_name != NULL) {
+ name = strdup(kg_ccache_name);
+ if (name == NULL)
+ err = ENOMEM;
+ } else {
+ krb5_context context = NULL;
+
+ /* Reset the context default ccache (see text above), and then
+ retrieve it. */
+ err = krb5_gss_init_context(&context);
+ if (!err)
+ err = krb5_cc_set_default_name (context, NULL);
+ if (!err) {
+ name = krb5_cc_default_name(context);
+ if (name) {
+ name = strdup(name);
+ if (name == NULL)
+ err = ENOMEM;
+ }
+ }
+ if (err && context)
+ save_error_info(err, context);
+ if (context)
+ krb5_free_context(context);
+ }
+
+ if (!err) {
+ if (out_name) {
+ *out_name = name;
+ }
+ }
+
+ *minor_status = err;
+ return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
+
+OM_uint32
+kg_set_ccache_name (OM_uint32 *minor_status, const char *name)
+{
+ char *new_name = NULL;
+ char *swap = NULL;
+ char *kg_ccache_name;
+ krb5_error_code kerr;
+
+ if (name) {
+ new_name = strdup(name);
+ if (new_name == NULL) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ kg_ccache_name = k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME);
+ swap = kg_ccache_name;
+ kg_ccache_name = new_name;
+ new_name = swap;
+ kerr = k5_setspecific(K5_KEY_GSS_KRB5_CCACHE_NAME, kg_ccache_name);
+ if (kerr != 0) {
+ /* Can't store, so free up the storage. */
+ free(kg_ccache_name);
+ /* ??? free(new_name); */
+ *minor_status = kerr;
+ return GSS_S_FAILURE;
+ }
+
+ free (new_name);
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+#define g_OID_prefix_equal(o1, o2) \
+ (((o1)->length >= (o2)->length) && \
+ (memcmp((o1)->elements, (o2)->elements, (o2)->length) == 0))
+
+/*
+ * gss_inquire_sec_context_by_oid() methods
+ */
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*func)(OM_uint32 *, const gss_ctx_id_t, const gss_OID, gss_buffer_set_t *);
+} krb5_gss_inquire_sec_context_by_oid_ops[] = {
+ {
+ {GSS_KRB5_GET_TKT_FLAGS_OID_LENGTH, GSS_KRB5_GET_TKT_FLAGS_OID},
+ gss_krb5int_get_tkt_flags
+ },
+ {
+ {GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID},
+ gss_krb5int_extract_authz_data_from_sec_context
+ },
+ {
+ {GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH, GSS_KRB5_INQ_SSPI_SESSION_KEY_OID},
+ gss_krb5int_inq_session_key
+ },
+ {
+ {GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID},
+ gss_krb5int_export_lucid_sec_context
+ },
+ {
+ {GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID},
+ gss_krb5int_extract_authtime_from_sec_context
+ }
+};
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_sec_context_by_oid (OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ size_t i;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ if (desired_object == GSS_C_NO_OID)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (data_set == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *data_set = GSS_C_NO_BUFFER_SET;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ if (ctx->terminated || !ctx->established)
+ return GSS_S_NO_CONTEXT;
+
+ for (i = 0; i < sizeof(krb5_gss_inquire_sec_context_by_oid_ops)/
+ sizeof(krb5_gss_inquire_sec_context_by_oid_ops[0]); i++) {
+ if (g_OID_prefix_equal(desired_object, &krb5_gss_inquire_sec_context_by_oid_ops[i].oid)) {
+ return (*krb5_gss_inquire_sec_context_by_oid_ops[i].func)(minor_status,
+ context_handle,
+ desired_object,
+ data_set);
+ }
+ }
+
+ *minor_status = EINVAL;
+
+ return GSS_S_UNAVAILABLE;
+}
+
+/*
+ * gss_inquire_cred_by_oid() methods
+ */
+#if 0
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*func)(OM_uint32 *, const gss_cred_id_t, const gss_OID, gss_buffer_set_t *);
+} krb5_gss_inquire_cred_by_oid_ops[] = {
+};
+#endif
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status,
+ const gss_cred_id_t cred_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ OM_uint32 major_status = GSS_S_FAILURE;
+#if 0
+ size_t i;
+#endif
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ if (desired_object == GSS_C_NO_OID)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (data_set == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *data_set = GSS_C_NO_BUFFER_SET;
+ if (cred_handle == GSS_C_NO_CREDENTIAL) {
+ *minor_status = (OM_uint32)KRB5_NOCREDS_SUPPLIED;
+ return GSS_S_NO_CRED;
+ }
+
+ major_status = krb5_gss_validate_cred(minor_status, cred_handle);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+#if 0
+ for (i = 0; i < sizeof(krb5_gss_inquire_cred_by_oid_ops)/
+ sizeof(krb5_gss_inquire_cred_by_oid_ops[0]); i++) {
+ if (g_OID_prefix_equal(desired_object, &krb5_gss_inquire_cred_by_oid_ops[i].oid)) {
+ return (*krb5_gss_inquire_cred_by_oid_ops[i].func)(minor_status,
+ cred_handle,
+ desired_object,
+ data_set);
+ }
+ }
+#endif
+
+ *minor_status = EINVAL;
+
+ return GSS_S_UNAVAILABLE;
+}
+
+/*
+ * gss_set_sec_context_option() methods
+ * (Disabled until we have something to populate the array.)
+ */
+#if 0
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*func)(OM_uint32 *, gss_ctx_id_t *, const gss_OID, const gss_buffer_t);
+} krb5_gss_set_sec_context_option_ops[] = {
+};
+#endif
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_set_sec_context_option (OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+#if 0
+ size_t i;
+#endif
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ if (context_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (desired_object == GSS_C_NO_OID)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+#if 0
+ for (i = 0; i < sizeof(krb5_gss_set_sec_context_option_ops)/
+ sizeof(krb5_gss_set_sec_context_option_ops[0]); i++) {
+ if (g_OID_prefix_equal(desired_object, &krb5_gss_set_sec_context_option_ops[i].oid)) {
+ return (*krb5_gss_set_sec_context_option_ops[i].func)(minor_status,
+ context_handle,
+ desired_object,
+ value);
+ }
+ }
+#endif
+
+ *minor_status = EINVAL;
+
+ return GSS_S_UNAVAILABLE;
+}
+
+static OM_uint32
+no_ci_flags(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_oid,
+ const gss_buffer_t value)
+{
+ krb5_gss_cred_id_t cred;
+
+ cred = (krb5_gss_cred_id_t) *cred_handle;
+ cred->suppress_ci_flags = 1;
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+/*
+ * gssspi_set_cred_option() methods
+ */
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*func)(OM_uint32 *, gss_cred_id_t *, const gss_OID, const gss_buffer_t);
+} krb5_gssspi_set_cred_option_ops[] = {
+ {
+ {GSS_KRB5_COPY_CCACHE_OID_LENGTH, GSS_KRB5_COPY_CCACHE_OID},
+ gss_krb5int_copy_ccache
+ },
+ {
+ {GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID_LENGTH, GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID},
+ gss_krb5int_set_allowable_enctypes
+ },
+ {
+ {GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH, GSS_KRB5_SET_CRED_RCACHE_OID},
+ gss_krb5int_set_cred_rcache
+ },
+ {
+ {GSS_KRB5_IMPORT_CRED_OID_LENGTH, GSS_KRB5_IMPORT_CRED_OID},
+ gss_krb5int_import_cred
+ },
+ {
+ {NO_CI_FLAGS_X_OID_LENGTH, NO_CI_FLAGS_X_OID},
+ no_ci_flags
+ },
+};
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gssspi_set_cred_option(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ OM_uint32 major_status = GSS_S_FAILURE;
+ size_t i;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (cred_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ if (desired_object == GSS_C_NO_OID)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (*cred_handle != GSS_C_NO_CREDENTIAL) {
+ major_status = krb5_gss_validate_cred(minor_status, *cred_handle);
+ if (GSS_ERROR(major_status))
+ return major_status;
+ }
+
+ for (i = 0; i < sizeof(krb5_gssspi_set_cred_option_ops)/
+ sizeof(krb5_gssspi_set_cred_option_ops[0]); i++) {
+ if (g_OID_prefix_equal(desired_object, &krb5_gssspi_set_cred_option_ops[i].oid)) {
+ return (*krb5_gssspi_set_cred_option_ops[i].func)(minor_status,
+ cred_handle,
+ desired_object,
+ value);
+ }
+ }
+
+ *minor_status = EINVAL;
+
+ return GSS_S_UNAVAILABLE;
+}
+
+/*
+ * gssspi_mech_invoke() methods
+ */
+static struct {
+ gss_OID_desc oid;
+ OM_uint32 (*func)(OM_uint32 *, const gss_OID, const gss_OID, gss_buffer_t);
+} krb5_gssspi_mech_invoke_ops[] = {
+ {
+ {GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID_LENGTH, GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID},
+ gss_krb5int_register_acceptor_identity
+ },
+ {
+ {GSS_KRB5_CCACHE_NAME_OID_LENGTH, GSS_KRB5_CCACHE_NAME_OID},
+ gss_krb5int_ccache_name
+ },
+ {
+ {GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID},
+ gss_krb5int_free_lucid_sec_context
+ },
+#ifndef _WIN32
+ {
+ {GSS_KRB5_USE_KDC_CONTEXT_OID_LENGTH, GSS_KRB5_USE_KDC_CONTEXT_OID},
+ krb5int_gss_use_kdc_context
+ },
+#endif
+};
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gssspi_mech_invoke (OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ const gss_OID desired_object,
+ gss_buffer_t value)
+{
+ size_t i;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *minor_status = 0;
+
+ if (desired_mech == GSS_C_NO_OID)
+ return GSS_S_BAD_MECH;
+
+ if (desired_object == GSS_C_NO_OID)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ for (i = 0; i < sizeof(krb5_gssspi_mech_invoke_ops)/
+ sizeof(krb5_gssspi_mech_invoke_ops[0]); i++) {
+ if (g_OID_prefix_equal(desired_object, &krb5_gssspi_mech_invoke_ops[i].oid)) {
+ return (*krb5_gssspi_mech_invoke_ops[i].func)(minor_status,
+ desired_mech,
+ desired_object,
+ value);
+ }
+ }
+
+ *minor_status = EINVAL;
+
+ return GSS_S_UNAVAILABLE;
+}
+
+#define GS2_KRB5_SASL_NAME "GS2-KRB5"
+#define GS2_KRB5_SASL_NAME_LEN (sizeof(GS2_KRB5_SASL_NAME) - 1)
+
+#define GS2_IAKERB_SASL_NAME "GS2-IAKERB"
+#define GS2_IAKERB_SASL_NAME_LEN (sizeof(GS2_IAKERB_SASL_NAME) - 1)
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_mech_for_saslname(OM_uint32 *minor_status,
+ const gss_buffer_t sasl_mech_name,
+ gss_OID *mech_type)
+{
+ *minor_status = 0;
+
+ if (sasl_mech_name->length == GS2_KRB5_SASL_NAME_LEN &&
+ memcmp(sasl_mech_name->value,
+ GS2_KRB5_SASL_NAME, GS2_KRB5_SASL_NAME_LEN) == 0) {
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_krb5;
+ return GSS_S_COMPLETE;
+ } else if (sasl_mech_name->length == GS2_IAKERB_SASL_NAME_LEN &&
+ memcmp(sasl_mech_name->value,
+ GS2_IAKERB_SASL_NAME, GS2_IAKERB_SASL_NAME_LEN) == 0) {
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_iakerb;
+ return GSS_S_COMPLETE;
+ }
+
+ return GSS_S_BAD_MECH;
+}
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_saslname_for_mech(OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ gss_buffer_t sasl_mech_name,
+ gss_buffer_t mech_name,
+ gss_buffer_t mech_description)
+{
+ if (g_OID_equal(desired_mech, gss_mech_iakerb)) {
+ if (!g_make_string_buffer(GS2_IAKERB_SASL_NAME, sasl_mech_name) ||
+ !g_make_string_buffer("iakerb", mech_name) ||
+ !g_make_string_buffer("Initial and Pass Through Authentication "
+ "Kerberos Mechanism (IAKERB)",
+ mech_description))
+ goto fail;
+ } else {
+ if (!g_make_string_buffer(GS2_KRB5_SASL_NAME, sasl_mech_name) ||
+ !g_make_string_buffer("krb5", mech_name) ||
+ !g_make_string_buffer("Kerberos 5 GSS-API Mechanism",
+ mech_description))
+ goto fail;
+ }
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+
+fail:
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+}
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_attrs_for_mech(OM_uint32 *minor_status,
+ gss_const_OID mech,
+ gss_OID_set *mech_attrs,
+ gss_OID_set *known_mech_attrs)
+{
+ OM_uint32 major, tmpMinor;
+
+ if (mech_attrs == NULL) {
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+ }
+
+ major = gss_create_empty_oid_set(minor_status, mech_attrs);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+#define MA_SUPPORTED(ma) do { \
+ major = gss_add_oid_set_member(minor_status, (gss_OID)ma, \
+ mech_attrs); \
+ if (GSS_ERROR(major)) \
+ goto cleanup; \
+ } while (0)
+
+ MA_SUPPORTED(GSS_C_MA_MECH_CONCRETE);
+ MA_SUPPORTED(GSS_C_MA_ITOK_FRAMED);
+ MA_SUPPORTED(GSS_C_MA_AUTH_INIT);
+ MA_SUPPORTED(GSS_C_MA_AUTH_TARG);
+ MA_SUPPORTED(GSS_C_MA_DELEG_CRED);
+ MA_SUPPORTED(GSS_C_MA_INTEG_PROT);
+ MA_SUPPORTED(GSS_C_MA_CONF_PROT);
+ MA_SUPPORTED(GSS_C_MA_MIC);
+ MA_SUPPORTED(GSS_C_MA_WRAP);
+ MA_SUPPORTED(GSS_C_MA_PROT_READY);
+ MA_SUPPORTED(GSS_C_MA_REPLAY_DET);
+ MA_SUPPORTED(GSS_C_MA_OOS_DET);
+ MA_SUPPORTED(GSS_C_MA_CBINDINGS);
+ MA_SUPPORTED(GSS_C_MA_CTX_TRANS);
+
+ if (g_OID_equal(mech, gss_mech_iakerb)) {
+ MA_SUPPORTED(GSS_C_MA_AUTH_INIT_INIT);
+ MA_SUPPORTED(GSS_C_MA_NOT_DFLT_MECH);
+ } else if (!g_OID_equal(mech, gss_mech_krb5)) {
+ MA_SUPPORTED(GSS_C_MA_DEPRECATED);
+ }
+
+cleanup:
+ if (GSS_ERROR(major))
+ gss_release_oid_set(&tmpMinor, mech_attrs);
+
+ return major;
+}
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gss_localname(OM_uint32 *minor,
+ const gss_name_t pname,
+ const gss_const_OID mech_type,
+ gss_buffer_t localname)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ char lname[BUFSIZ];
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)pname;
+
+ code = krb5_aname_to_localname(context, kname->princ,
+ sizeof(lname), lname);
+ if (code != 0) {
+ *minor = KRB5_NO_LOCALNAME;
+ krb5_free_context(context);
+ return GSS_S_FAILURE;
+ }
+
+
+ krb5_free_context(context);
+ localname->value = gssalloc_strdup(lname);
+ localname->length = strlen(lname);
+
+ return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
+
+
+static OM_uint32 KRB5_CALLCONV
+krb5_gss_authorize_localname(OM_uint32 *minor,
+ const gss_name_t pname,
+ gss_const_buffer_t local_user,
+ gss_const_OID name_type)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ char *user;
+ int user_ok;
+
+ if (name_type != GSS_C_NO_OID &&
+ !g_OID_equal(name_type, GSS_C_NT_USER_NAME)) {
+ return GSS_S_BAD_NAMETYPE;
+ }
+
+ kname = (krb5_gss_name_t)pname;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_FAILURE;
+ }
+
+ user = k5memdup0(local_user->value, local_user->length, &code);
+ if (user == NULL) {
+ *minor = code;
+ krb5_free_context(context);
+ return GSS_S_FAILURE;
+ }
+
+ user_ok = krb5_kuserok(context, kname->princ, user);
+
+ free(user);
+ krb5_free_context(context);
+
+ *minor = 0;
+ return user_ok ? GSS_S_COMPLETE : GSS_S_UNAUTHORIZED;
+}
+
+static struct gss_config krb5_mechanism = {
+ { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
+ NULL,
+ krb5_gss_acquire_cred,
+ krb5_gss_release_cred,
+ krb5_gss_init_sec_context,
+#ifdef LEAN_CLIENT
+ NULL,
+#else
+ krb5_gss_accept_sec_context,
+#endif
+ krb5_gss_process_context_token,
+ krb5_gss_delete_sec_context,
+ krb5_gss_context_time,
+ krb5_gss_get_mic,
+ krb5_gss_verify_mic,
+#if defined(IOV_SHIM_EXERCISE_WRAP) || defined(IOV_SHIM_EXERCISE)
+ NULL,
+#else
+ krb5_gss_wrap,
+#endif
+#if defined(IOV_SHIM_EXERCISE_UNWRAP) || defined(IOV_SHIM_EXERCISE)
+ NULL,
+#else
+ krb5_gss_unwrap,
+#endif
+ krb5_gss_display_status,
+ krb5_gss_indicate_mechs,
+ krb5_gss_compare_name,
+ krb5_gss_display_name,
+ krb5_gss_import_name,
+ krb5_gss_release_name,
+ krb5_gss_inquire_cred,
+ NULL, /* add_cred */
+#ifdef LEAN_CLIENT
+ NULL,
+ NULL,
+#else
+ krb5_gss_export_sec_context,
+ krb5_gss_import_sec_context,
+#endif
+ krb5_gss_inquire_cred_by_mech,
+ krb5_gss_inquire_names_for_mech,
+ krb5_gss_inquire_context,
+ krb5_gss_internal_release_oid,
+ krb5_gss_wrap_size_limit,
+ krb5_gss_localname,
+
+ krb5_gss_authorize_localname,
+ krb5_gss_export_name,
+ krb5_gss_duplicate_name,
+ krb5_gss_store_cred,
+ krb5_gss_inquire_sec_context_by_oid,
+ krb5_gss_inquire_cred_by_oid,
+ krb5_gss_set_sec_context_option,
+ krb5_gssspi_set_cred_option,
+ krb5_gssspi_mech_invoke,
+ NULL, /* wrap_aead */
+ NULL, /* unwrap_aead */
+ krb5_gss_wrap_iov,
+ krb5_gss_unwrap_iov,
+ krb5_gss_wrap_iov_length,
+ NULL, /* complete_auth_token */
+ krb5_gss_acquire_cred_impersonate_name,
+ NULL, /* krb5_gss_add_cred_impersonate_name */
+ NULL, /* display_name_ext */
+ krb5_gss_inquire_name,
+ krb5_gss_get_name_attribute,
+ krb5_gss_set_name_attribute,
+ krb5_gss_delete_name_attribute,
+ krb5_gss_export_name_composite,
+ krb5_gss_map_name_to_any,
+ krb5_gss_release_any_name_mapping,
+ krb5_gss_pseudo_random,
+ NULL, /* set_neg_mechs */
+ krb5_gss_inquire_saslname_for_mech,
+ krb5_gss_inquire_mech_for_saslname,
+ krb5_gss_inquire_attrs_for_mech,
+ krb5_gss_acquire_cred_from,
+ krb5_gss_store_cred_into,
+ krb5_gss_acquire_cred_with_password,
+ krb5_gss_export_cred,
+ krb5_gss_import_cred,
+ NULL, /* import_sec_context_by_mech */
+ NULL, /* import_name_by_mech */
+ NULL, /* import_cred_by_mech */
+ krb5_gss_get_mic_iov,
+ krb5_gss_verify_mic_iov,
+ krb5_gss_get_mic_iov_length,
+};
+
+/* Functions which use security contexts or acquire creds are IAKERB-specific;
+ * other functions can borrow from the krb5 mech. */
+static struct gss_config iakerb_mechanism = {
+ { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
+ NULL,
+ iakerb_gss_acquire_cred,
+ krb5_gss_release_cred,
+ iakerb_gss_init_sec_context,
+#ifdef LEAN_CLIENT
+ NULL,
+#else
+ iakerb_gss_accept_sec_context,
+#endif
+ iakerb_gss_process_context_token,
+ iakerb_gss_delete_sec_context,
+ iakerb_gss_context_time,
+ iakerb_gss_get_mic,
+ iakerb_gss_verify_mic,
+#if defined(IOV_SHIM_EXERCISE_WRAP) || defined(IOV_SHIM_EXERCISE)
+ NULL,
+#else
+ iakerb_gss_wrap,
+#endif
+#if defined(IOV_SHIM_EXERCISE_UNWRAP) || defined(IOV_SHIM_EXERCISE)
+ NULL,
+#else
+ iakerb_gss_unwrap,
+#endif
+ krb5_gss_display_status,
+ krb5_gss_indicate_mechs,
+ krb5_gss_compare_name,
+ krb5_gss_display_name,
+ krb5_gss_import_name,
+ krb5_gss_release_name,
+ krb5_gss_inquire_cred,
+ NULL, /* add_cred */
+#ifdef LEAN_CLIENT
+ NULL,
+ NULL,
+#else
+ iakerb_gss_export_sec_context,
+ iakerb_gss_import_sec_context,
+#endif
+ krb5_gss_inquire_cred_by_mech,
+ krb5_gss_inquire_names_for_mech,
+ iakerb_gss_inquire_context,
+ krb5_gss_internal_release_oid,
+ iakerb_gss_wrap_size_limit,
+ krb5_gss_localname,
+ krb5_gss_authorize_localname,
+ krb5_gss_export_name,
+ krb5_gss_duplicate_name,
+ krb5_gss_store_cred,
+ iakerb_gss_inquire_sec_context_by_oid,
+ krb5_gss_inquire_cred_by_oid,
+ iakerb_gss_set_sec_context_option,
+ krb5_gssspi_set_cred_option,
+ krb5_gssspi_mech_invoke,
+ NULL, /* wrap_aead */
+ NULL, /* unwrap_aead */
+ iakerb_gss_wrap_iov,
+ iakerb_gss_unwrap_iov,
+ iakerb_gss_wrap_iov_length,
+ NULL, /* complete_auth_token */
+ NULL, /* acquire_cred_impersonate_name */
+ NULL, /* add_cred_impersonate_name */
+ NULL, /* display_name_ext */
+ krb5_gss_inquire_name,
+ krb5_gss_get_name_attribute,
+ krb5_gss_set_name_attribute,
+ krb5_gss_delete_name_attribute,
+ krb5_gss_export_name_composite,
+ krb5_gss_map_name_to_any,
+ krb5_gss_release_any_name_mapping,
+ iakerb_gss_pseudo_random,
+ NULL, /* set_neg_mechs */
+ krb5_gss_inquire_saslname_for_mech,
+ krb5_gss_inquire_mech_for_saslname,
+ krb5_gss_inquire_attrs_for_mech,
+ krb5_gss_acquire_cred_from,
+ krb5_gss_store_cred_into,
+ iakerb_gss_acquire_cred_with_password,
+ krb5_gss_export_cred,
+ krb5_gss_import_cred,
+ NULL, /* import_sec_context_by_mech */
+ NULL, /* import_name_by_mech */
+ NULL, /* import_cred_by_mech */
+ iakerb_gss_get_mic_iov,
+ iakerb_gss_verify_mic_iov,
+ iakerb_gss_get_mic_iov_length,
+};
+
+#ifdef _GSS_STATIC_LINK
+#include "mglueP.h"
+static int gss_iakerbmechglue_init(void)
+{
+ struct gss_mech_config mech_iakerb;
+
+ memset(&mech_iakerb, 0, sizeof(mech_iakerb));
+ mech_iakerb.mech = &iakerb_mechanism;
+
+ mech_iakerb.mechNameStr = "iakerb";
+ mech_iakerb.mech_type = (gss_OID)gss_mech_iakerb;
+ gssint_register_mechinfo(&mech_iakerb);
+
+ return 0;
+}
+
+static int gss_krb5mechglue_init(void)
+{
+ struct gss_mech_config mech_krb5;
+
+ memset(&mech_krb5, 0, sizeof(mech_krb5));
+ mech_krb5.mech = &krb5_mechanism;
+
+ mech_krb5.mechNameStr = "kerberos_v5";
+ mech_krb5.mech_type = (gss_OID)gss_mech_krb5;
+ gssint_register_mechinfo(&mech_krb5);
+
+ mech_krb5.mechNameStr = "kerberos_v5_old";
+ mech_krb5.mech_type = (gss_OID)gss_mech_krb5_old;
+ gssint_register_mechinfo(&mech_krb5);
+
+ mech_krb5.mechNameStr = "mskrb";
+ mech_krb5.mech_type = (gss_OID)gss_mech_krb5_wrong;
+ gssint_register_mechinfo(&mech_krb5);
+
+ return 0;
+}
+#else
+MAKE_INIT_FUNCTION(gss_krb5int_lib_init);
+MAKE_FINI_FUNCTION(gss_krb5int_lib_fini);
+
+gss_mechanism KRB5_CALLCONV
+gss_mech_initialize(void)
+{
+ return &krb5_mechanism;
+}
+#endif /* _GSS_STATIC_LINK */
+
+int gss_krb5int_lib_init(void)
+{
+ int err;
+
+#ifdef SHOW_INITFINI_FUNCS
+ printf("gss_krb5int_lib_init\n");
+#endif
+
+ add_error_table(&et_k5g_error_table);
+
+#ifndef LEAN_CLIENT
+ err = k5_mutex_finish_init(&gssint_krb5_keytab_lock);
+ if (err)
+ return err;
+#endif /* LEAN_CLIENT */
+ err = k5_key_register(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME, free);
+ if (err)
+ return err;
+ err = k5_key_register(K5_KEY_GSS_KRB5_CCACHE_NAME, free);
+ if (err)
+ return err;
+ err = k5_key_register(K5_KEY_GSS_KRB5_ERROR_MESSAGE,
+ krb5_gss_delete_error_info);
+ if (err)
+ return err;
+#ifndef _WIN32
+ err = k5_mutex_finish_init(&kg_kdc_flag_mutex);
+ if (err)
+ return err;
+ err = k5_mutex_finish_init(&kg_vdb.mutex);
+ if (err)
+ return err;
+#endif
+#ifdef _GSS_STATIC_LINK
+ err = gss_krb5mechglue_init();
+ if (err)
+ return err;
+ err = gss_iakerbmechglue_init();
+ if (err)
+ return err;
+#endif
+
+ return 0;
+}
+
+void gss_krb5int_lib_fini(void)
+{
+#ifndef _GSS_STATIC_LINK
+ if (!INITIALIZER_RAN(gss_krb5int_lib_init) || PROGRAM_EXITING()) {
+# ifdef SHOW_INITFINI_FUNCS
+ printf("gss_krb5int_lib_fini: skipping\n");
+# endif
+ return;
+ }
+#endif
+#ifdef SHOW_INITFINI_FUNCS
+ printf("gss_krb5int_lib_fini\n");
+#endif
+ remove_error_table(&et_k5g_error_table);
+
+ k5_key_delete(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME);
+ k5_key_delete(K5_KEY_GSS_KRB5_CCACHE_NAME);
+ k5_key_delete(K5_KEY_GSS_KRB5_ERROR_MESSAGE);
+ k5_mutex_destroy(&kg_vdb.mutex);
+#ifndef _WIN32
+ k5_mutex_destroy(&kg_kdc_flag_mutex);
+#endif
+#ifndef LEAN_CLIENT
+ k5_mutex_destroy(&gssint_krb5_keytab_lock);
+#endif /* LEAN_CLIENT */
+}
+
+#ifdef _GSS_STATIC_LINK
+extern OM_uint32 gssint_lib_init(void);
+#endif
+
+OM_uint32 gss_krb5int_initialize_library (void)
+{
+#ifdef _GSS_STATIC_LINK
+ return gssint_mechglue_initialize_library();
+#else
+ return CALL_INIT_FUNCTION(gss_krb5int_lib_init);
+#endif
+}
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.h b/src/lib/gssapi/krb5/gssapi_krb5.h
new file mode 100644
index 000000000000..390b00032cce
--- /dev/null
+++ b/src/lib/gssapi/krb5/gssapi_krb5.h
@@ -0,0 +1,281 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _GSSAPI_KRB5_H_
+#define _GSSAPI_KRB5_H_
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_ext.h>
+#include <krb5.h>
+#include <stdint.h>
+
+/* C++ friendlyness */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Reserved static storage for GSS_oids. See rfc 1964 for more details. */
+
+/* 2.1.1. Kerberos Principal Name Form: */
+GSS_DLLIMP extern const gss_OID GSS_KRB5_NT_PRINCIPAL_NAME;
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_name(1)}. The recommended symbolic name for this type
+ * is "GSS_KRB5_NT_PRINCIPAL_NAME". */
+
+/* 2.1.2. Host-Based Service Name Form */
+#define GSS_KRB5_NT_HOSTBASED_SERVICE_NAME GSS_C_NT_HOSTBASED_SERVICE
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) service_name(4)}. The previously recommended symbolic
+ * name for this type is "GSS_KRB5_NT_HOSTBASED_SERVICE_NAME". The
+ * currently preferred symbolic name for this type is
+ * "GSS_C_NT_HOSTBASED_SERVICE". */
+
+/* 2.2.1. User Name Form */
+#define GSS_KRB5_NT_USER_NAME GSS_C_NT_USER_NAME
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) user_name(1)}. The recommended symbolic name for this
+ * type is "GSS_KRB5_NT_USER_NAME". */
+
+/* 2.2.2. Machine UID Form */
+#define GSS_KRB5_NT_MACHINE_UID_NAME GSS_C_NT_MACHINE_UID_NAME
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) machine_uid_name(2)}. The recommended symbolic name for
+ * this type is "GSS_KRB5_NT_MACHINE_UID_NAME". */
+
+/* 2.2.3. String UID Form */
+#define GSS_KRB5_NT_STRING_UID_NAME GSS_C_NT_STRING_UID_NAME
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) string_uid_name(3)}. The recommended symbolic name for
+ * this type is "GSS_KRB5_NT_STRING_UID_NAME". */
+
+GSS_DLLIMP extern const gss_OID gss_mech_krb5;
+GSS_DLLIMP extern const gss_OID gss_mech_krb5_old;
+GSS_DLLIMP extern const gss_OID gss_mech_krb5_wrong;
+GSS_DLLIMP extern const gss_OID gss_mech_iakerb;
+GSS_DLLIMP extern const gss_OID_set gss_mech_set_krb5;
+GSS_DLLIMP extern const gss_OID_set gss_mech_set_krb5_old;
+GSS_DLLIMP extern const gss_OID_set gss_mech_set_krb5_both;
+
+GSS_DLLIMP extern const gss_OID gss_nt_krb5_name;
+GSS_DLLIMP extern const gss_OID gss_nt_krb5_principal;
+
+GSS_DLLIMP extern const gss_OID_desc krb5_gss_oid_array[];
+
+/*
+ * This OID can be used with gss_set_cred_option() to suppress the
+ * confidentiality and integrity flags from being asserted in initial context
+ * tokens.
+ *
+ * iso(1) member-body(2) Sweden(752) Stockholm University(43) Heimdal GSS-API
+ * Extensions(13) no_ci_flags(29)
+ */
+GSS_DLLIMP extern const gss_OID GSS_KRB5_CRED_NO_CI_FLAGS_X;
+
+#define gss_krb5_nt_general_name gss_nt_krb5_name
+#define gss_krb5_nt_principal gss_nt_krb5_principal
+#define gss_krb5_nt_service_name gss_nt_service_name
+#define gss_krb5_nt_user_name gss_nt_user_name
+#define gss_krb5_nt_machine_uid_name gss_nt_machine_uid_name
+#define gss_krb5_nt_string_uid_name gss_nt_string_uid_name
+
+typedef struct gss_krb5_lucid_key {
+ OM_uint32 type; /* key encryption type */
+ OM_uint32 length; /* length of key data */
+ void * data; /* actual key data */
+} gss_krb5_lucid_key_t;
+
+typedef struct gss_krb5_rfc1964_keydata {
+ OM_uint32 sign_alg; /* signing algorthm */
+ OM_uint32 seal_alg; /* seal/encrypt algorithm */
+ gss_krb5_lucid_key_t ctx_key;
+ /* Context key
+ (Kerberos session key or subkey) */
+} gss_krb5_rfc1964_keydata_t;
+
+typedef struct gss_krb5_cfx_keydata {
+ OM_uint32 have_acceptor_subkey;
+ /* 1 if there is an acceptor_subkey
+ present, 0 otherwise */
+ gss_krb5_lucid_key_t ctx_key;
+ /* Context key
+ (Kerberos session key or subkey) */
+ gss_krb5_lucid_key_t acceptor_subkey;
+ /* acceptor-asserted subkey or
+ 0's if no acceptor subkey */
+} gss_krb5_cfx_keydata_t;
+
+typedef struct gss_krb5_lucid_context_v1 {
+ OM_uint32 version; /* Structure version number (1)
+ MUST be at beginning of struct! */
+ OM_uint32 initiate; /* Are we the initiator? */
+ OM_uint32 endtime; /* expiration time of context */
+ uint64_t send_seq; /* sender sequence number */
+ uint64_t recv_seq; /* receive sequence number */
+ OM_uint32 protocol; /* 0: rfc1964,
+ 1: draft-ietf-krb-wg-gssapi-cfx-07 */
+ /*
+ * if (protocol == 0) rfc1964_kd should be used
+ * and cfx_kd contents are invalid and should be zero
+ * if (protocol == 1) cfx_kd should be used
+ * and rfc1964_kd contents are invalid and should be zero
+ */
+ gss_krb5_rfc1964_keydata_t rfc1964_kd;
+ gss_krb5_cfx_keydata_t cfx_kd;
+} gss_krb5_lucid_context_v1_t;
+
+/*
+ * Mask for determining the version of a lucid context structure. Callers
+ * should not require this.
+ */
+typedef struct gss_krb5_lucid_context_version {
+ OM_uint32 version; /* Structure version number */
+} gss_krb5_lucid_context_version_t;
+
+
+
+
+/* Alias for Heimdal compat. */
+#define gsskrb5_register_acceptor_identity krb5_gss_register_acceptor_identity
+
+OM_uint32 KRB5_CALLCONV krb5_gss_register_acceptor_identity(const char *);
+
+OM_uint32 KRB5_CALLCONV gss_krb5_get_tkt_flags(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ krb5_flags *ticket_flags);
+
+OM_uint32 KRB5_CALLCONV gss_krb5_copy_ccache(
+ OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ krb5_ccache out_ccache);
+
+OM_uint32 KRB5_CALLCONV gss_krb5_ccache_name(
+ OM_uint32 *minor_status, const char *name,
+ const char **out_name);
+
+/*
+ * gss_krb5_set_allowable_enctypes
+ *
+ * This function may be called by a context initiator after calling
+ * gss_acquire_cred(), but before calling gss_init_sec_context(),
+ * to restrict the set of enctypes which will be negotiated during
+ * context establishment to those in the provided array.
+ *
+ * 'cred' must be a valid credential handle obtained via
+ * gss_acquire_cred(). It may not be GSS_C_NO_CREDENTIAL.
+ * gss_acquire_cred() may have been called to get a handle to
+ * the default credential.
+ *
+ * The purpose of this function is to limit the keys that may
+ * be exported via gss_krb5_export_lucid_sec_context(); thus it
+ * should limit the enctypes of all keys that will be needed
+ * after the security context has been established.
+ * (i.e. context establishment may use a session key with a
+ * stronger enctype than in the provided array, however a
+ * subkey must be established within the enctype limits
+ * established by this function.)
+ *
+ */
+OM_uint32 KRB5_CALLCONV
+gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ OM_uint32 num_ktypes,
+ krb5_enctype *ktypes);
+
+/*
+ * Returns a non-opaque (lucid) version of the internal context
+ * information.
+ *
+ * Note that context_handle must not be used again by the caller
+ * after this call. The GSS implementation is free to release any
+ * resources associated with the original context. It is up to the
+ * GSS implementation whether it returns pointers to existing data,
+ * or copies of the data. The caller should treat the returned
+ * lucid context as read-only.
+ *
+ * The caller must call gss_krb5_free_lucid_context() to free
+ * the context and allocated resources when it is finished with it.
+ *
+ * 'version' is an integer indicating the requested version of the lucid
+ * context. If the implementation does not understand the requested version,
+ * it will return an error.
+ *
+ * For example:
+ * void *return_ctx;
+ * gss_krb5_lucid_context_v1_t *ctx;
+ * OM_uint32 min_stat, maj_stat;
+ * OM_uint32 vers;
+ * gss_ctx_id_t *ctx_handle;
+ *
+ * maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
+ * ctx_handle, 1, &return_ctx);
+ * // Verify success
+ * ctx = (gss_krb5_lucid_context_v1_t *) return_ctx;
+ */
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ OM_uint32 version,
+ void **kctx);
+
+/*
+ * Frees the allocated storage associated with an
+ * exported struct gss_krb5_lucid_context.
+ */
+OM_uint32 KRB5_CALLCONV
+gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status,
+ void *kctx);
+
+
+OM_uint32 KRB5_CALLCONV
+gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int ad_type,
+ gss_buffer_t ad_data);
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_set_cred_rcache(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ krb5_rcache rcache);
+
+OM_uint32 KRB5_CALLCONV
+gsskrb5_extract_authtime_from_sec_context(OM_uint32 *, gss_ctx_id_t, krb5_timestamp *);
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_import_cred(OM_uint32 *minor_status,
+ krb5_ccache id,
+ krb5_principal keytab_principal,
+ krb5_keytab keytab,
+ gss_cred_id_t *cred);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _GSSAPI_KRB5_H_ */
diff --git a/src/lib/gssapi/krb5/iakerb.c b/src/lib/gssapi/krb5/iakerb.c
new file mode 100644
index 000000000000..2dc4d0c1a4d5
--- /dev/null
+++ b/src/lib/gssapi/krb5/iakerb.c
@@ -0,0 +1,1329 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+/*
+ * IAKERB implementation
+ */
+
+extern int gssint_get_der_length(unsigned char **, OM_uint32, unsigned int*);
+
+enum iakerb_state {
+ IAKERB_AS_REQ, /* acquiring ticket with initial creds */
+ IAKERB_TGS_REQ, /* acquiring ticket with TGT */
+ IAKERB_AP_REQ /* hand-off to normal GSS AP-REQ exchange */
+};
+
+struct _iakerb_ctx_id_rec {
+ krb5_magic magic; /* KG_IAKERB_CONTEXT */
+ krb5_context k5c;
+ gss_cred_id_t defcred; /* Initiator only */
+ enum iakerb_state state; /* Initiator only */
+ krb5_init_creds_context icc; /* Initiator only */
+ krb5_tkt_creds_context tcc; /* Initiator only */
+ gss_ctx_id_t gssc;
+ krb5_data conv; /* conversation for checksumming */
+ unsigned int count; /* number of round trips */
+ int initiate;
+ int established;
+ krb5_get_init_creds_opt *gic_opts;
+};
+
+#define IAKERB_MAX_HOPS ( 16 /* MAX_IN_TKT_LOOPS */ + KRB5_REFERRAL_MAXHOPS )
+
+typedef struct _iakerb_ctx_id_rec iakerb_ctx_id_rec;
+typedef iakerb_ctx_id_rec *iakerb_ctx_id_t;
+
+/*
+ * Release an IAKERB context
+ */
+static void
+iakerb_release_context(iakerb_ctx_id_t ctx)
+{
+ OM_uint32 tmp;
+
+ if (ctx == NULL)
+ return;
+
+ krb5_gss_release_cred(&tmp, &ctx->defcred);
+ krb5_init_creds_free(ctx->k5c, ctx->icc);
+ krb5_tkt_creds_free(ctx->k5c, ctx->tcc);
+ krb5_gss_delete_sec_context(&tmp, &ctx->gssc, NULL);
+ krb5_free_data_contents(ctx->k5c, &ctx->conv);
+ krb5_get_init_creds_opt_free(ctx->k5c, ctx->gic_opts);
+ krb5_free_context(ctx->k5c);
+ free(ctx);
+}
+
+/*
+ * Create a IAKERB-FINISHED structure containing a checksum of
+ * the entire IAKERB exchange.
+ */
+krb5_error_code
+iakerb_make_finished(krb5_context context,
+ krb5_key key,
+ const krb5_data *conv,
+ krb5_data **finished)
+{
+ krb5_error_code code;
+ krb5_iakerb_finished iaf;
+
+ *finished = NULL;
+
+ memset(&iaf, 0, sizeof(iaf));
+
+ if (key == NULL)
+ return KRB5KDC_ERR_NULL_KEY;
+
+ code = krb5_k_make_checksum(context, 0, key, KRB5_KEYUSAGE_IAKERB_FINISHED,
+ conv, &iaf.checksum);
+ if (code != 0)
+ return code;
+
+ code = encode_krb5_iakerb_finished(&iaf, finished);
+
+ krb5_free_checksum_contents(context, &iaf.checksum);
+
+ return code;
+}
+
+/*
+ * Verify a IAKERB-FINISHED structure submitted by the initiator
+ */
+krb5_error_code
+iakerb_verify_finished(krb5_context context,
+ krb5_key key,
+ const krb5_data *conv,
+ const krb5_data *finished)
+{
+ krb5_error_code code;
+ krb5_iakerb_finished *iaf;
+ krb5_boolean valid = FALSE;
+
+ if (key == NULL)
+ return KRB5KDC_ERR_NULL_KEY;
+
+ code = decode_krb5_iakerb_finished(finished, &iaf);
+ if (code != 0)
+ return code;
+
+ code = krb5_k_verify_checksum(context, key, KRB5_KEYUSAGE_IAKERB_FINISHED,
+ conv, &iaf->checksum, &valid);
+ if (code == 0 && valid == FALSE)
+ code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+
+ krb5_free_iakerb_finished(context, iaf);
+
+ return code;
+}
+
+/*
+ * Save a token for future checksumming.
+ */
+static krb5_error_code
+iakerb_save_token(iakerb_ctx_id_t ctx, const gss_buffer_t token)
+{
+ char *p;
+
+ p = realloc(ctx->conv.data, ctx->conv.length + token->length);
+ if (p == NULL)
+ return ENOMEM;
+
+ memcpy(p + ctx->conv.length, token->value, token->length);
+ ctx->conv.data = p;
+ ctx->conv.length += token->length;
+
+ return 0;
+}
+
+/*
+ * Parse a token into IAKERB-HEADER and KRB-KDC-REQ/REP
+ */
+static krb5_error_code
+iakerb_parse_token(iakerb_ctx_id_t ctx,
+ int initialContextToken,
+ const gss_buffer_t token,
+ krb5_data *realm,
+ krb5_data **cookie,
+ krb5_data *request)
+{
+ krb5_error_code code;
+ krb5_iakerb_header *iah = NULL;
+ unsigned int bodysize, lenlen;
+ int length;
+ unsigned char *ptr;
+ int flags = 0;
+ krb5_data data;
+
+ if (token == GSS_C_NO_BUFFER || token->length == 0) {
+ code = KRB5_BAD_MSIZE;
+ goto cleanup;
+ }
+
+ if (initialContextToken)
+ flags |= G_VFY_TOKEN_HDR_WRAPPER_REQUIRED;
+
+ ptr = token->value;
+
+ code = g_verify_token_header(gss_mech_iakerb,
+ &bodysize, &ptr,
+ IAKERB_TOK_PROXY,
+ token->length, flags);
+ if (code != 0)
+ goto cleanup;
+
+ data.data = (char *)ptr;
+
+ if (bodysize-- == 0 || *ptr++ != 0x30 /* SEQUENCE */) {
+ code = ASN1_BAD_ID;
+ goto cleanup;
+ }
+
+ length = gssint_get_der_length(&ptr, bodysize, &lenlen);
+ if (length < 0 || bodysize - lenlen < (unsigned int)length) {
+ code = KRB5_BAD_MSIZE;
+ goto cleanup;
+ }
+ data.length = 1 /* SEQUENCE */ + lenlen + length;
+
+ ptr += length;
+ bodysize -= (lenlen + length);
+
+ code = decode_krb5_iakerb_header(&data, &iah);
+ if (code != 0)
+ goto cleanup;
+
+ if (realm != NULL) {
+ *realm = iah->target_realm;
+ iah->target_realm.data = NULL;
+ }
+
+ if (cookie != NULL) {
+ *cookie = iah->cookie;
+ iah->cookie = NULL;
+ }
+
+ request->data = (char *)ptr;
+ request->length = bodysize;
+
+ assert(request->data + request->length ==
+ (char *)token->value + token->length);
+
+cleanup:
+ krb5_free_iakerb_header(ctx->k5c, iah);
+
+ return code;
+}
+
+/*
+ * Create a token from IAKERB-HEADER and KRB-KDC-REQ/REP
+ */
+static krb5_error_code
+iakerb_make_token(iakerb_ctx_id_t ctx,
+ krb5_data *realm,
+ krb5_data *cookie,
+ krb5_data *request,
+ int initialContextToken,
+ gss_buffer_t token)
+{
+ krb5_error_code code;
+ krb5_iakerb_header iah;
+ krb5_data *data = NULL;
+ char *p;
+ unsigned int tokenSize;
+ unsigned char *q;
+
+ token->value = NULL;
+ token->length = 0;
+
+ /*
+ * Assemble the IAKERB-HEADER from the realm and cookie
+ */
+ memset(&iah, 0, sizeof(iah));
+ iah.target_realm = *realm;
+ iah.cookie = cookie;
+
+ code = encode_krb5_iakerb_header(&iah, &data);
+ if (code != 0)
+ goto cleanup;
+
+ /*
+ * Concatenate Kerberos request.
+ */
+ p = realloc(data->data, data->length + request->length);
+ if (p == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ data->data = p;
+
+ if (request->length > 0)
+ memcpy(data->data + data->length, request->data, request->length);
+ data->length += request->length;
+
+ if (initialContextToken)
+ tokenSize = g_token_size(gss_mech_iakerb, data->length);
+ else
+ tokenSize = 2 + data->length;
+
+ token->value = q = gssalloc_malloc(tokenSize);
+ if (q == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ token->length = tokenSize;
+
+ if (initialContextToken) {
+ g_make_token_header(gss_mech_iakerb, data->length, &q,
+ IAKERB_TOK_PROXY);
+ } else {
+ store_16_be(IAKERB_TOK_PROXY, q);
+ q += 2;
+ }
+ memcpy(q, data->data, data->length);
+ q += data->length;
+
+ assert(q == (unsigned char *)token->value + token->length);
+
+cleanup:
+ krb5_free_data(ctx->k5c, data);
+
+ return code;
+}
+
+/*
+ * Parse the IAKERB token in input_token and send the contained KDC
+ * request to the KDC for the realm.
+ *
+ * Wrap the KDC reply in output_token.
+ */
+static krb5_error_code
+iakerb_acceptor_step(iakerb_ctx_id_t ctx,
+ int initialContextToken,
+ const gss_buffer_t input_token,
+ gss_buffer_t output_token)
+{
+ krb5_error_code code;
+ krb5_data request = empty_data(), reply = empty_data();
+ krb5_data realm = empty_data();
+ OM_uint32 tmp;
+ int tcp_only, use_master;
+ krb5_ui_4 kdc_code;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if (ctx->count >= IAKERB_MAX_HOPS) {
+ code = KRB5_KDC_UNREACH;
+ goto cleanup;
+ }
+
+ code = iakerb_parse_token(ctx, initialContextToken, input_token, &realm,
+ NULL, &request);
+ if (code != 0)
+ goto cleanup;
+
+ if (realm.length == 0 || request.length == 0) {
+ code = KRB5_BAD_MSIZE;
+ goto cleanup;
+ }
+
+ code = iakerb_save_token(ctx, input_token);
+ if (code != 0)
+ goto cleanup;
+
+ for (tcp_only = 0; tcp_only <= 1; tcp_only++) {
+ use_master = 0;
+ code = krb5_sendto_kdc(ctx->k5c, &request, &realm,
+ &reply, &use_master, tcp_only);
+ if (code == 0 && krb5_is_krb_error(&reply)) {
+ krb5_error *error;
+
+ code = decode_krb5_error(&reply, &error);
+ if (code != 0)
+ goto cleanup;
+ kdc_code = error->error;
+ krb5_free_error(ctx->k5c, error);
+ if (kdc_code == KRB_ERR_RESPONSE_TOO_BIG) {
+ krb5_free_data_contents(ctx->k5c, &reply);
+ reply = empty_data();
+ continue;
+ }
+ }
+ break;
+ }
+
+ if (code == KRB5_KDC_UNREACH || code == KRB5_REALM_UNKNOWN) {
+ krb5_error error;
+
+ memset(&error, 0, sizeof(error));
+ if (code == KRB5_KDC_UNREACH)
+ error.error = KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE;
+ else if (code == KRB5_REALM_UNKNOWN)
+ error.error = KRB_AP_ERR_IAKERB_KDC_NOT_FOUND;
+
+ code = krb5_mk_error(ctx->k5c, &error, &reply);
+ if (code != 0)
+ goto cleanup;
+ } else if (code != 0)
+ goto cleanup;
+
+ code = iakerb_make_token(ctx, &realm, NULL, &reply, 0, output_token);
+ if (code != 0)
+ goto cleanup;
+
+ code = iakerb_save_token(ctx, output_token);
+ if (code != 0)
+ goto cleanup;
+
+ ctx->count++;
+
+cleanup:
+ if (code != 0)
+ gss_release_buffer(&tmp, output_token);
+ /* request is a pointer into input_token, no need to free */
+ krb5_free_data_contents(ctx->k5c, &realm);
+ krb5_free_data_contents(ctx->k5c, &reply);
+
+ return code;
+}
+
+/*
+ * Initialise the krb5_init_creds context for the IAKERB context
+ */
+static krb5_error_code
+iakerb_init_creds_ctx(iakerb_ctx_id_t ctx,
+ krb5_gss_cred_id_t cred,
+ OM_uint32 time_req)
+{
+ krb5_error_code code;
+
+ if (cred->iakerb_mech == 0) {
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ assert(cred->name != NULL);
+ assert(cred->name->princ != NULL);
+
+ code = krb5_get_init_creds_opt_alloc(ctx->k5c, &ctx->gic_opts);
+ if (code != 0)
+ goto cleanup;
+
+ if (time_req != 0 && time_req != GSS_C_INDEFINITE)
+ krb5_get_init_creds_opt_set_tkt_life(ctx->gic_opts, time_req);
+
+ code = krb5_get_init_creds_opt_set_out_ccache(ctx->k5c, ctx->gic_opts,
+ cred->ccache);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_init_creds_init(ctx->k5c,
+ cred->name->princ,
+ NULL, /* prompter */
+ NULL, /* data */
+ 0, /* start_time */
+ ctx->gic_opts,
+ &ctx->icc);
+ if (code != 0)
+ goto cleanup;
+
+ if (cred->password != NULL) {
+ code = krb5_init_creds_set_password(ctx->k5c, ctx->icc,
+ cred->password);
+ } else if (cred->client_keytab != NULL) {
+ code = krb5_init_creds_set_keytab(ctx->k5c, ctx->icc,
+ cred->client_keytab);
+ } else {
+ code = KRB5_KT_NOTFOUND;
+ }
+ if (code != 0)
+ goto cleanup;
+
+cleanup:
+ return code;
+}
+
+/*
+ * Initialise the krb5_tkt_creds context for the IAKERB context
+ */
+static krb5_error_code
+iakerb_tkt_creds_ctx(iakerb_ctx_id_t ctx,
+ krb5_gss_cred_id_t cred,
+ krb5_gss_name_t name,
+ OM_uint32 time_req)
+
+{
+ krb5_error_code code;
+ krb5_creds creds;
+ krb5_timestamp now;
+
+ assert(cred->name != NULL);
+ assert(cred->name->princ != NULL);
+
+ memset(&creds, 0, sizeof(creds));
+
+ creds.client = cred->name->princ;
+ creds.server = name->princ;
+
+ if (time_req != 0 && time_req != GSS_C_INDEFINITE) {
+ code = krb5_timeofday(ctx->k5c, &now);
+ if (code != 0)
+ goto cleanup;
+
+ creds.times.endtime = now + time_req;
+ }
+
+ if (cred->name->ad_context != NULL) {
+ code = krb5_authdata_export_authdata(ctx->k5c,
+ cred->name->ad_context,
+ AD_USAGE_TGS_REQ,
+ &creds.authdata);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_tkt_creds_init(ctx->k5c, cred->ccache, &creds, 0, &ctx->tcc);
+ if (code != 0)
+ goto cleanup;
+
+cleanup:
+ krb5_free_authdata(ctx->k5c, creds.authdata);
+
+ return code;
+}
+
+/*
+ * Parse the IAKERB token in input_token and process the KDC
+ * response.
+ *
+ * Emit the next KDC request, if any, in output_token.
+ */
+static krb5_error_code
+iakerb_initiator_step(iakerb_ctx_id_t ctx,
+ krb5_gss_cred_id_t cred,
+ krb5_gss_name_t name,
+ OM_uint32 time_req,
+ const gss_buffer_t input_token,
+ gss_buffer_t output_token)
+{
+ krb5_error_code code = 0;
+ krb5_data in = empty_data(), out = empty_data(), realm = empty_data();
+ krb5_data *cookie = NULL;
+ OM_uint32 tmp;
+ unsigned int flags = 0;
+ krb5_ticket_times times;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if (input_token != GSS_C_NO_BUFFER) {
+ code = iakerb_parse_token(ctx, 0, input_token, NULL, &cookie, &in);
+ if (code != 0)
+ goto cleanup;
+
+ code = iakerb_save_token(ctx, input_token);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ switch (ctx->state) {
+ case IAKERB_AS_REQ:
+ if (ctx->icc == NULL) {
+ code = iakerb_init_creds_ctx(ctx, cred, time_req);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_init_creds_step(ctx->k5c, ctx->icc, &in, &out, &realm,
+ &flags);
+ if (code != 0) {
+ if (cred->have_tgt) {
+ /* We were trying to refresh; keep going with current creds. */
+ ctx->state = IAKERB_TGS_REQ;
+ krb5_clear_error_message(ctx->k5c);
+ } else {
+ goto cleanup;
+ }
+ } else if (!(flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE)) {
+ krb5_init_creds_get_times(ctx->k5c, ctx->icc, &times);
+ kg_cred_set_initial_refresh(ctx->k5c, cred, &times);
+ cred->expire = times.endtime;
+
+ krb5_init_creds_free(ctx->k5c, ctx->icc);
+ ctx->icc = NULL;
+
+ ctx->state = IAKERB_TGS_REQ;
+ } else
+ break;
+ in = empty_data();
+ /* Done with AS request; fall through to TGS request. */
+ case IAKERB_TGS_REQ:
+ if (ctx->tcc == NULL) {
+ code = iakerb_tkt_creds_ctx(ctx, cred, name, time_req);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_tkt_creds_step(ctx->k5c, ctx->tcc, &in, &out, &realm,
+ &flags);
+ if (code != 0)
+ goto cleanup;
+ if (!(flags & KRB5_TKT_CREDS_STEP_FLAG_CONTINUE)) {
+ krb5_tkt_creds_get_times(ctx->k5c, ctx->tcc, &times);
+ cred->expire = times.endtime;
+
+ krb5_tkt_creds_free(ctx->k5c, ctx->tcc);
+ ctx->tcc = NULL;
+
+ ctx->state = IAKERB_AP_REQ;
+ } else
+ break;
+ /* Done with TGS request; fall through to AP request. */
+ case IAKERB_AP_REQ:
+ break;
+ }
+
+ if (out.length != 0) {
+ assert(ctx->state != IAKERB_AP_REQ);
+
+ code = iakerb_make_token(ctx, &realm, cookie, &out,
+ (input_token == GSS_C_NO_BUFFER),
+ output_token);
+ if (code != 0)
+ goto cleanup;
+
+ /* Save the token for generating a future checksum */
+ code = iakerb_save_token(ctx, output_token);
+ if (code != 0)
+ goto cleanup;
+
+ ctx->count++;
+ }
+
+cleanup:
+ if (code != 0)
+ gss_release_buffer(&tmp, output_token);
+ krb5_free_data(ctx->k5c, cookie);
+ krb5_free_data_contents(ctx->k5c, &out);
+ krb5_free_data_contents(ctx->k5c, &realm);
+
+ return code;
+}
+
+/*
+ * Determine the starting IAKERB state for a context. If we already
+ * have a ticket, we may not need to do IAKERB at all.
+ */
+static krb5_error_code
+iakerb_get_initial_state(iakerb_ctx_id_t ctx,
+ krb5_gss_cred_id_t cred,
+ krb5_gss_name_t target,
+ OM_uint32 time_req,
+ enum iakerb_state *state)
+{
+ krb5_creds in_creds, *out_creds = NULL;
+ krb5_error_code code;
+
+ memset(&in_creds, 0, sizeof(in_creds));
+
+ in_creds.client = cred->name->princ;
+ in_creds.server = target->princ;
+
+ if (cred->name->ad_context != NULL) {
+ code = krb5_authdata_export_authdata(ctx->k5c,
+ cred->name->ad_context,
+ AD_USAGE_TGS_REQ,
+ &in_creds.authdata);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ if (time_req != 0 && time_req != GSS_C_INDEFINITE) {
+ krb5_timestamp now;
+
+ code = krb5_timeofday(ctx->k5c, &now);
+ if (code != 0)
+ goto cleanup;
+
+ in_creds.times.endtime = now + time_req;
+ }
+
+ /* Make an AS request if we have no creds or it's time to refresh them. */
+ if (cred->expire == 0 || kg_cred_time_to_refresh(ctx->k5c, cred)) {
+ *state = IAKERB_AS_REQ;
+ code = 0;
+ goto cleanup;
+ }
+
+ code = krb5_get_credentials(ctx->k5c, KRB5_GC_CACHED, cred->ccache,
+ &in_creds, &out_creds);
+ if (code == KRB5_CC_NOTFOUND || code == KRB5_CC_NOT_KTYPE) {
+ *state = cred->have_tgt ? IAKERB_TGS_REQ : IAKERB_AS_REQ;
+ code = 0;
+ } else if (code == 0) {
+ *state = IAKERB_AP_REQ;
+ krb5_free_creds(ctx->k5c, out_creds);
+ }
+
+cleanup:
+ krb5_free_authdata(ctx->k5c, in_creds.authdata);
+
+ return code;
+}
+
+/*
+ * Allocate and initialise an IAKERB context
+ */
+static krb5_error_code
+iakerb_alloc_context(iakerb_ctx_id_t *pctx, int initiate)
+{
+ iakerb_ctx_id_t ctx;
+ krb5_error_code code;
+
+ *pctx = NULL;
+
+ ctx = k5alloc(sizeof(*ctx), &code);
+ if (ctx == NULL)
+ goto cleanup;
+ ctx->defcred = GSS_C_NO_CREDENTIAL;
+ ctx->magic = KG_IAKERB_CONTEXT;
+ ctx->state = IAKERB_AS_REQ;
+ ctx->count = 0;
+ ctx->initiate = initiate;
+ ctx->established = 0;
+
+ code = krb5_gss_init_context(&ctx->k5c);
+ if (code != 0)
+ goto cleanup;
+
+ *pctx = ctx;
+
+cleanup:
+ if (code != 0)
+ iakerb_release_context(ctx);
+
+ return code;
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_delete_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token)
+{
+ iakerb_ctx_id_t iakerb_ctx = (iakerb_ctx_id_t)*context_handle;
+
+ if (output_token != GSS_C_NO_BUFFER) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+
+ *minor_status = 0;
+ *context_handle = GSS_C_NO_CONTEXT;
+ iakerb_release_context(iakerb_ctx);
+
+ return GSS_S_COMPLETE;
+}
+
+static krb5_boolean
+iakerb_is_iakerb_token(const gss_buffer_t token)
+{
+ krb5_error_code code;
+ unsigned int bodysize = token->length;
+ unsigned char *ptr = token->value;
+
+ code = g_verify_token_header(gss_mech_iakerb,
+ &bodysize, &ptr,
+ IAKERB_TOK_PROXY,
+ token->length, 0);
+
+ return (code == 0);
+}
+
+static void
+iakerb_make_exts(iakerb_ctx_id_t ctx, krb5_gss_ctx_ext_rec *exts)
+{
+ memset(exts, 0, sizeof(*exts));
+
+ if (ctx->conv.length != 0)
+ exts->iakerb.conv = &ctx->conv;
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_accept_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_cred_id_t verifier_cred_handle,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle)
+{
+ OM_uint32 major_status = GSS_S_FAILURE;
+ OM_uint32 code;
+ iakerb_ctx_id_t ctx;
+ int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT);
+
+ if (initialContextToken) {
+ code = iakerb_alloc_context(&ctx, 0);
+ if (code != 0)
+ goto cleanup;
+
+ } else
+ ctx = (iakerb_ctx_id_t)*context_handle;
+
+ if (iakerb_is_iakerb_token(input_token)) {
+ if (ctx->gssc != GSS_C_NO_CONTEXT) {
+ /* We shouldn't get an IAKERB token now. */
+ code = G_WRONG_TOKID;
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+ code = iakerb_acceptor_step(ctx, initialContextToken,
+ input_token, output_token);
+ if (code == (OM_uint32)KRB5_BAD_MSIZE)
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ if (code != 0)
+ goto cleanup;
+ if (initialContextToken) {
+ *context_handle = (gss_ctx_id_t)ctx;
+ ctx = NULL;
+ }
+ if (src_name != NULL)
+ *src_name = GSS_C_NO_NAME;
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_iakerb;
+ if (ret_flags != NULL)
+ *ret_flags = 0;
+ if (time_rec != NULL)
+ *time_rec = 0;
+ if (delegated_cred_handle != NULL)
+ *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+ major_status = GSS_S_CONTINUE_NEEDED;
+ } else {
+ krb5_gss_ctx_ext_rec exts;
+
+ iakerb_make_exts(ctx, &exts);
+
+ major_status = krb5_gss_accept_sec_context_ext(&code,
+ &ctx->gssc,
+ verifier_cred_handle,
+ input_token,
+ input_chan_bindings,
+ src_name,
+ NULL,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle,
+ &exts);
+ if (major_status == GSS_S_COMPLETE)
+ ctx->established = 1;
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_krb5;
+ }
+
+cleanup:
+ if (initialContextToken && GSS_ERROR(major_status)) {
+ iakerb_release_context(ctx);
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+
+ *minor_status = code;
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_init_sec_context(OM_uint32 *minor_status,
+ gss_cred_id_t claimant_cred_handle,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 major_status = GSS_S_FAILURE;
+ krb5_error_code code;
+ iakerb_ctx_id_t ctx;
+ krb5_gss_cred_id_t kcred;
+ krb5_gss_name_t kname;
+ krb5_boolean cred_locked = FALSE;
+ int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT);
+
+ if (initialContextToken) {
+ code = iakerb_alloc_context(&ctx, 1);
+ if (code != 0) {
+ *minor_status = code;
+ goto cleanup;
+ }
+ if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
+ major_status = iakerb_gss_acquire_cred(minor_status, NULL,
+ GSS_C_INDEFINITE,
+ GSS_C_NULL_OID_SET,
+ GSS_C_INITIATE,
+ &ctx->defcred, NULL, NULL);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+ claimant_cred_handle = ctx->defcred;
+ }
+ } else {
+ ctx = (iakerb_ctx_id_t)*context_handle;
+ if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
+ claimant_cred_handle = ctx->defcred;
+ }
+
+ kname = (krb5_gss_name_t)target_name;
+
+ major_status = kg_cred_resolve(minor_status, ctx->k5c,
+ claimant_cred_handle, target_name);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+ cred_locked = TRUE;
+ kcred = (krb5_gss_cred_id_t)claimant_cred_handle;
+
+ major_status = GSS_S_FAILURE;
+
+ if (initialContextToken) {
+ code = iakerb_get_initial_state(ctx, kcred, kname, time_req,
+ &ctx->state);
+ if (code != 0) {
+ *minor_status = code;
+ goto cleanup;
+ }
+ *context_handle = (gss_ctx_id_t)ctx;
+ }
+
+ if (ctx->state != IAKERB_AP_REQ) {
+ /* We need to do IAKERB. */
+ code = iakerb_initiator_step(ctx,
+ kcred,
+ kname,
+ time_req,
+ input_token,
+ output_token);
+ if (code == KRB5_BAD_MSIZE)
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ if (code != 0) {
+ *minor_status = code;
+ goto cleanup;
+ }
+ }
+
+ if (ctx->state == IAKERB_AP_REQ) {
+ krb5_gss_ctx_ext_rec exts;
+
+ if (cred_locked) {
+ k5_mutex_unlock(&kcred->lock);
+ cred_locked = FALSE;
+ }
+
+ iakerb_make_exts(ctx, &exts);
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ input_token = GSS_C_NO_BUFFER;
+
+ /* IAKERB is finished, or we skipped to Kerberos directly. */
+ major_status = krb5_gss_init_sec_context_ext(minor_status,
+ (gss_cred_id_t) kcred,
+ &ctx->gssc,
+ target_name,
+ (gss_OID)gss_mech_iakerb,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ NULL,
+ output_token,
+ ret_flags,
+ time_rec,
+ &exts);
+ if (major_status == GSS_S_COMPLETE)
+ ctx->established = 1;
+ if (actual_mech_type != NULL)
+ *actual_mech_type = (gss_OID)gss_mech_krb5;
+ } else {
+ if (actual_mech_type != NULL)
+ *actual_mech_type = (gss_OID)gss_mech_iakerb;
+ if (ret_flags != NULL)
+ *ret_flags = 0;
+ if (time_rec != NULL)
+ *time_rec = 0;
+ major_status = GSS_S_CONTINUE_NEEDED;
+ }
+
+cleanup:
+ if (cred_locked)
+ k5_mutex_unlock(&kcred->lock);
+ if (initialContextToken && GSS_ERROR(major_status)) {
+ iakerb_release_context(ctx);
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_unwrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer, int *conf_state,
+ gss_qop_t *qop_state)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_unwrap(minor_status, ctx->gssc, input_message_buffer,
+ output_message_buffer, conf_state, qop_state);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int conf_req_flag, gss_qop_t qop_req,
+ gss_buffer_t input_message_buffer, int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_wrap(minor_status, ctx->gssc, conf_req_flag, qop_req,
+ input_message_buffer, conf_state,
+ output_message_buffer);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_process_context_token(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t token_buffer)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ return krb5_gss_process_context_token(minor_status, ctx->gssc,
+ token_buffer);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_context_time(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ OM_uint32 *time_rec)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_context_time(minor_status, ctx->gssc, time_rec);
+}
+
+#ifndef LEAN_CLIENT
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_export_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t interprocess_token)
+{
+ OM_uint32 maj;
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle;
+
+ /* We don't currently support exporting partially established contexts. */
+ if (!ctx->established)
+ return GSS_S_UNAVAILABLE;
+
+ maj = krb5_gss_export_sec_context(minor_status, &ctx->gssc,
+ interprocess_token);
+ if (ctx->gssc == GSS_C_NO_CONTEXT) {
+ iakerb_release_context(ctx);
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+ return maj;
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_import_sec_context(OM_uint32 *minor_status,
+ gss_buffer_t interprocess_token,
+ gss_ctx_id_t *context_handle)
+{
+ OM_uint32 maj, tmpmin;
+ krb5_error_code code;
+ gss_ctx_id_t gssc;
+ krb5_gss_ctx_id_t kctx;
+ iakerb_ctx_id_t ctx;
+
+ maj = krb5_gss_import_sec_context(minor_status, interprocess_token, &gssc);
+ if (maj != GSS_S_COMPLETE)
+ return maj;
+ kctx = (krb5_gss_ctx_id_t)gssc;
+
+ if (!kctx->established) {
+ /* We don't currently support importing partially established
+ * contexts. */
+ krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER);
+ return GSS_S_FAILURE;
+ }
+
+ code = iakerb_alloc_context(&ctx, kctx->initiate);
+ if (code != 0) {
+ krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ ctx->gssc = gssc;
+ ctx->established = 1;
+ *context_handle = (gss_ctx_id_t)ctx;
+ return GSS_S_COMPLETE;
+}
+#endif /* LEAN_CLIENT */
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_inquire_context(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, gss_name_t *src_name,
+ gss_name_t *targ_name, OM_uint32 *lifetime_rec,
+ gss_OID *mech_type, OM_uint32 *ctx_flags,
+ int *initiate, int *opened)
+{
+ OM_uint32 ret;
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (src_name != NULL)
+ *src_name = GSS_C_NO_NAME;
+ if (targ_name != NULL)
+ *targ_name = GSS_C_NO_NAME;
+ if (lifetime_rec != NULL)
+ *lifetime_rec = 0;
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_iakerb;
+ if (ctx_flags != NULL)
+ *ctx_flags = 0;
+ if (initiate != NULL)
+ *initiate = ctx->initiate;
+ if (opened != NULL)
+ *opened = ctx->established;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_COMPLETE;
+
+ ret = krb5_gss_inquire_context(minor_status, ctx->gssc, src_name,
+ targ_name, lifetime_rec, mech_type,
+ ctx_flags, initiate, opened);
+
+ if (!ctx->established) {
+ /* Report IAKERB as the mech OID until the context is established. */
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_iakerb;
+
+ /* We don't support exporting partially-established contexts. */
+ if (ctx_flags != NULL)
+ *ctx_flags &= ~GSS_C_TRANS_FLAG;
+ }
+
+ return ret;
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_size_limit(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, int conf_req_flag,
+ gss_qop_t qop_req, OM_uint32 req_output_size,
+ OM_uint32 *max_input_size)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_wrap_size_limit(minor_status, ctx->gssc, conf_req_flag,
+ qop_req, req_output_size, max_input_size);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t qop_req, gss_buffer_t message_buffer,
+ gss_buffer_t message_token)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_get_mic(minor_status, ctx->gssc, qop_req, message_buffer,
+ message_token);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_verify_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_buffer_t msg_buffer, gss_buffer_t token_buffer,
+ gss_qop_t *qop_state)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_verify_mic(minor_status, ctx->gssc, msg_buffer,
+ token_buffer, qop_state);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_inquire_sec_context_by_oid(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_UNAVAILABLE;
+
+ return krb5_gss_inquire_sec_context_by_oid(minor_status, ctx->gssc,
+ desired_object, data_set);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_set_sec_context_option(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle;
+
+ if (ctx == NULL || ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_UNAVAILABLE;
+
+ return krb5_gss_set_sec_context_option(minor_status, &ctx->gssc,
+ desired_object, value);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int conf_req_flag, gss_qop_t qop_req, int *conf_state,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_wrap_iov(minor_status, ctx->gssc, conf_req_flag, qop_req,
+ conf_state, iov, iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_unwrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int *conf_state, gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_unwrap_iov(minor_status, ctx->gssc, conf_state, qop_state,
+ iov, iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, int conf_req_flag,
+ gss_qop_t qop_req, int *conf_state,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_wrap_iov_length(minor_status, ctx->gssc, conf_req_flag,
+ qop_req, conf_state, iov, iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ int prf_key, const gss_buffer_t prf_in,
+ ssize_t desired_output_len, gss_buffer_t prf_out)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_pseudo_random(minor_status, ctx->gssc, prf_key, prf_in,
+ desired_output_len, prf_out);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t qop_req, gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_get_mic_iov(minor_status, ctx->gssc, qop_req, iov,
+ iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+ gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_verify_mic_iov(minor_status, ctx->gssc, qop_state, iov,
+ iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, gss_qop_t qop_req,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+ if (ctx->gssc == GSS_C_NO_CONTEXT)
+ return GSS_S_NO_CONTEXT;
+
+ return krb5_gss_get_mic_iov_length(minor_status, ctx->gssc, qop_req, iov,
+ iov_count);
+}
diff --git a/src/lib/gssapi/krb5/import_cred.c b/src/lib/gssapi/krb5/import_cred.c
new file mode 100644
index 000000000000..f0a0373bfb79
--- /dev/null
+++ b/src/lib/gssapi/krb5/import_cred.c
@@ -0,0 +1,648 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/import_cred.c - krb5 import_cred implementation */
+/*
+ * Copyright (C) 2012 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#include "k5-json.h"
+#include "gssapiP_krb5.h"
+
+/* Return the idx element of array if it is of type tid; otherwise return
+ * NULL. The caller is responsible for checking the array length. */
+static k5_json_value
+check_element(k5_json_array array, size_t idx, k5_json_tid tid)
+{
+ k5_json_value v;
+
+ v = k5_json_array_get(array, idx);
+ return (k5_json_get_tid(v) == tid) ? v : NULL;
+}
+
+/* All of the json_to_x functions return 0 on success, -1 on failure (either
+ * from running out of memory or from defective input). */
+
+/* Convert a JSON value to a C string or to NULL. */
+static int
+json_to_optional_string(k5_json_value v, char **string_out)
+{
+ *string_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
+ return -1;
+ *string_out = strdup(k5_json_string_utf8(v));
+ return (*string_out == NULL) ? -1 : 0;
+}
+
+/* Convert a JSON value to a principal or to NULL. */
+static int
+json_to_principal(krb5_context context, k5_json_value v,
+ krb5_principal *princ_out)
+{
+ *princ_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
+ return -1;
+ if (krb5_parse_name(context, k5_json_string_utf8(v), princ_out))
+ return -1;
+ return 0;
+}
+
+/* Convert a JSON value to a zero-terminated enctypes list or to NULL. */
+static int
+json_to_etypes(k5_json_value v, krb5_enctype **etypes_out)
+{
+ krb5_enctype *etypes = NULL;
+ k5_json_array array;
+ k5_json_number n;
+ size_t len, i;
+
+ *etypes_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ len = k5_json_array_length(array);
+ etypes = calloc(len + 1, sizeof(*etypes));
+ for (i = 0; i < len; i++) {
+ n = check_element(array, i, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ etypes[i] = k5_json_number_value(n);
+ }
+ *etypes_out = etypes;
+ return 0;
+
+invalid:
+ free(etypes);
+ return -1;
+}
+
+/* Convert a JSON value to a krb5 GSS name or to NULL. */
+static int
+json_to_kgname(krb5_context context, k5_json_value v,
+ krb5_gss_name_t *name_out)
+{
+ k5_json_array array;
+ krb5_gss_name_t name = NULL;
+
+ *name_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ if (k5_json_array_length(array) != 3)
+ return -1;
+ name = calloc(1, sizeof(*name));
+ if (name == NULL)
+ return -1;
+ if (k5_mutex_init(&name->lock)) {
+ free(name);
+ return -1;
+ }
+
+ if (json_to_principal(context, k5_json_array_get(array, 0), &name->princ))
+ goto invalid;
+ if (json_to_optional_string(k5_json_array_get(array, 1), &name->service))
+ goto invalid;
+ if (json_to_optional_string(k5_json_array_get(array, 2), &name->host))
+ goto invalid;
+
+ *name_out = name;
+ return 0;
+
+invalid:
+ kg_release_name(context, &name);
+ return -1;
+}
+
+/* Convert a JSON value to a keytab handle or to NULL. */
+static int
+json_to_keytab(krb5_context context, k5_json_value v, krb5_keytab *keytab_out)
+{
+ *keytab_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
+ return -1;
+ if (krb5_kt_resolve(context, k5_json_string_utf8(v), keytab_out))
+ return -1;
+ return 0;
+}
+
+/* Convert a JSON value to an rcache handle or to NULL. */
+static int
+json_to_rcache(krb5_context context, k5_json_value v, krb5_rcache *rcache_out)
+{
+ krb5_rcache rcache;
+
+ *rcache_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
+ return -1;
+ if (krb5_rc_resolve_full(context, &rcache, (char *)k5_json_string_utf8(v)))
+ return -1;
+ if (krb5_rc_recover_or_initialize(context, rcache, context->clockskew)) {
+ krb5_rc_close(context, rcache);
+ return -1;
+ }
+ *rcache_out = rcache;
+ return 0;
+}
+
+/* Convert a JSON value to a keyblock, filling in keyblock. */
+static int
+json_to_keyblock(k5_json_value v, krb5_keyblock *keyblock)
+{
+ k5_json_array array;
+ k5_json_number n;
+ k5_json_string s;
+ size_t len;
+
+ memset(keyblock, 0, sizeof(*keyblock));
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ if (k5_json_array_length(array) != 2)
+ return -1;
+
+ n = check_element(array, 0, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ return -1;
+ keyblock->enctype = k5_json_number_value(n);
+
+ s = check_element(array, 1, K5_JSON_TID_STRING);
+ if (s == NULL)
+ return -1;
+ if (k5_json_string_unbase64(s, &keyblock->contents, &len))
+ return -1;
+ keyblock->length = len;
+ keyblock->magic = KV5M_KEYBLOCK;
+ return 0;
+}
+
+/* Convert a JSON value to a krb5 address. */
+static int
+json_to_address(k5_json_value v, krb5_address **addr_out)
+{
+ k5_json_array array;
+ krb5_address *addr = NULL;
+ k5_json_number n;
+ k5_json_string s;
+ size_t len;
+
+ *addr_out = NULL;
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ if (k5_json_array_length(array) != 2)
+ return -1;
+
+ n = check_element(array, 0, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ return -1;
+ s = check_element(array, 1, K5_JSON_TID_STRING);
+ if (s == NULL)
+ return -1;
+
+ addr = malloc(sizeof(*addr));
+ if (addr == NULL)
+ return -1;
+ addr->addrtype = k5_json_number_value(n);
+ if (k5_json_string_unbase64(s, &addr->contents, &len)) {
+ free(addr);
+ return -1;
+ }
+ addr->length = len;
+ addr->magic = KV5M_ADDRESS;
+ *addr_out = addr;
+ return 0;
+}
+
+/* Convert a JSON value to a null-terminated list of krb5 addresses or to
+ * NULL. */
+static int
+json_to_addresses(krb5_context context, k5_json_value v,
+ krb5_address ***addresses_out)
+{
+ k5_json_array array;
+ krb5_address **addrs = NULL;
+ size_t len, i;
+
+ *addresses_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ len = k5_json_array_length(array);
+ addrs = calloc(len + 1, sizeof(*addrs));
+ for (i = 0; i < len; i++) {
+ if (json_to_address(k5_json_array_get(array, i), &addrs[i]))
+ goto invalid;
+ }
+ addrs[i] = NULL;
+ *addresses_out = addrs;
+ return 0;
+
+invalid:
+ krb5_free_addresses(context, addrs);
+ return -1;
+}
+
+/* Convert a JSON value to an authdata element. */
+static int
+json_to_authdata_element(k5_json_value v, krb5_authdata **ad_out)
+{
+ k5_json_array array;
+ krb5_authdata *ad = NULL;
+ k5_json_number n;
+ k5_json_string s;
+ size_t len;
+
+ *ad_out = NULL;
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ if (k5_json_array_length(array) != 2)
+ return -1;
+
+ n = check_element(array, 0, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ return -1;
+ s = check_element(array, 1, K5_JSON_TID_STRING);
+ if (s == NULL)
+ return -1;
+
+ ad = malloc(sizeof(*ad));
+ if (ad == NULL)
+ return -1;
+ ad->ad_type = k5_json_number_value(n);
+ if (k5_json_string_unbase64(s, &ad->contents, &len)) {
+ free(ad);
+ return -1;
+ }
+ ad->length = len;
+ ad->magic = KV5M_AUTHDATA;
+ *ad_out = ad;
+ return 0;
+}
+
+/* Convert a JSON value to a null-terminated authdata list or to NULL. */
+static int
+json_to_authdata(krb5_context context, k5_json_value v,
+ krb5_authdata ***authdata_out)
+{
+ k5_json_array array;
+ krb5_authdata **authdata = NULL;
+ size_t len, i;
+
+ *authdata_out = NULL;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ len = k5_json_array_length(array);
+ authdata = calloc(len + 1, sizeof(*authdata));
+ for (i = 0; i < len; i++) {
+ if (json_to_authdata_element(k5_json_array_get(array, i),
+ &authdata[i]))
+ goto invalid;
+ }
+ authdata[i] = NULL;
+ *authdata_out = authdata;
+ return 0;
+
+invalid:
+ krb5_free_authdata(context, authdata);
+ return -1;
+}
+
+/* Convert a JSON value to a krb5 credential structure, filling in creds. */
+static int
+json_to_creds(krb5_context context, k5_json_value v, krb5_creds *creds)
+{
+ k5_json_array array;
+ k5_json_number n;
+ k5_json_bool b;
+ k5_json_string s;
+ unsigned char *data;
+ size_t len;
+
+ memset(creds, 0, sizeof(*creds));
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ if (k5_json_array_length(array) != 13)
+ return -1;
+
+ if (json_to_principal(context, k5_json_array_get(array, 0),
+ &creds->client))
+ goto invalid;
+
+ if (json_to_principal(context, k5_json_array_get(array, 1),
+ &creds->server))
+ goto invalid;
+
+ if (json_to_keyblock(k5_json_array_get(array, 2), &creds->keyblock))
+ goto invalid;
+
+ n = check_element(array, 3, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ creds->times.authtime = k5_json_number_value(n);
+
+ n = check_element(array, 4, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ creds->times.starttime = k5_json_number_value(n);
+
+ n = check_element(array, 5, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ creds->times.endtime = k5_json_number_value(n);
+
+ n = check_element(array, 6, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ creds->times.renew_till = k5_json_number_value(n);
+
+ b = check_element(array, 7, K5_JSON_TID_BOOL);
+ if (b == NULL)
+ goto invalid;
+ creds->is_skey = k5_json_bool_value(b);
+
+ n = check_element(array, 8, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ creds->ticket_flags = k5_json_number_value(n);
+
+ if (json_to_addresses(context, k5_json_array_get(array, 9),
+ &creds->addresses))
+ goto invalid;
+
+ s = check_element(array, 10, K5_JSON_TID_STRING);
+ if (s == NULL)
+ goto invalid;
+ if (k5_json_string_unbase64(s, &data, &len))
+ goto invalid;
+ creds->ticket.data = (char *)data;
+ creds->ticket.length = len;
+
+ s = check_element(array, 11, K5_JSON_TID_STRING);
+ if (s == NULL)
+ goto invalid;
+ if (k5_json_string_unbase64(s, &data, &len))
+ goto invalid;
+ creds->second_ticket.data = (char *)data;
+ creds->second_ticket.length = len;
+
+ if (json_to_authdata(context, k5_json_array_get(array, 12),
+ &creds->authdata))
+ goto invalid;
+
+ creds->magic = KV5M_CREDS;
+ return 0;
+
+invalid:
+ krb5_free_cred_contents(context, creds);
+ memset(creds, 0, sizeof(*creds));
+ return -1;
+}
+
+/* Convert a JSON value to a ccache handle or to NULL. Set *new_out to true if
+ * the ccache handle is a newly created memory ccache, false otherwise. */
+static int
+json_to_ccache(krb5_context context, k5_json_value v, krb5_ccache *ccache_out,
+ krb5_boolean *new_out)
+{
+ krb5_error_code ret;
+ krb5_ccache ccache = NULL;
+ krb5_principal princ;
+ krb5_creds creds;
+ k5_json_array array;
+ size_t i, len;
+
+ *ccache_out = NULL;
+ *new_out = FALSE;
+ if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
+ return 0;
+ if (k5_json_get_tid(v) == K5_JSON_TID_STRING) {
+ /* We got a reference to an external ccache; just resolve it. */
+ return krb5_cc_resolve(context, k5_json_string_utf8(v), ccache_out) ?
+ -1 : 0;
+ }
+
+ /* We got the contents of a memory ccache. */
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ return -1;
+ array = v;
+ len = k5_json_array_length(array);
+ if (len < 1)
+ return -1;
+
+ /* Initialize a new memory ccache using the principal in the first array
+ * entry.*/
+ if (krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))
+ return -1;
+ if (json_to_principal(context, k5_json_array_get(array, 0), &princ))
+ goto invalid;
+ ret = krb5_cc_initialize(context, ccache, princ);
+ krb5_free_principal(context, princ);
+ if (ret)
+ goto invalid;
+
+ /* Add remaining array entries to the ccache as credentials. */
+ for (i = 1; i < len; i++) {
+ if (json_to_creds(context, k5_json_array_get(array, i), &creds))
+ goto invalid;
+ ret = krb5_cc_store_cred(context, ccache, &creds);
+ krb5_free_cred_contents(context, &creds);
+ if (ret)
+ goto invalid;
+ }
+
+ *ccache_out = ccache;
+ *new_out = TRUE;
+ return 0;
+
+invalid:
+ (void)krb5_cc_destroy(context, ccache);
+ return -1;
+}
+
+/* Convert a JSON array value to a krb5 GSS credential. */
+static int
+json_to_kgcred(krb5_context context, k5_json_array array,
+ krb5_gss_cred_id_t *cred_out)
+{
+ krb5_gss_cred_id_t cred;
+ k5_json_number n;
+ k5_json_bool b;
+ krb5_boolean is_new;
+ OM_uint32 tmp;
+
+ *cred_out = NULL;
+ if (k5_json_array_length(array) != 14)
+ return -1;
+
+ cred = calloc(1, sizeof(*cred));
+ if (cred == NULL)
+ return -1;
+ if (k5_mutex_init(&cred->lock)) {
+ free(cred);
+ return -1;
+ }
+
+ n = check_element(array, 0, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ cred->usage = k5_json_number_value(n);
+
+ if (json_to_kgname(context, k5_json_array_get(array, 1), &cred->name))
+ goto invalid;
+
+ if (json_to_principal(context, k5_json_array_get(array, 2),
+ &cred->impersonator))
+ goto invalid;
+
+ b = check_element(array, 3, K5_JSON_TID_BOOL);
+ if (b == NULL)
+ goto invalid;
+ cred->default_identity = k5_json_bool_value(b);
+
+ b = check_element(array, 4, K5_JSON_TID_BOOL);
+ if (b == NULL)
+ goto invalid;
+ cred->iakerb_mech = k5_json_bool_value(b);
+
+ if (json_to_keytab(context, k5_json_array_get(array, 5), &cred->keytab))
+ goto invalid;
+
+ if (json_to_rcache(context, k5_json_array_get(array, 6), &cred->rcache))
+ goto invalid;
+
+ if (json_to_ccache(context, k5_json_array_get(array, 7), &cred->ccache,
+ &is_new))
+ goto invalid;
+ cred->destroy_ccache = is_new;
+
+ if (json_to_keytab(context, k5_json_array_get(array, 8),
+ &cred->client_keytab))
+ goto invalid;
+
+ b = check_element(array, 9, K5_JSON_TID_BOOL);
+ if (b == NULL)
+ goto invalid;
+ cred->have_tgt = k5_json_bool_value(b);
+
+ n = check_element(array, 10, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ cred->expire = k5_json_number_value(n);
+
+ n = check_element(array, 11, K5_JSON_TID_NUMBER);
+ if (n == NULL)
+ goto invalid;
+ cred->refresh_time = k5_json_number_value(n);
+
+ if (json_to_etypes(k5_json_array_get(array, 12), &cred->req_enctypes))
+ goto invalid;
+
+ if (json_to_optional_string(k5_json_array_get(array, 13), &cred->password))
+ goto invalid;
+
+ *cred_out = cred;
+ return 0;
+
+invalid:
+ (void)krb5_gss_release_cred(&tmp, (gss_cred_id_t *)&cred);
+ return -1;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_import_cred(OM_uint32 *minor_status, gss_buffer_t token,
+ gss_cred_id_t *cred_handle)
+{
+ OM_uint32 status = GSS_S_COMPLETE;
+ krb5_context context;
+ krb5_error_code ret;
+ krb5_gss_cred_id_t cred;
+ k5_json_value v = NULL;
+ k5_json_array array;
+ k5_json_string str;
+ char *copy = NULL;
+
+ ret = krb5_gss_init_context(&context);
+ if (ret) {
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+
+ /* Decode token. */
+ copy = k5memdup0(token->value, token->length, &ret);
+ if (copy == NULL) {
+ status = GSS_S_FAILURE;
+ *minor_status = ret;
+ goto cleanup;
+ }
+ if (k5_json_decode(copy, &v))
+ goto invalid;
+
+ /* Decode the CRED_EXPORT_MAGIC array wrapper. */
+ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
+ goto invalid;
+ array = v;
+ if (k5_json_array_length(array) != 2)
+ goto invalid;
+ str = check_element(array, 0, K5_JSON_TID_STRING);
+ if (str == NULL ||
+ strcmp(k5_json_string_utf8(str), CRED_EXPORT_MAGIC) != 0)
+ goto invalid;
+ if (json_to_kgcred(context, k5_json_array_get(array, 1), &cred))
+ goto invalid;
+
+ *cred_handle = (gss_cred_id_t)cred;
+
+cleanup:
+ free(copy);
+ k5_json_release(v);
+ krb5_free_context(context);
+ return status;
+
+invalid:
+ status = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+}
diff --git a/src/lib/gssapi/krb5/import_name.c b/src/lib/gssapi/krb5/import_name.c
new file mode 100644
index 000000000000..3f5492b99f6b
--- /dev/null
+++ b/src/lib/gssapi/krb5/import_name.c
@@ -0,0 +1,332 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_krb5.h"
+
+#ifndef NO_PASSWORD
+#include <pwd.h>
+#include <stdio.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * errors:
+ * GSS_S_BAD_NAMETYPE if the type is bogus
+ * GSS_S_BAD_NAME if the type is good but the name is bogus
+ * GSS_S_FAILURE if memory allocation fails
+ */
+
+/*
+ * Import serialized authdata context
+ */
+static krb5_error_code
+import_name_composite(krb5_context context,
+ unsigned char *enc_data, size_t enc_length,
+ krb5_authdata_context *pad_context)
+{
+ krb5_authdata_context ad_context;
+ krb5_error_code code;
+ krb5_data data;
+
+ if (enc_length == 0)
+ return 0;
+
+ code = krb5_authdata_context_init(context, &ad_context);
+ if (code != 0)
+ return code;
+
+ data.data = (char *)enc_data;
+ data.length = enc_length;
+
+ code = krb5_authdata_import_attributes(context,
+ ad_context,
+ AD_USAGE_MASK,
+ &data);
+ if (code != 0) {
+ krb5_authdata_context_free(context, ad_context);
+ return code;
+ }
+
+ *pad_context = ad_context;
+
+ return 0;
+}
+
+/* Split a host-based name "service[@host]" into allocated strings
+ * placed in *service_out and *host_out (possibly NULL). */
+static krb5_error_code
+parse_hostbased(const char *str, size_t len,
+ char **service_out, char **host_out)
+{
+ const char *at;
+ size_t servicelen, hostlen;
+ char *service, *host = NULL;
+
+ *service_out = *host_out = NULL;
+
+ /* Find the bound of the service name and copy it. */
+ at = memchr(str, '@', len);
+ servicelen = (at == NULL) ? len : (size_t)(at - str);
+ service = xmalloc(servicelen + 1);
+ if (service == NULL)
+ return ENOMEM;
+ memcpy(service, str, servicelen);
+ service[servicelen] = '\0';
+
+ /* If present, copy the hostname. */
+ if (at != NULL) {
+ hostlen = len - servicelen - 1;
+ host = malloc(hostlen + 1);
+ if (host == NULL) {
+ free(service);
+ return ENOMEM;
+ }
+ memcpy(host, at + 1, hostlen);
+ host[hostlen] = '\0';
+ }
+
+ *service_out = service;
+ *host_out = host;
+ return 0;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_import_name(minor_status, input_name_buffer,
+ input_name_type, output_name)
+ OM_uint32 *minor_status;
+ gss_buffer_t input_name_buffer;
+ gss_OID input_name_type;
+ gss_name_t *output_name;
+{
+ krb5_context context;
+ krb5_principal princ = NULL;
+ krb5_error_code code;
+ unsigned char *cp, *end;
+ char *tmp = NULL, *tmp2 = NULL, *service = NULL, *host = NULL, *stringrep;
+ ssize_t length;
+#ifndef NO_PASSWORD
+ struct passwd *pw;
+#endif
+ int is_composite = 0;
+ krb5_authdata_context ad_context = NULL;
+ OM_uint32 status = GSS_S_FAILURE;
+ krb5_gss_name_t name;
+
+ *output_name = NULL;
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code)
+ goto cleanup;
+
+ if ((input_name_type != GSS_C_NULL_OID) &&
+ (g_OID_equal(input_name_type, gss_nt_service_name) ||
+ g_OID_equal(input_name_type, gss_nt_service_name_v2))) {
+ /* Split the name into service and host (or NULL). */
+ code = parse_hostbased(input_name_buffer->value,
+ input_name_buffer->length, &service, &host);
+ if (code)
+ goto cleanup;
+
+ /*
+ * Compute the initiator target name. In some cases this is a waste of
+ * getaddrinfo/getnameinfo queries, but computing the name when we need
+ * it would require a lot of code changes.
+ */
+ code = krb5_sname_to_principal(context, host, service, KRB5_NT_SRV_HST,
+ &princ);
+ if (code)
+ goto cleanup;
+ } else if ((input_name_type != GSS_C_NULL_OID) &&
+ (g_OID_equal(input_name_type, gss_nt_krb5_principal))) {
+ krb5_principal input;
+
+ if (input_name_buffer->length != sizeof(krb5_principal)) {
+ code = G_WRONG_SIZE;
+ status = GSS_S_BAD_NAME;
+ goto cleanup;
+ }
+
+ input = *((krb5_principal *) input_name_buffer->value);
+
+ code = krb5_copy_principal(context, input, &princ);
+ if (code)
+ goto cleanup;
+ } else if ((input_name_type != NULL) &&
+ g_OID_equal(input_name_type, GSS_C_NT_ANONYMOUS)) {
+ code = krb5_copy_principal(context, krb5_anonymous_principal(),
+ &princ);
+ if (code)
+ goto cleanup;
+ } else {
+#ifndef NO_PASSWORD
+ uid_t uid;
+ struct passwd pwx;
+ char pwbuf[BUFSIZ];
+#endif
+
+ stringrep = NULL;
+
+ tmp = k5memdup0(input_name_buffer->value, input_name_buffer->length,
+ &code);
+ if (tmp == NULL)
+ goto cleanup;
+ tmp2 = NULL;
+
+ /* Find the appropriate string rep to pass into parse_name. */
+ if ((input_name_type == GSS_C_NULL_OID) ||
+ g_OID_equal(input_name_type, gss_nt_krb5_name) ||
+ g_OID_equal(input_name_type, gss_nt_user_name)) {
+ stringrep = (char *) tmp;
+#ifndef NO_PASSWORD
+ } else if (g_OID_equal(input_name_type, gss_nt_machine_uid_name)) {
+ uid = *(uid_t *) input_name_buffer->value;
+ do_getpwuid:
+ if (k5_getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) == 0)
+ stringrep = pw->pw_name;
+ else
+ code = G_NOUSER;
+ } else if (g_OID_equal(input_name_type, gss_nt_string_uid_name)) {
+ uid = atoi(tmp);
+ goto do_getpwuid;
+#endif
+ } else if (g_OID_equal(input_name_type, gss_nt_exported_name) ||
+ g_OID_equal(input_name_type, GSS_C_NT_COMPOSITE_EXPORT)) {
+#define BOUNDS_CHECK(cp, end, n) \
+ do { if ((end) - (cp) < (n)) goto fail_name; } while (0)
+ cp = (unsigned char *)tmp;
+ end = cp + input_name_buffer->length;
+
+ BOUNDS_CHECK(cp, end, 2);
+ if (*cp++ != 0x04)
+ goto fail_name;
+ switch (*cp++) {
+ case 0x01:
+ break;
+ case 0x02:
+ is_composite++;
+ break;
+ default:
+ goto fail_name;
+ }
+
+ BOUNDS_CHECK(cp, end, 2);
+ if (*cp++ != 0x00)
+ goto fail_name;
+ length = *cp++;
+ if (length != (ssize_t)gss_mech_krb5->length+2)
+ goto fail_name;
+
+ BOUNDS_CHECK(cp, end, 2);
+ if (*cp++ != 0x06)
+ goto fail_name;
+ length = *cp++;
+ if (length != (ssize_t)gss_mech_krb5->length)
+ goto fail_name;
+
+ BOUNDS_CHECK(cp, end, length);
+ if (memcmp(cp, gss_mech_krb5->elements, length) != 0)
+ goto fail_name;
+ cp += length;
+
+ BOUNDS_CHECK(cp, end, 4);
+ length = *cp++;
+ length = (length << 8) | *cp++;
+ length = (length << 8) | *cp++;
+ length = (length << 8) | *cp++;
+
+ BOUNDS_CHECK(cp, end, length);
+ tmp2 = k5alloc(length + 1, &code);
+ if (tmp2 == NULL)
+ goto cleanup;
+ strncpy(tmp2, (char *)cp, length);
+ tmp2[length] = 0;
+ stringrep = tmp2;
+ cp += length;
+
+ if (is_composite) {
+ BOUNDS_CHECK(cp, end, 4);
+ length = *cp++;
+ length = (length << 8) | *cp++;
+ length = (length << 8) | *cp++;
+ length = (length << 8) | *cp++;
+
+ BOUNDS_CHECK(cp, end, length);
+ code = import_name_composite(context,
+ cp, length,
+ &ad_context);
+ if (code != 0)
+ goto fail_name;
+ cp += length;
+ }
+ assert(cp == end);
+ } else {
+ status = GSS_S_BAD_NAMETYPE;
+ goto cleanup;
+ }
+
+ /* At this point, stringrep is set, or if not, code is. */
+ if (stringrep) {
+ code = krb5_parse_name(context, (char *)stringrep, &princ);
+ if (code)
+ goto cleanup;
+ } else {
+ fail_name:
+ status = GSS_S_BAD_NAME;
+ goto cleanup;
+ }
+ }
+
+ /* Create a name and save it in the validation database. */
+ code = kg_init_name(context, princ, service, host, ad_context,
+ KG_INIT_NAME_NO_COPY, &name);
+ if (code)
+ goto cleanup;
+ princ = NULL;
+ ad_context = NULL;
+ service = host = NULL;
+ *output_name = (gss_name_t)name;
+ status = GSS_S_COMPLETE;
+
+cleanup:
+ *minor_status = (OM_uint32)code;
+ if (*minor_status)
+ save_error_info(*minor_status, context);
+ krb5_free_principal(context, princ);
+ krb5_authdata_context_free(context, ad_context);
+ krb5_free_context(context);
+ free(tmp);
+ free(tmp2);
+ free(service);
+ free(host);
+ return status;
+}
diff --git a/src/lib/gssapi/krb5/import_sec_context.c b/src/lib/gssapi/krb5/import_sec_context.c
new file mode 100644
index 000000000000..4190adf35cab
--- /dev/null
+++ b/src/lib/gssapi/krb5/import_sec_context.c
@@ -0,0 +1,118 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/import_sec_context.c - Internalize the security context */
+/*
+ * Copyright 1995,2004,2007,2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "gssapiP_krb5.h"
+/* for serialization initialization functions */
+#include "k5-int.h"
+
+/*
+ * Fix up the OID of the mechanism so that uses the static version of
+ * the OID if possible.
+ */
+gss_OID krb5_gss_convert_static_mech_oid(oid)
+ gss_OID oid;
+{
+ const gss_OID_desc *p;
+ OM_uint32 minor_status;
+
+ for (p = krb5_gss_oid_array; p->length; p++) {
+ if ((oid->length == p->length) &&
+ (memcmp(oid->elements, p->elements, p->length) == 0)) {
+ generic_gss_release_oid(&minor_status, &oid);
+ return (gss_OID) p;
+ }
+ }
+ return oid;
+}
+
+krb5_error_code
+krb5_gss_ser_init (krb5_context context)
+{
+ krb5_error_code code;
+ static krb5_error_code (KRB5_CALLCONV *const fns[])(krb5_context) = {
+ krb5_ser_context_init, krb5_ser_auth_context_init,
+ krb5_ser_ccache_init, krb5_ser_rcache_init, krb5_ser_keytab_init,
+ };
+ unsigned int i;
+
+ for (i = 0; i < sizeof(fns)/sizeof(fns[0]); i++)
+ if ((code = (fns[i])(context)) != 0)
+ return code;
+ return 0;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_import_sec_context(minor_status, interprocess_token, context_handle)
+ OM_uint32 *minor_status;
+ gss_buffer_t interprocess_token;
+ gss_ctx_id_t *context_handle;
+{
+ krb5_context context;
+ krb5_error_code kret = 0;
+ size_t blen;
+ krb5_gss_ctx_id_t ctx;
+ krb5_octet *ibp;
+
+ /* This is a bit screwy. We create a krb5 context because we need
+ one when calling the serialization code. However, one of the
+ objects we're unpacking is a krb5 context, so when we finish,
+ we can throw this one away. */
+ kret = krb5_gss_init_context(&context);
+ if (kret) {
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
+ kret = krb5_gss_ser_init(context);
+ if (kret) {
+ *minor_status = kret;
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return GSS_S_FAILURE;
+ }
+
+ /* Assume a tragic failure */
+ ctx = (krb5_gss_ctx_id_t) NULL;
+ *minor_status = 0;
+
+ /* Internalize the context */
+ ibp = (krb5_octet *) interprocess_token->value;
+ blen = (size_t) interprocess_token->length;
+ kret = kg_ctx_internalize(context, (krb5_pointer *) &ctx, &ibp, &blen);
+ if (kret) {
+ *minor_status = (OM_uint32) kret;
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return(GSS_S_FAILURE);
+ }
+ krb5_free_context(context);
+
+ ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used);
+
+ *context_handle = (gss_ctx_id_t) ctx;
+
+ *minor_status = 0;
+ return (GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/indicate_mechs.c b/src/lib/gssapi/krb5/indicate_mechs.c
new file mode 100644
index 000000000000..45538cb779aa
--- /dev/null
+++ b/src/lib/gssapi/krb5/indicate_mechs.c
@@ -0,0 +1,37 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_krb5.h"
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_indicate_mechs(minor_status, mech_set)
+ OM_uint32 *minor_status;
+ gss_OID_set *mech_set;
+{
+ return generic_gss_copy_oid_set(minor_status, kg_all_mechs, mech_set);
+}
diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
new file mode 100644
index 000000000000..70f7955ae1ae
--- /dev/null
+++ b/src/lib/gssapi/krb5/init_sec_context.c
@@ -0,0 +1,1104 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2000, 2002, 2003, 2007, 2008 by the Massachusetts Institute of
+ * Technology. All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * The copyright holder's name is not used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <stdlib.h>
+#include <assert.h>
+
+/*
+ * $Id$
+ */
+
+/* XXX This is for debugging only!!! Should become a real bitfield
+ at some point */
+int krb5_gss_dbg_client_expcreds = 0;
+
+/*
+ * Common code which fetches the correct krb5 credentials from the
+ * ccache.
+ */
+static krb5_error_code get_credentials(context, cred, server, now,
+ endtime, out_creds)
+ krb5_context context;
+ krb5_gss_cred_id_t cred;
+ krb5_gss_name_t server;
+ krb5_timestamp now;
+ krb5_timestamp endtime;
+ krb5_creds **out_creds;
+{
+ krb5_error_code code;
+ krb5_creds in_creds, evidence_creds, mcreds, *result_creds = NULL;
+ krb5_flags flags = 0;
+
+ *out_creds = NULL;
+
+ k5_mutex_assert_locked(&cred->lock);
+ memset(&in_creds, 0, sizeof(krb5_creds));
+ memset(&evidence_creds, 0, sizeof(krb5_creds));
+ in_creds.client = in_creds.server = NULL;
+
+ assert(cred->name != NULL);
+
+ in_creds.client = cred->name->princ;
+ in_creds.server = server->princ;
+ in_creds.times.endtime = endtime;
+ in_creds.authdata = NULL;
+ in_creds.keyblock.enctype = 0;
+
+ /*
+ * cred->name is immutable, so there is no need to acquire
+ * cred->name->lock.
+ */
+ if (cred->name->ad_context != NULL) {
+ code = krb5_authdata_export_authdata(context,
+ cred->name->ad_context,
+ AD_USAGE_TGS_REQ,
+ &in_creds.authdata);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ /*
+ * For IAKERB or constrained delegation, only check the cache in this step.
+ * For IAKERB we will ask the server to make any necessary TGS requests;
+ * for constrained delegation we will adjust in_creds and make an S4U2Proxy
+ * request below if the cache lookup fails.
+ */
+ if (cred->impersonator != NULL || cred->iakerb_mech)
+ flags |= KRB5_GC_CACHED;
+
+ code = krb5_get_credentials(context, flags, cred->ccache,
+ &in_creds, &result_creds);
+
+ /*
+ * Try constrained delegation if we have proxy credentials, unless
+ * we are trying to get a ticket to ourselves (in which case we could
+ * just use the evidence ticket directly from cache).
+ */
+ if (code == KRB5_CC_NOTFOUND && cred->impersonator != NULL &&
+ !cred->iakerb_mech &&
+ !krb5_principal_compare(context, cred->impersonator, server->princ)) {
+
+ memset(&mcreds, 0, sizeof(mcreds));
+ mcreds.magic = KV5M_CREDS;
+ mcreds.server = cred->impersonator;
+ mcreds.client = cred->name->princ;
+ code = krb5_cc_retrieve_cred(context, cred->ccache,
+ KRB5_TC_MATCH_AUTHDATA, &mcreds,
+ &evidence_creds);
+ if (code)
+ goto cleanup;
+
+ assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
+ in_creds.client = cred->impersonator;
+ in_creds.second_ticket = evidence_creds.ticket;
+ flags = KRB5_GC_CANONICALIZE | KRB5_GC_CONSTRAINED_DELEGATION;
+ code = krb5_get_credentials(context, flags, cred->ccache,
+ &in_creds, &result_creds);
+ }
+
+ if (code)
+ goto cleanup;
+
+ if (flags & KRB5_GC_CONSTRAINED_DELEGATION) {
+ if (!krb5_principal_compare(context, cred->name->princ,
+ result_creds->client)) {
+ /* server did not support constrained delegation */
+ code = KRB5_KDCREP_MODIFIED;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Enforce a stricter limit (without timeskew forgiveness at the
+ * boundaries) because accept_sec_context code is also similarly
+ * non-forgiving.
+ */
+ if (!krb5_gss_dbg_client_expcreds && result_creds->times.endtime < now) {
+ code = KRB5KRB_AP_ERR_TKT_EXPIRED;
+ goto cleanup;
+ }
+
+ *out_creds = result_creds;
+ result_creds = NULL;
+
+cleanup:
+ krb5_free_authdata(context, in_creds.authdata);
+ krb5_free_cred_contents(context, &evidence_creds);
+ krb5_free_creds(context, result_creds);
+
+ return code;
+}
+struct gss_checksum_data {
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_gss_cred_id_t cred;
+ krb5_checksum md5;
+ krb5_data checksum_data;
+ krb5_gss_ctx_ext_t exts;
+};
+
+#ifdef CFX_EXERCISE
+#include "../../krb5/krb/auth_con.h"
+#endif
+static krb5_error_code KRB5_CALLCONV
+make_gss_checksum (krb5_context context, krb5_auth_context auth_context,
+ void *cksum_data, krb5_data **out)
+{
+ krb5_error_code code;
+ krb5_int32 con_flags;
+ unsigned char *ptr;
+ struct gss_checksum_data *data = cksum_data;
+ krb5_data credmsg;
+ unsigned int junk;
+ krb5_data *finished = NULL;
+ krb5_key send_subkey;
+
+ data->checksum_data.data = 0;
+ credmsg.data = 0;
+ /* build the checksum field */
+
+ if (data->ctx->gss_flags & GSS_C_DELEG_FLAG) {
+ /* first get KRB_CRED message, so we know its length */
+
+ /* clear the time check flag that was set in krb5_auth_con_init() */
+ krb5_auth_con_getflags(context, auth_context, &con_flags);
+ krb5_auth_con_setflags(context, auth_context,
+ con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME);
+
+ assert(data->cred->name != NULL);
+
+ /*
+ * RFC 4121 4.1.1 specifies forwarded credentials must be encrypted in
+ * the session key, but krb5_fwd_tgt_creds will use the send subkey if
+ * it's set in the auth context. Suppress the send subkey
+ * temporarily.
+ */
+ krb5_auth_con_getsendsubkey_k(context, auth_context, &send_subkey);
+ krb5_auth_con_setsendsubkey_k(context, auth_context, NULL);
+
+ code = krb5_fwd_tgt_creds(context, auth_context, 0,
+ data->cred->name->princ, data->ctx->there->princ,
+ data->cred->ccache, 1,
+ &credmsg);
+
+ /* Turn KRB5_AUTH_CONTEXT_DO_TIME back on and reset the send subkey. */
+ krb5_auth_con_setflags(context, auth_context, con_flags);
+ krb5_auth_con_setsendsubkey_k(context, auth_context, send_subkey);
+ krb5_k_free_key(context, send_subkey);
+
+ if (code) {
+ /* don't fail here; just don't accept/do the delegation
+ request */
+ data->ctx->gss_flags &= ~(GSS_C_DELEG_FLAG |
+ GSS_C_DELEG_POLICY_FLAG);
+
+ data->checksum_data.length = 24;
+ } else {
+ if (credmsg.length+28 > KRB5_INT16_MAX) {
+ code = KRB5KRB_ERR_FIELD_TOOLONG;
+ goto cleanup;
+ }
+
+ data->checksum_data.length = 28+credmsg.length;
+ }
+ } else {
+ data->checksum_data.length = 24;
+ }
+#ifdef CFX_EXERCISE
+ if (data->ctx->auth_context->keyblock != NULL
+ && data->ctx->auth_context->keyblock->enctype == 18) {
+ srand(time(0) ^ getpid());
+ /* Our ftp client code stupidly assumes a base64-encoded
+ version of the token will fit in 10K, so don't make this
+ too big. */
+ junk = rand() & 0xff;
+ } else
+ junk = 0;
+#else
+ junk = 0;
+#endif
+
+ assert(data->exts != NULL);
+
+ if (data->exts->iakerb.conv) {
+ krb5_key key;
+
+ code = krb5_auth_con_getsendsubkey_k(context, auth_context, &key);
+ if (code != 0)
+ goto cleanup;
+
+ code = iakerb_make_finished(context, key, data->exts->iakerb.conv,
+ &finished);
+ if (code != 0) {
+ krb5_k_free_key(context, key);
+ goto cleanup;
+ }
+
+ krb5_k_free_key(context, key);
+ data->checksum_data.length += 8 + finished->length;
+ }
+
+ data->checksum_data.length += junk;
+
+ /* now allocate a buffer to hold the checksum data and
+ (maybe) KRB_CRED msg */
+
+ if ((data->checksum_data.data =
+ (char *) xmalloc(data->checksum_data.length)) == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ ptr = (unsigned char *)data->checksum_data.data;
+
+ TWRITE_INT(ptr, data->md5.length, 0);
+ TWRITE_STR(ptr, data->md5.contents, data->md5.length);
+ TWRITE_INT(ptr, data->ctx->gss_flags, 0);
+
+ /* done with this, free it */
+ xfree(data->md5.contents);
+
+ if (credmsg.data) {
+ TWRITE_INT16(ptr, KRB5_GSS_FOR_CREDS_OPTION, 0);
+ TWRITE_INT16(ptr, credmsg.length, 0);
+ TWRITE_STR(ptr, credmsg.data, credmsg.length);
+ }
+ if (data->exts->iakerb.conv) {
+ TWRITE_INT(ptr, KRB5_GSS_EXTS_IAKERB_FINISHED, 1);
+ TWRITE_INT(ptr, finished->length, 1);
+ TWRITE_STR(ptr, finished->data, finished->length);
+ }
+ if (junk)
+ memset(ptr, 'i', junk);
+ *out = &data->checksum_data;
+ code = 0;
+cleanup:
+ krb5_free_data_contents(context, &credmsg);
+ krb5_free_data(context, finished);
+ return code;
+}
+
+static krb5_error_code
+make_ap_req_v1(context, ctx, cred, k_cred, ad_context,
+ chan_bindings, mech_type, token, exts)
+ krb5_context context;
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_gss_cred_id_t cred;
+ krb5_creds *k_cred;
+ krb5_authdata_context ad_context;
+ gss_channel_bindings_t chan_bindings;
+ gss_OID mech_type;
+ gss_buffer_t token;
+ krb5_gss_ctx_ext_t exts;
+{
+ krb5_flags mk_req_flags = 0;
+ krb5_error_code code;
+ struct gss_checksum_data cksum_struct;
+ krb5_checksum md5;
+ krb5_data ap_req;
+ unsigned char *ptr;
+ unsigned char *t;
+ unsigned int tlen;
+
+ k5_mutex_assert_locked(&cred->lock);
+ ap_req.data = 0;
+
+ /* compute the hash of the channel bindings */
+
+ if ((code = kg_checksum_channel_bindings(context, chan_bindings, &md5)))
+ return(code);
+
+ krb5_auth_con_set_req_cksumtype(context, ctx->auth_context,
+ CKSUMTYPE_KG_CB);
+ cksum_struct.md5 = md5;
+ cksum_struct.ctx = ctx;
+ cksum_struct.cred = cred;
+ cksum_struct.checksum_data.data = NULL;
+ cksum_struct.exts = exts;
+ krb5_auth_con_set_checksum_func(context, ctx->auth_context,
+ make_gss_checksum, &cksum_struct);
+
+ /* call mk_req. subkey and ap_req need to be used or destroyed */
+
+ mk_req_flags = AP_OPTS_USE_SUBKEY;
+
+ if (ctx->gss_flags & GSS_C_MUTUAL_FLAG)
+ mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_ETYPE_NEGOTIATION;
+
+ krb5_auth_con_set_authdata_context(context, ctx->auth_context, ad_context);
+ code = krb5_mk_req_extended(context, &ctx->auth_context, mk_req_flags,
+ NULL, k_cred, &ap_req);
+ krb5_auth_con_set_authdata_context(context, ctx->auth_context, NULL);
+ krb5_free_data_contents(context, &cksum_struct.checksum_data);
+ if (code)
+ goto cleanup;
+
+ /* store the interesting stuff from creds and authent */
+ ctx->krb_times = k_cred->times;
+ ctx->krb_flags = k_cred->ticket_flags;
+
+ /* build up the token */
+ if (ctx->gss_flags & GSS_C_DCE_STYLE) {
+ /*
+ * For DCE RPC, do not encapsulate the AP-REQ in the
+ * typical GSS wrapping.
+ */
+ code = data_to_gss(&ap_req, token);
+ if (code)
+ goto cleanup;
+ } else {
+ /* allocate space for the token */
+ tlen = g_token_size((gss_OID) mech_type, ap_req.length);
+
+ if ((t = (unsigned char *) gssalloc_malloc(tlen)) == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ /* fill in the buffer */
+ ptr = t;
+
+ g_make_token_header(mech_type, ap_req.length,
+ &ptr, KG_TOK_CTX_AP_REQ);
+
+ TWRITE_STR(ptr, ap_req.data, ap_req.length);
+
+ /* pass it back */
+
+ token->length = tlen;
+ token->value = (void *) t;
+ }
+
+ code = 0;
+
+cleanup:
+ if (ap_req.data)
+ krb5_free_data_contents(context, &ap_req);
+
+ return (code);
+}
+
+/*
+ * new_connection
+ *
+ * Do the grunt work of setting up a new context.
+ */
+static OM_uint32
+kg_new_connection(
+ OM_uint32 *minor_status,
+ krb5_gss_cred_id_t cred,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ krb5_context context,
+ krb5_gss_ctx_ext_t exts)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_creds *k_cred = NULL;
+ krb5_gss_ctx_id_rec *ctx, *ctx_free;
+ krb5_timestamp now;
+ gss_buffer_desc token;
+ krb5_keyblock *keyblock;
+
+ k5_mutex_assert_locked(&cred->lock);
+ major_status = GSS_S_FAILURE;
+ token.length = 0;
+ token.value = NULL;
+
+ /* make sure the cred is usable for init */
+
+ if ((cred->usage != GSS_C_INITIATE) &&
+ (cred->usage != GSS_C_BOTH)) {
+ *minor_status = 0;
+ return(GSS_S_NO_CRED);
+ }
+
+ /* complain if the input token is non-null */
+
+ if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ /* create the ctx */
+
+ if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
+ == NULL) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ /* fill in the ctx */
+ memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+ ctx->magic = KG_CONTEXT;
+ ctx_free = ctx;
+ if ((code = krb5_auth_con_init(context, &ctx->auth_context)))
+ goto cleanup;
+ krb5_auth_con_setflags(context, ctx->auth_context,
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+
+ /* limit the encryption types negotiated (if requested) */
+ if (cred->req_enctypes) {
+ if ((code = krb5_set_default_tgs_enctypes(context,
+ cred->req_enctypes))) {
+ goto cleanup;
+ }
+ }
+
+ ctx->initiate = 1;
+ ctx->seed_init = 0;
+ ctx->seqstate = 0;
+
+ ctx->gss_flags = req_flags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG |
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
+ GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
+ GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
+ GSS_C_EXTENDED_ERROR_FLAG);
+ ctx->gss_flags |= GSS_C_TRANS_FLAG;
+ if (!cred->suppress_ci_flags)
+ ctx->gss_flags |= (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);
+ if (req_flags & GSS_C_DCE_STYLE)
+ ctx->gss_flags |= GSS_C_MUTUAL_FLAG;
+
+ if ((code = krb5_timeofday(context, &now)))
+ goto cleanup;
+
+ if (time_req == 0 || time_req == GSS_C_INDEFINITE) {
+ ctx->krb_times.endtime = 0;
+ } else {
+ ctx->krb_times.endtime = now + time_req;
+ }
+
+ if ((code = kg_duplicate_name(context, cred->name, &ctx->here)))
+ goto cleanup;
+
+ if ((code = kg_duplicate_name(context, (krb5_gss_name_t)target_name,
+ &ctx->there)))
+ goto cleanup;
+
+ code = get_credentials(context, cred, ctx->there, now,
+ ctx->krb_times.endtime, &k_cred);
+ if (code)
+ goto cleanup;
+
+ ctx->krb_times = k_cred->times;
+
+ /*
+ * GSS_C_DELEG_POLICY_FLAG means to delegate only if the
+ * ok-as-delegate ticket flag is set.
+ */
+ if ((req_flags & GSS_C_DELEG_POLICY_FLAG)
+ && (k_cred->ticket_flags & TKT_FLG_OK_AS_DELEGATE))
+ ctx->gss_flags |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG;
+
+ if (generic_gss_copy_oid(minor_status, mech_type, &ctx->mech_used)
+ != GSS_S_COMPLETE) {
+ code = *minor_status;
+ goto cleanup;
+ }
+ /*
+ * Now try to make it static if at all possible....
+ */
+ ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used);
+
+ {
+ /* gsskrb5 v1 */
+ krb5_int32 seq_temp;
+ if ((code = make_ap_req_v1(context, ctx,
+ cred, k_cred, ctx->here->ad_context,
+ input_chan_bindings,
+ mech_type, &token, exts))) {
+ if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) ||
+ (code == KG_EMPTY_CCACHE))
+ major_status = GSS_S_NO_CRED;
+ if (code == KRB5KRB_AP_ERR_TKT_EXPIRED)
+ major_status = GSS_S_CREDENTIALS_EXPIRED;
+ goto cleanup;
+ }
+
+ krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &seq_temp);
+ ctx->seq_send = seq_temp;
+ code = krb5_auth_con_getsendsubkey(context, ctx->auth_context,
+ &keyblock);
+ if (code != 0)
+ goto cleanup;
+ code = krb5_k_create_key(context, keyblock, &ctx->subkey);
+ krb5_free_keyblock(context, keyblock);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ ctx->enc = NULL;
+ ctx->seq = NULL;
+ ctx->have_acceptor_subkey = 0;
+ code = kg_setup_keys(context, ctx, ctx->subkey, &ctx->cksumtype);
+ if (code != 0)
+ goto cleanup;
+
+ if (!(ctx->gss_flags & GSS_C_MUTUAL_FLAG)) {
+ /* There will be no AP-REP, so set up sequence state now. */
+ ctx->seq_recv = ctx->seq_send;
+ code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
+ (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
+ (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
+ ctx->proto);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ /* compute time_rec */
+ if (time_rec) {
+ if ((code = krb5_timeofday(context, &now)))
+ goto cleanup;
+ *time_rec = ctx->krb_times.endtime - now;
+ }
+
+ /* set the other returns */
+ *output_token = token;
+
+ if (ret_flags)
+ *ret_flags = ctx->gss_flags;
+
+ if (actual_mech_type)
+ *actual_mech_type = mech_type;
+
+ /* return successfully */
+
+ *context_handle = (gss_ctx_id_t) ctx;
+ ctx_free = NULL;
+ if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
+ ctx->established = 0;
+ major_status = GSS_S_CONTINUE_NEEDED;
+ } else {
+ ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
+ ctx->established = 1;
+ major_status = GSS_S_COMPLETE;
+ }
+
+cleanup:
+ krb5_free_creds(context, k_cred);
+ if (ctx_free) {
+ if (ctx_free->auth_context)
+ krb5_auth_con_free(context, ctx_free->auth_context);
+ if (ctx_free->here)
+ kg_release_name(context, &ctx_free->here);
+ if (ctx_free->there)
+ kg_release_name(context, &ctx_free->there);
+ if (ctx_free->subkey)
+ krb5_k_free_key(context, ctx_free->subkey);
+ xfree(ctx_free);
+ }
+
+ *minor_status = code;
+ return (major_status);
+}
+
+/*
+ * mutual_auth
+ *
+ * Handle the reply from the acceptor, if we're doing mutual auth.
+ */
+static OM_uint32
+mutual_auth(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ krb5_context context)
+{
+ OM_uint32 major_status;
+ unsigned char *ptr;
+ char *sptr;
+ krb5_data ap_rep;
+ krb5_ap_rep_enc_part *ap_rep_data;
+ krb5_timestamp now;
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_error *krb_error;
+ krb5_error_code code;
+ krb5int_access kaccess;
+
+ major_status = GSS_S_FAILURE;
+
+ code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+ if (code)
+ goto fail;
+
+ ctx = (krb5_gss_ctx_id_t) *context_handle;
+
+ /* make sure the context is non-established, and that certain
+ arguments are unchanged */
+
+ if ((ctx->established) ||
+ ((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) {
+ code = KG_CONTEXT_ESTABLISHED;
+ goto fail;
+ }
+
+ if (! kg_compare_name(context, ctx->there, (krb5_gss_name_t)target_name)) {
+ (void)krb5_gss_delete_sec_context(minor_status,
+ context_handle, NULL);
+ code = 0;
+ major_status = GSS_S_BAD_NAME;
+ goto fail;
+ }
+
+ /* verify the token and leave the AP_REP message in ap_rep */
+
+ if (input_token == GSS_C_NO_BUFFER) {
+ (void)krb5_gss_delete_sec_context(minor_status,
+ context_handle, NULL);
+ code = 0;
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto fail;
+ }
+
+ ptr = (unsigned char *) input_token->value;
+
+ if (ctx->gss_flags & GSS_C_DCE_STYLE) {
+ /* Raw AP-REP */
+ ap_rep.length = input_token->length;
+ ap_rep.data = (char *)input_token->value;
+ } else if (g_verify_token_header(ctx->mech_used,
+ &(ap_rep.length),
+ &ptr, KG_TOK_CTX_AP_REP,
+ input_token->length, 1)) {
+ if (g_verify_token_header((gss_OID) ctx->mech_used,
+ &(ap_rep.length),
+ &ptr, KG_TOK_CTX_ERROR,
+ input_token->length, 1) == 0) {
+
+ /* Handle a KRB_ERROR message from the server */
+
+ sptr = (char *) ptr; /* PC compiler bug */
+ TREAD_STR(sptr, ap_rep.data, ap_rep.length);
+
+ code = krb5_rd_error(context, &ap_rep, &krb_error);
+ if (code)
+ goto fail;
+ if (krb_error->error)
+ code = (krb5_error_code)krb_error->error + ERROR_TABLE_BASE_krb5;
+ else
+ code = 0;
+ krb5_free_error(context, krb_error);
+ goto fail;
+ } else {
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+ }
+
+ sptr = (char *) ptr; /* PC compiler bug */
+ TREAD_STR(sptr, ap_rep.data, ap_rep.length);
+
+ /* decode the ap_rep */
+ if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep,
+ &ap_rep_data))) {
+ /*
+ * XXX A hack for backwards compatiblity.
+ * To be removed in 1999 -- proven
+ */
+ krb5_auth_con_setuseruserkey(context, ctx->auth_context,
+ &ctx->subkey->keyblock);
+ if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep,
+ &ap_rep_data)))
+ goto fail;
+ }
+
+ /* store away the sequence number */
+ ctx->seq_recv = ap_rep_data->seq_number;
+ code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
+ (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
+ (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
+ ctx->proto);
+ if (code) {
+ krb5_free_ap_rep_enc_part(context, ap_rep_data);
+ goto fail;
+ }
+
+ if (ap_rep_data->subkey != NULL &&
+ (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) ||
+ ap_rep_data->subkey->enctype != ctx->subkey->keyblock.enctype)) {
+ /* Keep acceptor's subkey. */
+ ctx->have_acceptor_subkey = 1;
+ code = krb5_k_create_key(context, ap_rep_data->subkey,
+ &ctx->acceptor_subkey);
+ if (code) {
+ krb5_free_ap_rep_enc_part(context, ap_rep_data);
+ goto fail;
+ }
+ code = kg_setup_keys(context, ctx, ctx->acceptor_subkey,
+ &ctx->acceptor_subkey_cksumtype);
+ if (code) {
+ krb5_free_ap_rep_enc_part(context, ap_rep_data);
+ goto fail;
+ }
+ }
+ /* free the ap_rep_data */
+ krb5_free_ap_rep_enc_part(context, ap_rep_data);
+
+ if (ctx->gss_flags & GSS_C_DCE_STYLE) {
+ krb5_data outbuf;
+
+ code = krb5_mk_rep_dce(context, ctx->auth_context, &outbuf);
+ if (code)
+ goto fail;
+
+ code = data_to_gss(&outbuf, output_token);
+ if (code)
+ goto fail;
+ }
+
+ /* set established */
+ ctx->established = 1;
+
+ /* set returns */
+
+ if (time_rec) {
+ if ((code = krb5_timeofday(context, &now)))
+ goto fail;
+ *time_rec = ctx->krb_times.endtime - now;
+ }
+
+ if (ret_flags)
+ *ret_flags = ctx->gss_flags;
+
+ if (actual_mech_type)
+ *actual_mech_type = mech_type;
+
+ /* success */
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+
+fail:
+ (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
+
+ *minor_status = code;
+ return (major_status);
+}
+
+OM_uint32
+krb5_gss_init_sec_context_ext(
+ OM_uint32 *minor_status,
+ gss_cred_id_t claimant_cred_handle,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ krb5_gss_ctx_ext_t exts)
+{
+ krb5_context context;
+ gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
+ krb5_gss_cred_id_t cred;
+ krb5_error_code kerr;
+ OM_uint32 major_status;
+ OM_uint32 tmp_min_stat;
+
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ kerr = krb5_gss_init_context(&context);
+ if (kerr) {
+ *minor_status = kerr;
+ return GSS_S_FAILURE;
+ }
+ if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) {
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return GSS_S_FAILURE;
+ }
+ } else {
+ context = ((krb5_gss_ctx_id_rec *)*context_handle)->k5_context;
+ }
+
+ /* set up return values so they can be "freed" successfully */
+
+ major_status = GSS_S_FAILURE; /* Default major code */
+ output_token->length = 0;
+ output_token->value = NULL;
+ if (actual_mech_type)
+ *actual_mech_type = NULL;
+
+ /* verify the mech_type */
+
+ if (mech_type == GSS_C_NULL_OID || g_OID_equal(mech_type, gss_mech_krb5)) {
+ mech_type = (gss_OID) gss_mech_krb5;
+ } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) {
+ mech_type = (gss_OID) gss_mech_krb5_old;
+ } else if (g_OID_equal(mech_type, gss_mech_krb5_wrong)) {
+ mech_type = (gss_OID) gss_mech_krb5_wrong;
+ } else if (g_OID_equal(mech_type, gss_mech_iakerb)) {
+ mech_type = (gss_OID) gss_mech_iakerb;
+ } else {
+ *minor_status = 0;
+ if (*context_handle == GSS_C_NO_CONTEXT)
+ krb5_free_context(context);
+ return(GSS_S_BAD_MECH);
+ }
+
+ /* is this a new connection or not? */
+
+ /*SUPPRESS 29*/
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ /* verify the credential, or use the default */
+ /*SUPPRESS 29*/
+ if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
+ major_status = kg_get_defcred(minor_status, &defcred);
+ if (major_status && GSS_ERROR(major_status)) {
+ if (*context_handle == GSS_C_NO_CONTEXT)
+ krb5_free_context(context);
+ return(major_status);
+ }
+ claimant_cred_handle = defcred;
+ }
+
+ major_status = kg_cred_resolve(minor_status, context,
+ claimant_cred_handle, target_name);
+ if (GSS_ERROR(major_status)) {
+ save_error_info(*minor_status, context);
+ krb5_gss_release_cred(&tmp_min_stat, &defcred);
+ if (*context_handle == GSS_C_NO_CONTEXT)
+ krb5_free_context(context);
+ return(major_status);
+ }
+ cred = (krb5_gss_cred_id_t)claimant_cred_handle;
+
+ major_status = kg_new_connection(minor_status, cred, context_handle,
+ target_name, mech_type, req_flags,
+ time_req, input_chan_bindings,
+ input_token, actual_mech_type,
+ output_token, ret_flags, time_rec,
+ context, exts);
+ k5_mutex_unlock(&cred->lock);
+ krb5_gss_release_cred(&tmp_min_stat, &defcred);
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ save_error_info (*minor_status, context);
+ krb5_free_context(context);
+ } else
+ ((krb5_gss_ctx_id_rec *) *context_handle)->k5_context = context;
+ } else {
+ /* mutual_auth doesn't care about the credentials */
+ major_status = mutual_auth(minor_status, context_handle,
+ target_name, mech_type, req_flags,
+ time_req, input_chan_bindings,
+ input_token, actual_mech_type,
+ output_token, ret_flags, time_rec,
+ context);
+ /* If context_handle is now NO_CONTEXT, mutual_auth called
+ delete_sec_context, which would've zapped the krb5 context
+ too. */
+ }
+
+ return(major_status);
+}
+
+#ifndef _WIN32
+k5_mutex_t kg_kdc_flag_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+static int kdc_flag = 0;
+#endif
+
+krb5_error_code
+krb5_gss_init_context (krb5_context *ctxp)
+{
+ krb5_error_code err;
+#ifndef _WIN32
+ int is_kdc;
+#endif
+
+ err = gss_krb5int_initialize_library();
+ if (err)
+ return err;
+#ifndef _WIN32
+ k5_mutex_lock(&kg_kdc_flag_mutex);
+ is_kdc = kdc_flag;
+ k5_mutex_unlock(&kg_kdc_flag_mutex);
+
+ if (is_kdc)
+ return krb5int_init_context_kdc(ctxp);
+#endif
+
+ return krb5_init_context(ctxp);
+}
+
+#ifndef _WIN32
+OM_uint32
+krb5int_gss_use_kdc_context(OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ const gss_OID desired_object,
+ gss_buffer_t value)
+{
+ OM_uint32 err;
+
+ *minor_status = 0;
+
+ err = gss_krb5int_initialize_library();
+ if (err)
+ return err;
+ k5_mutex_lock(&kg_kdc_flag_mutex);
+ kdc_flag = 1;
+ k5_mutex_unlock(&kg_kdc_flag_mutex);
+ return GSS_S_COMPLETE;
+}
+#endif
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
+ context_handle, target_name, mech_type,
+ req_flags, time_req, input_chan_bindings,
+ input_token, actual_mech_type, output_token,
+ ret_flags, time_rec)
+ OM_uint32 *minor_status;
+ gss_cred_id_t claimant_cred_handle;
+ gss_ctx_id_t *context_handle;
+ gss_name_t target_name;
+ gss_OID mech_type;
+ OM_uint32 req_flags;
+ OM_uint32 time_req;
+ gss_channel_bindings_t input_chan_bindings;
+ gss_buffer_t input_token;
+ gss_OID *actual_mech_type;
+ gss_buffer_t output_token;
+ OM_uint32 *ret_flags;
+ OM_uint32 *time_rec;
+{
+ krb5_gss_ctx_ext_rec exts;
+
+ memset(&exts, 0, sizeof(exts));
+
+ return krb5_gss_init_sec_context_ext(minor_status,
+ claimant_cred_handle,
+ context_handle,
+ target_name,
+ mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ &exts);
+}
diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c
new file mode 100644
index 000000000000..9024b3c7ea9c
--- /dev/null
+++ b/src/lib/gssapi/krb5/inq_context.c
@@ -0,0 +1,312 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * The copyright holder's name is not used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * The copyright holder's name is not used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_context(minor_status, context_handle, initiator_name,
+ acceptor_name, lifetime_rec, mech_type, ret_flags,
+ locally_initiated, opened)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ gss_name_t *initiator_name;
+ gss_name_t *acceptor_name;
+ OM_uint32 *lifetime_rec;
+ gss_OID *mech_type;
+ OM_uint32 *ret_flags;
+ int *locally_initiated;
+ int *opened;
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_gss_name_t initiator, acceptor;
+ krb5_timestamp now;
+ krb5_deltat lifetime;
+
+ if (initiator_name)
+ *initiator_name = (gss_name_t) NULL;
+ if (acceptor_name)
+ *acceptor_name = (gss_name_t) NULL;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+ context = ctx->k5_context;
+
+ /* RFC 2743 states that a partially completed context must return
+ * flags, locally_initiated, and open, and *may* return mech_type. */
+ if (ctx->established) {
+ initiator = NULL;
+ acceptor = NULL;
+
+ if ((code = krb5_timeofday(context, &now))) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ return(GSS_S_FAILURE);
+ }
+
+ /* Add the maximum allowable clock skew as a grace period for context
+ * expiration, just as we do for the ticket during authentication. */
+ lifetime = ctx->krb_times.endtime - now;
+ if (!ctx->initiate)
+ lifetime += context->clockskew;
+ if (lifetime < 0)
+ lifetime = 0;
+
+ if (initiator_name) {
+ code = kg_duplicate_name(context,
+ ctx->initiate ? ctx->here : ctx->there,
+ &initiator);
+ if (code) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ return(GSS_S_FAILURE);
+ }
+ }
+
+ if (acceptor_name) {
+ code = kg_duplicate_name(context,
+ ctx->initiate ? ctx->there : ctx->here,
+ &acceptor);
+ if (code) {
+ if (initiator)
+ kg_release_name(context, &initiator);
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ return(GSS_S_FAILURE);
+ }
+ }
+
+ if (initiator_name)
+ *initiator_name = (gss_name_t) initiator;
+
+ if (acceptor_name)
+ *acceptor_name = (gss_name_t) acceptor;
+
+ if (lifetime_rec)
+ *lifetime_rec = lifetime;
+ } else {
+ lifetime = 0;
+ if (initiator_name)
+ *initiator_name = GSS_C_NO_NAME;
+
+ if (acceptor_name)
+ *acceptor_name = GSS_C_NO_NAME;
+
+ if (lifetime_rec)
+ *lifetime_rec = 0;
+ }
+
+ if (mech_type)
+ *mech_type = (gss_OID) ctx->mech_used;
+
+ if (ret_flags)
+ *ret_flags = ctx->gss_flags;
+
+ if (locally_initiated)
+ *locally_initiated = ctx->initiate;
+
+ if (opened)
+ *opened = ctx->established;
+
+ *minor_status = 0;
+ if (ctx->established)
+ return((lifetime == 0)?GSS_S_CONTEXT_EXPIRED:GSS_S_COMPLETE);
+ else
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gss_krb5int_inq_session_key(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_key key;
+ gss_buffer_desc keyvalue, keyinfo;
+ OM_uint32 major_status, minor;
+ unsigned char oid_buf[GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH + 6];
+ gss_OID_desc oid;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+ key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey : ctx->subkey;
+
+ keyvalue.value = key->keyblock.contents;
+ keyvalue.length = key->keyblock.length;
+
+ major_status = generic_gss_add_buffer_set_member(minor_status, &keyvalue, data_set);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ oid.elements = oid_buf;
+ oid.length = sizeof(oid_buf);
+
+ major_status = generic_gss_oid_compose(minor_status,
+ GSS_KRB5_SESSION_KEY_ENCTYPE_OID,
+ GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
+ key->keyblock.enctype,
+ &oid);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ keyinfo.value = oid.elements;
+ keyinfo.length = oid.length;
+
+ major_status = generic_gss_add_buffer_set_member(minor_status, &keyinfo, data_set);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ return GSS_S_COMPLETE;
+
+cleanup:
+ if (*data_set != GSS_C_NO_BUFFER_SET) {
+ if ((*data_set)->count != 0)
+ memset((*data_set)->elements[0].value, 0, (*data_set)->elements[0].length);
+ gss_release_buffer_set(&minor, data_set);
+ }
+
+ return major_status;
+}
+
+OM_uint32
+gss_krb5int_extract_authz_data_from_sec_context(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ OM_uint32 major_status;
+ krb5_gss_ctx_id_rec *ctx;
+ int ad_type = 0;
+ size_t i;
+
+ *data_set = GSS_C_NO_BUFFER_SET;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ major_status = generic_gss_oid_decompose(minor_status,
+ GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID,
+ GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH,
+ desired_object,
+ &ad_type);
+ if (major_status != GSS_S_COMPLETE || ad_type == 0) {
+ *minor_status = ENOENT;
+ return GSS_S_FAILURE;
+ }
+
+ if (ctx->authdata != NULL) {
+ for (i = 0; ctx->authdata[i] != NULL; i++) {
+ if (ctx->authdata[i]->ad_type == ad_type) {
+ gss_buffer_desc ad_data;
+
+ ad_data.length = ctx->authdata[i]->length;
+ ad_data.value = ctx->authdata[i]->contents;
+
+ major_status = generic_gss_add_buffer_set_member(minor_status,
+ &ad_data, data_set);
+ if (GSS_ERROR(major_status))
+ break;
+ }
+ }
+ }
+
+ if (GSS_ERROR(major_status)) {
+ OM_uint32 tmp;
+
+ generic_gss_release_buffer_set(&tmp, data_set);
+ }
+
+ return major_status;
+}
+
+OM_uint32
+gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_oid,
+ gss_buffer_set_t *data_set)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ gss_buffer_desc rep;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ rep.value = &ctx->krb_times.authtime;
+ rep.length = sizeof(ctx->krb_times.authtime);
+
+ return generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
+}
diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c
new file mode 100644
index 000000000000..4e35a056316f
--- /dev/null
+++ b/src/lib/gssapi/krb5/inq_cred.c
@@ -0,0 +1,247 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2000, 2007 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret,
+ cred_usage, mechanisms)
+ OM_uint32 *minor_status;
+ gss_cred_id_t cred_handle;
+ gss_name_t *name;
+ OM_uint32 *lifetime_ret;
+ gss_cred_usage_t *cred_usage;
+ gss_OID_set *mechanisms;
+{
+ krb5_context context;
+ gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
+ krb5_gss_cred_id_t cred = NULL;
+ krb5_error_code code;
+ krb5_timestamp now;
+ krb5_deltat lifetime;
+ krb5_gss_name_t ret_name;
+ krb5_principal princ;
+ gss_OID_set mechs;
+ OM_uint32 major, tmpmin, ret;
+
+ ret = GSS_S_FAILURE;
+ ret_name = NULL;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (name) *name = NULL;
+ if (mechanisms) *mechanisms = NULL;
+
+ /* check for default credential */
+ /*SUPPRESS 29*/
+ if (cred_handle == GSS_C_NO_CREDENTIAL) {
+ major = kg_get_defcred(minor_status, &defcred);
+ if (GSS_ERROR(major)) {
+ krb5_free_context(context);
+ return(major);
+ }
+ cred_handle = defcred;
+ }
+
+ major = kg_cred_resolve(minor_status, context, cred_handle, GSS_C_NO_NAME);
+ if (GSS_ERROR(major)) {
+ krb5_gss_release_cred(minor_status, &defcred);
+ krb5_free_context(context);
+ return(major);
+ }
+ cred = (krb5_gss_cred_id_t)cred_handle;
+
+ if ((code = krb5_timeofday(context, &now))) {
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ if (cred->expire > 0) {
+ if ((lifetime = cred->expire - now) < 0)
+ lifetime = 0;
+ }
+ else
+ lifetime = GSS_C_INDEFINITE;
+
+ if (name) {
+ if (cred->name) {
+ code = kg_duplicate_name(context, cred->name, &ret_name);
+ } else if ((cred->usage == GSS_C_ACCEPT || cred->usage == GSS_C_BOTH)
+ && cred->keytab != NULL) {
+ /* This is a default acceptor cred; use a name from the keytab if
+ * we can. */
+ code = k5_kt_get_principal(context, cred->keytab, &princ);
+ if (code == 0) {
+ code = kg_init_name(context, princ, NULL, NULL, NULL,
+ KG_INIT_NAME_NO_COPY, &ret_name);
+ if (code)
+ krb5_free_principal(context, princ);
+ } else if (code == KRB5_KT_NOTFOUND)
+ code = 0;
+ }
+ if (code) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ ret = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
+ if (mechanisms) {
+ if (GSS_ERROR(ret = generic_gss_create_empty_oid_set(minor_status,
+ &mechs)) ||
+ GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5_old,
+ &mechs)) ||
+ GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5,
+ &mechs))) {
+ if (ret_name)
+ kg_release_name(context, &ret_name);
+ /* *minor_status set above */
+ goto fail;
+ }
+ }
+
+ if (name) {
+ if (ret_name != NULL)
+ *name = (gss_name_t) ret_name;
+ else
+ *name = GSS_C_NO_NAME;
+ }
+
+ if (lifetime_ret)
+ *lifetime_ret = lifetime;
+
+ if (cred_usage)
+ *cred_usage = cred->usage;
+ k5_mutex_unlock(&cred->lock);
+
+ if (mechanisms)
+ *mechanisms = mechs;
+
+ if (cred_handle == GSS_C_NO_CREDENTIAL)
+ krb5_gss_release_cred(minor_status, (gss_cred_id_t *)&cred);
+
+ krb5_free_context(context);
+ *minor_status = 0;
+ return((lifetime == 0)?GSS_S_CREDENTIALS_EXPIRED:GSS_S_COMPLETE);
+fail:
+ k5_mutex_unlock(&cred->lock);
+ krb5_gss_release_cred(&tmpmin, &defcred);
+ krb5_free_context(context);
+ return ret;
+}
+
+/* V2 interface */
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_cred_by_mech(minor_status, cred_handle,
+ mech_type, name, initiator_lifetime,
+ acceptor_lifetime, cred_usage)
+ OM_uint32 *minor_status;
+ gss_cred_id_t cred_handle;
+ gss_OID mech_type;
+ gss_name_t *name;
+ OM_uint32 *initiator_lifetime;
+ OM_uint32 *acceptor_lifetime;
+ gss_cred_usage_t *cred_usage;
+{
+ krb5_gss_cred_id_t cred;
+ OM_uint32 lifetime;
+ OM_uint32 mstat;
+
+ cred = (krb5_gss_cred_id_t) cred_handle;
+ mstat = krb5_gss_inquire_cred(minor_status,
+ cred_handle,
+ name,
+ &lifetime,
+ cred_usage,
+ (gss_OID_set *) NULL);
+ if (mstat == GSS_S_COMPLETE) {
+ if (cred &&
+ ((cred->usage == GSS_C_INITIATE) ||
+ (cred->usage == GSS_C_BOTH)) &&
+ initiator_lifetime)
+ *initiator_lifetime = lifetime;
+ if (cred &&
+ ((cred->usage == GSS_C_ACCEPT) ||
+ (cred->usage == GSS_C_BOTH)) &&
+ acceptor_lifetime)
+ *acceptor_lifetime = lifetime;
+ }
+ return(mstat);
+}
diff --git a/src/lib/gssapi/krb5/inq_names.c b/src/lib/gssapi/krb5/inq_names.c
new file mode 100644
index 000000000000..b326adbb5f23
--- /dev/null
+++ b/src/lib/gssapi/krb5/inq_names.c
@@ -0,0 +1,100 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/inq_names.c - Return nametypes supported by krb5 mech */
+/*
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_names_for_mech(minor_status, mechanism, name_types)
+ OM_uint32 *minor_status;
+ gss_OID mechanism;
+ gss_OID_set *name_types;
+{
+ OM_uint32 major, minor;
+
+ /*
+ * We only know how to handle our own mechanism.
+ */
+ if ((mechanism != GSS_C_NULL_OID) &&
+ !g_OID_equal(gss_mech_krb5, mechanism) &&
+ !g_OID_equal(gss_mech_krb5_old, mechanism) &&
+ !g_OID_equal(gss_mech_krb5_wrong, mechanism) &&
+ !g_OID_equal(gss_mech_iakerb, mechanism)) {
+ *minor_status = 0;
+ return(GSS_S_BAD_MECH);
+ }
+
+ /* We're okay. Create an empty OID set */
+ major = generic_gss_create_empty_oid_set(minor_status, name_types);
+ if (major == GSS_S_COMPLETE) {
+ /* Now add our members. */
+ if (
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_user_name,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_machine_uid_name,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_string_uid_name,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_service_name,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_service_name_v2,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_exported_name,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_krb5_name,
+ name_types)
+ ) == GSS_S_COMPLETE) &&
+ ((major = generic_gss_add_oid_set_member(minor_status,
+ GSS_C_NT_COMPOSITE_EXPORT,
+ name_types)
+ ) == GSS_S_COMPLETE)
+ ) {
+ major = generic_gss_add_oid_set_member(minor_status,
+ gss_nt_krb5_principal,
+ name_types);
+ }
+
+ /*
+ * If we choked, then release the set, but don't overwrite the minor
+ * status with the release call.
+ */
+ if (major != GSS_S_COMPLETE)
+ (void) generic_gss_release_oid_set(&minor, name_types);
+ }
+ return(major);
+}
diff --git a/src/lib/gssapi/krb5/k5seal.c b/src/lib/gssapi/krb5/k5seal.c
new file mode 100644
index 000000000000..4da531b58245
--- /dev/null
+++ b/src/lib/gssapi/krb5/k5seal.c
@@ -0,0 +1,413 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+
+#include <assert.h>
+
+static krb5_error_code
+make_seal_token_v1 (krb5_context context,
+ krb5_key enc,
+ krb5_key seq,
+ uint64_t *seqnum,
+ int direction,
+ gss_buffer_t text,
+ gss_buffer_t token,
+ int signalg,
+ size_t cksum_size,
+ int sealalg,
+ int do_encrypt,
+ int toktype,
+ gss_OID oid)
+{
+ krb5_error_code code;
+ size_t sumlen;
+ char *data_ptr;
+ krb5_data plaind;
+ krb5_checksum md5cksum;
+ krb5_checksum cksum;
+ /* msglen contains the message length
+ * we are signing/encrypting. tmsglen
+ * contains the length of the message
+ * we plan to write out to the token.
+ * tlen is the length of the token
+ * including header. */
+ unsigned int conflen=0, tmsglen, tlen, msglen;
+ unsigned char *t, *ptr;
+ unsigned char *plain;
+ unsigned char pad;
+ krb5_keyusage sign_usage = KG_USAGE_SIGN;
+
+
+ assert((!do_encrypt) || (toktype == KG_TOK_SEAL_MSG));
+ /* create the token buffer */
+ /* Do we need confounder? */
+ if (do_encrypt || toktype == KG_TOK_SEAL_MSG)
+ conflen = kg_confounder_size(context, enc->keyblock.enctype);
+ else conflen = 0;
+
+ if (toktype == KG_TOK_SEAL_MSG) {
+ switch (sealalg) {
+ case SEAL_ALG_MICROSOFT_RC4:
+ msglen = conflen + text->length+1;
+ pad = 1;
+ break;
+ default:
+ /* XXX knows that des block size is 8 */
+ msglen = (conflen+text->length+8)&(~7);
+ pad = 8-(text->length%8);
+ }
+ tmsglen = msglen;
+ } else {
+ tmsglen = 0;
+ msglen = text->length;
+ pad = 0;
+ }
+ tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen);
+
+ if ((t = (unsigned char *) gssalloc_malloc(tlen)) == NULL)
+ return(ENOMEM);
+
+ /*** fill in the token */
+
+ ptr = t;
+ g_make_token_header(oid, 14+cksum_size+tmsglen, &ptr, toktype);
+
+ /* 0..1 SIGN_ALG */
+ store_16_le(signalg, &ptr[0]);
+
+ /* 2..3 SEAL_ALG or Filler */
+ if ((toktype == KG_TOK_SEAL_MSG) && do_encrypt) {
+ store_16_le(sealalg, &ptr[2]);
+ } else {
+ /* No seal */
+ ptr[2] = 0xff;
+ ptr[3] = 0xff;
+ }
+
+ /* 4..5 Filler */
+ ptr[4] = 0xff;
+ ptr[5] = 0xff;
+
+ /* pad the plaintext, encrypt if needed, and stick it in the token */
+
+ /* initialize the the cksum */
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
+ break;
+ case SGN_ALG_HMAC_MD5:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
+ if (toktype != KG_TOK_SEAL_MSG)
+ sign_usage = 15;
+ break;
+ default:
+ case SGN_ALG_DES_MAC:
+ abort ();
+ }
+
+ code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
+ if (code) {
+ gssalloc_free(t);
+ return(code);
+ }
+ md5cksum.length = sumlen;
+
+
+ if ((plain = (unsigned char *) xmalloc(msglen ? msglen : 1)) == NULL) {
+ gssalloc_free(t);
+ return(ENOMEM);
+ }
+
+ if (conflen) {
+ if ((code = kg_make_confounder(context, enc->keyblock.enctype,
+ plain))) {
+ xfree(plain);
+ gssalloc_free(t);
+ return(code);
+ }
+ }
+
+ memcpy(plain+conflen, text->value, text->length);
+ if (pad) memset(plain+conflen+text->length, pad, pad);
+
+ /* compute the checksum */
+
+ /* 8 = head of token body as specified by mech spec */
+ if (! (data_ptr = xmalloc(8 + msglen))) {
+ xfree(plain);
+ gssalloc_free(t);
+ return(ENOMEM);
+ }
+ (void) memcpy(data_ptr, ptr-2, 8);
+ (void) memcpy(data_ptr+8, plain, msglen);
+ plaind.length = 8 + msglen;
+ plaind.data = data_ptr;
+ code = krb5_k_make_checksum(context, md5cksum.checksum_type, seq,
+ sign_usage, &plaind, &md5cksum);
+ xfree(data_ptr);
+
+ if (code) {
+ xfree(plain);
+ gssalloc_free(t);
+ return(code);
+ }
+ switch(signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case 3:
+
+ code = kg_encrypt_inplace(context, seq, KG_USAGE_SEAL,
+ (g_OID_equal(oid, gss_mech_krb5_old) ?
+ seq->keyblock.contents : NULL),
+ md5cksum.contents, 16);
+ if (code) {
+ krb5_free_checksum_contents(context, &md5cksum);
+ xfree (plain);
+ gssalloc_free(t);
+ return code;
+ }
+
+ cksum.length = cksum_size;
+ cksum.contents = md5cksum.contents + 16 - cksum.length;
+
+ memcpy(ptr+14, cksum.contents, cksum.length);
+ break;
+
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ /*
+ * Using key derivation, the call to krb5_c_make_checksum
+ * already dealt with encrypting.
+ */
+ if (md5cksum.length != cksum_size)
+ abort ();
+ memcpy (ptr+14, md5cksum.contents, md5cksum.length);
+ break;
+ case SGN_ALG_HMAC_MD5:
+ memcpy (ptr+14, md5cksum.contents, cksum_size);
+ break;
+ }
+
+ krb5_free_checksum_contents(context, &md5cksum);
+
+ /* create the seq_num */
+
+ if ((code = kg_make_seq_num(context, seq, direction?0:0xff,
+ (krb5_ui_4)*seqnum, ptr+14, ptr+6))) {
+ xfree (plain);
+ gssalloc_free(t);
+ return(code);
+ }
+
+ if (do_encrypt) {
+ switch(sealalg) {
+ case SEAL_ALG_MICROSOFT_RC4:
+ {
+ unsigned char bigend_seqnum[4];
+ krb5_keyblock *enc_key;
+ int i;
+ store_32_be(*seqnum, bigend_seqnum);
+ code = krb5_k_key_keyblock(context, enc, &enc_key);
+ if (code)
+ {
+ xfree(plain);
+ gssalloc_free(t);
+ return(code);
+ }
+ assert (enc_key->length == 16);
+ for (i = 0; i <= 15; i++)
+ ((char *) enc_key->contents)[i] ^=0xf0;
+ code = kg_arcfour_docrypt (enc_key, 0,
+ bigend_seqnum, 4,
+ plain, tmsglen,
+ ptr+14+cksum_size);
+ krb5_free_keyblock (context, enc_key);
+ if (code)
+ {
+ xfree(plain);
+ gssalloc_free(t);
+ return(code);
+ }
+ }
+ break;
+ default:
+ if ((code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL,
+ (krb5_pointer) plain,
+ (krb5_pointer) (ptr+cksum_size+14),
+ tmsglen))) {
+ xfree(plain);
+ gssalloc_free(t);
+ return(code);
+ }
+ }
+ }else {
+ if (tmsglen)
+ memcpy(ptr+14+cksum_size, plain, tmsglen);
+ }
+ xfree(plain);
+
+
+ /* that's it. return the token */
+
+ (*seqnum)++;
+ *seqnum &= 0xffffffffL;
+
+ token->length = tlen;
+ token->value = (void *) t;
+
+ return(0);
+}
+
+/* if signonly is true, ignore conf_req, conf_state,
+ and do not encode the ENC_TYPE, MSG_LENGTH, or MSG_TEXT fields */
+
+OM_uint32
+kg_seal(minor_status, context_handle, conf_req_flag, qop_req,
+ input_message_buffer, conf_state, output_message_buffer, toktype)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ int conf_req_flag;
+ gss_qop_t qop_req;
+ gss_buffer_t input_message_buffer;
+ int *conf_state;
+ gss_buffer_t output_message_buffer;
+ int toktype;
+{
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_error_code code;
+ krb5_context context;
+
+ output_message_buffer->length = 0;
+ output_message_buffer->value = NULL;
+
+ /* Only default qop or matching established cryptosystem is allowed.
+
+ There are NO EXTENSIONS to this set for AES and friends! The
+ new spec says "just use 0". The old spec plus extensions would
+ actually allow for certain non-zero values. Fix this to handle
+ them later. */
+ if (qop_req != 0) {
+ *minor_status = (OM_uint32) G_UNKNOWN_QOP;
+ return GSS_S_BAD_QOP;
+ }
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return(GSS_S_NO_CONTEXT);
+ }
+
+ context = ctx->k5_context;
+ switch (ctx->proto)
+ {
+ case 0:
+ code = make_seal_token_v1(context, ctx->enc, ctx->seq,
+ &ctx->seq_send, ctx->initiate,
+ input_message_buffer, output_message_buffer,
+ ctx->signalg, ctx->cksum_size, ctx->sealalg,
+ conf_req_flag, toktype, ctx->mech_used);
+ break;
+ case 1:
+ code = gss_krb5int_make_seal_token_v3(context, ctx,
+ input_message_buffer,
+ output_message_buffer,
+ conf_req_flag, toktype);
+ break;
+ default:
+ code = G_UNKNOWN_QOP; /* XXX */
+ break;
+ }
+
+ if (code) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ return(GSS_S_FAILURE);
+ }
+
+ if (conf_state)
+ *conf_state = conf_req_flag;
+
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_wrap(minor_status, context_handle, conf_req_flag,
+ qop_req, input_message_buffer, conf_state,
+ output_message_buffer)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ int conf_req_flag;
+ gss_qop_t qop_req;
+ gss_buffer_t input_message_buffer;
+ int *conf_state;
+ gss_buffer_t output_message_buffer;
+{
+ return(kg_seal(minor_status, context_handle, conf_req_flag,
+ qop_req, input_message_buffer, conf_state,
+ output_message_buffer, KG_TOK_WRAP_MSG));
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_get_mic(minor_status, context_handle, qop_req,
+ message_buffer, message_token)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ gss_qop_t qop_req;
+ gss_buffer_t message_buffer;
+ gss_buffer_t message_token;
+{
+ return(kg_seal(minor_status, context_handle, 0,
+ qop_req, message_buffer, NULL,
+ message_token, KG_TOK_MIC_MSG));
+}
diff --git a/src/lib/gssapi/krb5/k5sealiov.c b/src/lib/gssapi/krb5/k5sealiov.c
new file mode 100644
index 000000000000..88caa856f86a
--- /dev/null
+++ b/src/lib/gssapi/krb5/k5sealiov.c
@@ -0,0 +1,557 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/k5sealiov.c */
+/*
+ * Copyright 2008, 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+static krb5_error_code
+make_seal_token_v1_iov(krb5_context context,
+ krb5_gss_ctx_id_rec *ctx,
+ int conf_req_flag,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ krb5_error_code code = 0;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t padding;
+ gss_iov_buffer_t trailer;
+ krb5_checksum md5cksum;
+ krb5_checksum cksum;
+ size_t k5_headerlen = 0, k5_trailerlen = 0;
+ size_t data_length = 0, assoc_data_length = 0;
+ size_t tmsglen = 0, tlen;
+ unsigned char *ptr;
+ krb5_keyusage sign_usage = KG_USAGE_SIGN;
+
+ md5cksum.length = cksum.length = 0;
+ md5cksum.contents = cksum.contents = NULL;
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ if (header == NULL)
+ return EINVAL;
+
+ padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ if (padding == NULL && toktype == KG_TOK_WRAP_MSG &&
+ (ctx->gss_flags & GSS_C_DCE_STYLE) == 0)
+ return EINVAL;
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ if (trailer != NULL)
+ trailer->buffer.length = 0;
+
+ /* Determine confounder length */
+ if (toktype == KG_TOK_WRAP_MSG || conf_req_flag)
+ k5_headerlen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
+
+ /* Check padding length */
+ if (toktype == KG_TOK_WRAP_MSG) {
+ size_t k5_padlen = (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) ? 1 : 8;
+ size_t gss_padlen;
+ size_t conf_data_length;
+
+ kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
+ conf_data_length = k5_headerlen + data_length - assoc_data_length;
+
+ if (k5_padlen == 1)
+ gss_padlen = 1; /* one byte to indicate one byte of padding */
+ else
+ gss_padlen = k5_padlen - (conf_data_length % k5_padlen);
+
+ if (ctx->gss_flags & GSS_C_DCE_STYLE) {
+ /* DCE will pad the actual data itself; padding buffer optional and will be zeroed */
+ gss_padlen = 0;
+
+ if (conf_data_length % k5_padlen)
+ code = KRB5_BAD_MSIZE;
+ } else if (padding->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
+ code = kg_allocate_iov(padding, gss_padlen);
+ } else if (padding->buffer.length < gss_padlen) {
+ code = KRB5_BAD_MSIZE;
+ }
+ if (code != 0)
+ goto cleanup;
+
+ /* Initialize padding buffer to pad itself */
+ if (padding != NULL) {
+ padding->buffer.length = gss_padlen;
+ memset(padding->buffer.value, (int)gss_padlen, gss_padlen);
+ }
+
+ if (ctx->gss_flags & GSS_C_DCE_STYLE)
+ tmsglen = k5_headerlen; /* confounder length */
+ else
+ tmsglen = conf_data_length + padding->buffer.length;
+ }
+
+ /* Determine token size */
+ tlen = g_token_size(ctx->mech_used, 14 + ctx->cksum_size + tmsglen);
+
+ k5_headerlen += tlen - tmsglen;
+
+ if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = kg_allocate_iov(header, k5_headerlen);
+ else if (header->buffer.length < k5_headerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+
+ header->buffer.length = k5_headerlen;
+
+ ptr = (unsigned char *)header->buffer.value;
+ g_make_token_header(ctx->mech_used, 14 + ctx->cksum_size + tmsglen, &ptr, toktype);
+
+ /* 0..1 SIGN_ALG */
+ store_16_le(ctx->signalg, &ptr[0]);
+
+ /* 2..3 SEAL_ALG or Filler */
+ if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
+ store_16_le(ctx->sealalg, &ptr[2]);
+ } else {
+ /* No seal */
+ ptr[2] = 0xFF;
+ ptr[3] = 0xFF;
+ }
+
+ /* 4..5 Filler */
+ ptr[4] = 0xFF;
+ ptr[5] = 0xFF;
+
+ /* pad the plaintext, encrypt if needed, and stick it in the token */
+
+ /* initialize the checksum */
+ switch (ctx->signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
+ break;
+ case SGN_ALG_HMAC_MD5:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
+ if (toktype != KG_TOK_WRAP_MSG)
+ sign_usage = 15;
+ break;
+ default:
+ case SGN_ALG_DES_MAC:
+ abort ();
+ }
+
+ code = krb5_c_checksum_length(context, md5cksum.checksum_type, &k5_trailerlen);
+ if (code != 0)
+ goto cleanup;
+ md5cksum.length = k5_trailerlen;
+
+ if (k5_headerlen != 0 && toktype == KG_TOK_WRAP_MSG) {
+ code = kg_make_confounder(context, ctx->enc->keyblock.enctype,
+ ptr + 14 + ctx->cksum_size);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ /* compute the checksum */
+ code = kg_make_checksum_iov_v1(context, md5cksum.checksum_type,
+ ctx->cksum_size, ctx->seq, ctx->enc,
+ sign_usage, iov, iov_count, toktype,
+ &md5cksum);
+ if (code != 0)
+ goto cleanup;
+
+ switch (ctx->signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_3:
+ code = kg_encrypt_inplace(context, ctx->seq, KG_USAGE_SEAL,
+ (g_OID_equal(ctx->mech_used,
+ gss_mech_krb5_old) ?
+ ctx->seq->keyblock.contents : NULL),
+ md5cksum.contents, 16);
+ if (code != 0)
+ goto cleanup;
+
+ cksum.length = ctx->cksum_size;
+ cksum.contents = md5cksum.contents + 16 - cksum.length;
+
+ memcpy(ptr + 14, cksum.contents, cksum.length);
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ assert(md5cksum.length == ctx->cksum_size);
+ memcpy(ptr + 14, md5cksum.contents, md5cksum.length);
+ break;
+ case SGN_ALG_HMAC_MD5:
+ memcpy(ptr + 14, md5cksum.contents, ctx->cksum_size);
+ break;
+ }
+
+ /* create the seq_num */
+ code = kg_make_seq_num(context, ctx->seq, ctx->initiate ? 0 : 0xFF,
+ (OM_uint32)ctx->seq_send, ptr + 14, ptr + 6);
+ if (code != 0)
+ goto cleanup;
+
+ if (conf_req_flag) {
+ if (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) {
+ unsigned char bigend_seqnum[4];
+ krb5_keyblock *enc_key;
+ size_t i;
+
+ store_32_be(ctx->seq_send, bigend_seqnum);
+
+ code = krb5_k_key_keyblock(context, ctx->enc, &enc_key);
+ if (code != 0)
+ goto cleanup;
+
+ assert(enc_key->length == 16);
+
+ for (i = 0; i < enc_key->length; i++)
+ ((char *)enc_key->contents)[i] ^= 0xF0;
+
+ code = kg_arcfour_docrypt_iov(context, enc_key, 0,
+ bigend_seqnum, 4,
+ iov, iov_count);
+ krb5_free_keyblock(context, enc_key);
+ } else {
+ code = kg_encrypt_iov(context, ctx->proto,
+ ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0),
+ 0 /*EC*/, 0 /*RRC*/,
+ ctx->enc, KG_USAGE_SEAL, NULL,
+ iov, iov_count);
+ }
+ if (code != 0)
+ goto cleanup;
+ }
+
+ ctx->seq_send++;
+ ctx->seq_send &= 0xFFFFFFFFL;
+
+ code = 0;
+
+ if (conf_state != NULL)
+ *conf_state = conf_req_flag;
+
+cleanup:
+ if (code != 0)
+ kg_release_iov(iov, iov_count);
+ krb5_free_checksum_contents(context, &md5cksum);
+
+ return code;
+}
+
+OM_uint32
+kg_seal_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_error_code code;
+ krb5_context context;
+
+ if (qop_req != 0) {
+ *minor_status = (OM_uint32)G_UNKNOWN_QOP;
+ return GSS_S_BAD_QOP;
+ }
+
+ ctx = (krb5_gss_ctx_id_rec *)context_handle;
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ if (conf_req_flag && kg_integ_only_iov(iov, iov_count)) {
+ /* may be more sensible to return an error here */
+ conf_req_flag = FALSE;
+ }
+
+ context = ctx->k5_context;
+ switch (ctx->proto) {
+ case 0:
+ code = make_seal_token_v1_iov(context, ctx, conf_req_flag,
+ conf_state, iov, iov_count, toktype);
+ break;
+ case 1:
+ code = gss_krb5int_make_seal_token_v3_iov(context, ctx, conf_req_flag,
+ conf_state, iov, iov_count, toktype);
+ break;
+ default:
+ code = G_UNKNOWN_QOP;
+ break;
+ }
+
+ if (code != 0) {
+ *minor_status = code;
+ save_error_info(*minor_status, context);
+ return GSS_S_FAILURE;
+ }
+
+ *minor_status = 0;
+
+ return GSS_S_COMPLETE;
+}
+
+#define INIT_IOV_DATA(_iov) do { (_iov)->buffer.value = NULL; \
+ (_iov)->buffer.length = 0; } \
+ while (0)
+
+OM_uint32
+kg_seal_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ gss_iov_buffer_t header, trailer, padding;
+ size_t data_length, assoc_data_length;
+ size_t gss_headerlen, gss_padlen, gss_trailerlen;
+ unsigned int k5_headerlen = 0, k5_trailerlen = 0, k5_padlen = 0;
+ krb5_error_code code;
+ krb5_context context;
+ int dce_or_mic;
+
+ if (qop_req != GSS_C_QOP_DEFAULT) {
+ *minor_status = (OM_uint32)G_UNKNOWN_QOP;
+ return GSS_S_BAD_QOP;
+ }
+
+ ctx = (krb5_gss_ctx_id_rec *)context_handle;
+ if (!ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ if (header == NULL) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+ INIT_IOV_DATA(header);
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ if (trailer != NULL) {
+ INIT_IOV_DATA(trailer);
+ }
+
+ /* MIC tokens and DCE-style wrap tokens have similar length considerations:
+ * no padding, and the framing surrounds the header only, not the data. */
+ dce_or_mic = ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0 ||
+ toktype == KG_TOK_MIC_MSG);
+
+ /* For CFX, EC is used instead of padding, and is placed in header or trailer */
+ padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ if (padding == NULL) {
+ if (conf_req_flag && ctx->proto == 0 && !dce_or_mic) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+ } else {
+ INIT_IOV_DATA(padding);
+ }
+
+ kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
+
+ if (conf_req_flag && kg_integ_only_iov(iov, iov_count))
+ conf_req_flag = FALSE;
+
+ context = ctx->k5_context;
+
+ gss_headerlen = gss_padlen = gss_trailerlen = 0;
+
+ if (ctx->proto == 1) {
+ krb5_key key;
+ krb5_enctype enctype;
+ size_t ec;
+
+ key = (ctx->have_acceptor_subkey) ? ctx->acceptor_subkey : ctx->subkey;
+ enctype = key->keyblock.enctype;
+
+ code = krb5_c_crypto_length(context, enctype,
+ conf_req_flag ?
+ KRB5_CRYPTO_TYPE_TRAILER : KRB5_CRYPTO_TYPE_CHECKSUM,
+ &k5_trailerlen);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (conf_req_flag) {
+ code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ gss_headerlen = 16; /* Header */
+ if (conf_req_flag) {
+ gss_headerlen += k5_headerlen; /* Kerb-Header */
+ gss_trailerlen = 16 /* E(Header) */ + k5_trailerlen; /* Kerb-Trailer */
+
+ code = krb5_c_padding_length(context, enctype,
+ data_length - assoc_data_length + 16 /* E(Header) */, &k5_padlen);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (k5_padlen == 0 && dce_or_mic) {
+ /* Windows rejects AEAD tokens with non-zero EC */
+ code = krb5_c_block_size(context, enctype, &ec);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+ } else
+ ec = k5_padlen;
+
+ gss_trailerlen += ec;
+ } else {
+ gss_trailerlen = k5_trailerlen; /* Kerb-Checksum */
+ }
+ } else if (!dce_or_mic) {
+ k5_padlen = (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) ? 1 : 8;
+
+ if (k5_padlen == 1)
+ gss_padlen = 1;
+ else
+ gss_padlen = k5_padlen - ((data_length - assoc_data_length) % k5_padlen);
+ }
+
+ data_length += gss_padlen;
+
+ if (ctx->proto == 0) {
+ /* Header | Checksum | Confounder | Data | Pad */
+ size_t data_size;
+
+ k5_headerlen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
+
+ data_size = 14 /* Header */ + ctx->cksum_size + k5_headerlen;
+
+ if (!dce_or_mic)
+ data_size += data_length;
+
+ gss_headerlen = g_token_size(ctx->mech_used, data_size);
+
+ /* g_token_size() will include data_size as well as the overhead, so
+ * subtract data_length just to get the overhead (ie. token size) */
+ if (!dce_or_mic)
+ gss_headerlen -= data_length;
+ }
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (trailer == NULL)
+ gss_headerlen += gss_trailerlen;
+ else
+ trailer->buffer.length = gss_trailerlen;
+
+ assert(gss_padlen == 0 || padding != NULL);
+
+ if (padding != NULL)
+ padding->buffer.length = gss_padlen;
+
+ header->buffer.length = gss_headerlen;
+
+ if (conf_state != NULL)
+ *conf_state = conf_req_flag;
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_wrap_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major_status;
+
+ major_status = kg_seal_iov(minor_status, context_handle, conf_req_flag,
+ qop_req, conf_state,
+ iov, iov_count, KG_TOK_WRAP_MSG);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_wrap_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major_status;
+
+ major_status = kg_seal_iov_length(minor_status, context_handle,
+ conf_req_flag, qop_req, conf_state, iov,
+ iov_count, KG_TOK_WRAP_MSG);
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_get_mic_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major_status;
+
+ major_status = kg_seal_iov(minor_status, context_handle, FALSE,
+ qop_req, NULL,
+ iov, iov_count, KG_TOK_MIC_MSG);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_get_mic_iov_length(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major_status;
+
+ major_status = kg_seal_iov_length(minor_status, context_handle, FALSE,
+ qop_req, NULL, iov, iov_count,
+ KG_TOK_MIC_MSG);
+ return major_status;
+}
diff --git a/src/lib/gssapi/krb5/k5sealv3.c b/src/lib/gssapi/krb5/k5sealv3.c
new file mode 100644
index 000000000000..1a5c14c2713b
--- /dev/null
+++ b/src/lib/gssapi/krb5/k5sealv3.c
@@ -0,0 +1,512 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/k5sealv3.c */
+/*
+ * Copyright 2003,2004,2007 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/* draft-ietf-krb-wg-gssapi-cfx-05 */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+int
+gss_krb5int_rotate_left (void *ptr, size_t bufsiz, size_t rc)
+{
+ /* Optimize for receiving. After some debugging is done, the MIT
+ implementation won't do any rotates on sending, and while
+ debugging, they'll be randomly chosen.
+
+ Return 1 for success, 0 for failure (ENOMEM). */
+ void *tbuf;
+
+ if (bufsiz == 0)
+ return 1;
+ rc = rc % bufsiz;
+ if (rc == 0)
+ return 1;
+
+ tbuf = malloc(rc);
+ if (tbuf == 0)
+ return 0;
+ memcpy(tbuf, ptr, rc);
+ memmove(ptr, (char *)ptr + rc, bufsiz - rc);
+ memcpy((char *)ptr + bufsiz - rc, tbuf, rc);
+ free(tbuf);
+ return 1;
+}
+
+static const gss_buffer_desc empty_message = { 0, 0 };
+
+krb5_error_code
+gss_krb5int_make_seal_token_v3 (krb5_context context,
+ krb5_gss_ctx_id_rec *ctx,
+ const gss_buffer_desc * message,
+ gss_buffer_t token,
+ int conf_req_flag, int toktype)
+{
+ size_t bufsize = 16;
+ unsigned char *outbuf = 0;
+ krb5_error_code err;
+ int key_usage;
+ unsigned char acceptor_flag;
+ const gss_buffer_desc *message2 = message;
+#ifdef CFX_EXERCISE
+ size_t rrc;
+#endif
+ size_t ec;
+ unsigned short tok_id;
+ krb5_checksum sum;
+ krb5_key key;
+ krb5_cksumtype cksumtype;
+
+ acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
+ key_usage = (toktype == KG_TOK_WRAP_MSG
+ ? (ctx->initiate
+ ? KG_USAGE_INITIATOR_SEAL
+ : KG_USAGE_ACCEPTOR_SEAL)
+ : (ctx->initiate
+ ? KG_USAGE_INITIATOR_SIGN
+ : KG_USAGE_ACCEPTOR_SIGN));
+ if (ctx->have_acceptor_subkey) {
+ key = ctx->acceptor_subkey;
+ cksumtype = ctx->acceptor_subkey_cksumtype;
+ } else {
+ key = ctx->subkey;
+ cksumtype = ctx->cksumtype;
+ }
+ assert(key != NULL);
+
+#ifdef CFX_EXERCISE
+ {
+ static int initialized = 0;
+ if (!initialized) {
+ srand(time(0));
+ initialized = 1;
+ }
+ }
+#endif
+
+ if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
+ krb5_data plain;
+ krb5_enc_data cipher;
+ size_t ec_max;
+
+ /* 300: Adds some slop. */
+ if (SIZE_MAX - 300 < message->length)
+ return ENOMEM;
+ ec_max = SIZE_MAX - message->length - 300;
+ if (ec_max > 0xffff)
+ ec_max = 0xffff;
+#ifdef CFX_EXERCISE
+ /* For testing only. For performance, always set ec = 0. */
+ ec = ec_max & rand();
+#else
+ ec = 0;
+#endif
+ err = alloc_data(&plain, message->length + 16 + ec);
+ if (err)
+ return err;
+
+ /* Get size of ciphertext. */
+ bufsize = 16 + krb5_encrypt_size (plain.length, key->keyblock.enctype);
+ /* Allocate space for header plus encrypted data. */
+ outbuf = gssalloc_malloc(bufsize);
+ if (outbuf == NULL) {
+ free(plain.data);
+ return ENOMEM;
+ }
+
+ /* TOK_ID */
+ store_16_be(KG2_TOK_WRAP_MSG, outbuf);
+ /* flags */
+ outbuf[2] = (acceptor_flag
+ | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0)
+ | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
+ /* filler */
+ outbuf[3] = 0xff;
+ /* EC */
+ store_16_be(ec, outbuf+4);
+ /* RRC */
+ store_16_be(0, outbuf+6);
+ store_64_be(ctx->seq_send, outbuf+8);
+
+ memcpy(plain.data, message->value, message->length);
+ if (ec != 0)
+ memset(plain.data + message->length, 'x', ec);
+ memcpy(plain.data + message->length + ec, outbuf, 16);
+
+ cipher.ciphertext.data = (char *)outbuf + 16;
+ cipher.ciphertext.length = bufsize - 16;
+ cipher.enctype = key->keyblock.enctype;
+ err = krb5_k_encrypt(context, key, key_usage, 0, &plain, &cipher);
+ zap(plain.data, plain.length);
+ free(plain.data);
+ plain.data = 0;
+ if (err)
+ goto error;
+
+ /* Now that we know we're returning a valid token.... */
+ ctx->seq_send++;
+
+#ifdef CFX_EXERCISE
+ rrc = rand() & 0xffff;
+ if (gss_krb5int_rotate_left(outbuf+16, bufsize-16,
+ (bufsize-16) - (rrc % (bufsize - 16))))
+ store_16_be(rrc, outbuf+6);
+ /* If the rotate fails, don't worry about it. */
+#endif
+ } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
+ krb5_data plain;
+ size_t cksumsize;
+
+ /* Here, message is the application-supplied data; message2 is
+ what goes into the output token. They may be the same, or
+ message2 may be empty (for MIC). */
+
+ tok_id = KG2_TOK_WRAP_MSG;
+
+ wrap_with_checksum:
+ err = alloc_data(&plain, message->length + 16);
+ if (err)
+ return err;
+
+ err = krb5_c_checksum_length(context, cksumtype, &cksumsize);
+ if (err)
+ goto error;
+
+ assert(cksumsize <= 0xffff);
+
+ bufsize = 16 + message2->length + cksumsize;
+ outbuf = gssalloc_malloc(bufsize);
+ if (outbuf == NULL) {
+ free(plain.data);
+ plain.data = 0;
+ err = ENOMEM;
+ goto error;
+ }
+
+ /* TOK_ID */
+ store_16_be(tok_id, outbuf);
+ /* flags */
+ outbuf[2] = (acceptor_flag
+ | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
+ /* filler */
+ outbuf[3] = 0xff;
+ if (toktype == KG_TOK_WRAP_MSG) {
+ /* Use 0 for checksum calculation, substitute
+ checksum length later. */
+ /* EC */
+ store_16_be(0, outbuf+4);
+ /* RRC */
+ store_16_be(0, outbuf+6);
+ } else {
+ /* MIC and DEL store 0xFF in EC and RRC. */
+ store_16_be(0xffff, outbuf+4);
+ store_16_be(0xffff, outbuf+6);
+ }
+ store_64_be(ctx->seq_send, outbuf+8);
+
+ memcpy(plain.data, message->value, message->length);
+ memcpy(plain.data + message->length, outbuf, 16);
+
+ /* Fill in the output token -- data contents, if any, and
+ space for the checksum. */
+ if (message2->length)
+ memcpy(outbuf + 16, message2->value, message2->length);
+
+ sum.contents = outbuf + 16 + message2->length;
+ sum.length = cksumsize;
+
+ err = krb5_k_make_checksum(context, cksumtype, key,
+ key_usage, &plain, &sum);
+ zap(plain.data, plain.length);
+ free(plain.data);
+ plain.data = 0;
+ if (err) {
+ zap(outbuf,bufsize);
+ goto error;
+ }
+ if (sum.length != cksumsize)
+ abort();
+ memcpy(outbuf + 16 + message2->length, sum.contents, cksumsize);
+ krb5_free_checksum_contents(context, &sum);
+ sum.contents = 0;
+ /* Now that we know we're actually generating the token... */
+ ctx->seq_send++;
+
+ if (toktype == KG_TOK_WRAP_MSG) {
+#ifdef CFX_EXERCISE
+ rrc = rand() & 0xffff;
+ /* If the rotate fails, don't worry about it. */
+ if (gss_krb5int_rotate_left(outbuf+16, bufsize-16,
+ (bufsize-16) - (rrc % (bufsize - 16))))
+ store_16_be(rrc, outbuf+6);
+#endif
+ /* Fix up EC field. */
+ store_16_be(cksumsize, outbuf+4);
+ } else {
+ store_16_be(0xffff, outbuf+6);
+ }
+ } else if (toktype == KG_TOK_MIC_MSG) {
+ tok_id = KG2_TOK_MIC_MSG;
+ message2 = &empty_message;
+ goto wrap_with_checksum;
+ } else if (toktype == KG_TOK_DEL_CTX) {
+ tok_id = KG2_TOK_DEL_CTX;
+ message = message2 = &empty_message;
+ goto wrap_with_checksum;
+ } else
+ abort();
+
+ token->value = outbuf;
+ token->length = bufsize;
+ return 0;
+
+error:
+ gssalloc_free(outbuf);
+ token->value = NULL;
+ token->length = 0;
+ return err;
+}
+
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+ conf_state is only valid if SEAL. */
+
+OM_uint32
+gss_krb5int_unseal_token_v3(krb5_context *contextptr,
+ OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ unsigned char *ptr, unsigned int bodysize,
+ gss_buffer_t message_buffer,
+ int *conf_state, gss_qop_t *qop_state, int toktype)
+{
+ krb5_context context = *contextptr;
+ krb5_data plain;
+ uint64_t seqnum;
+ size_t ec, rrc;
+ int key_usage;
+ unsigned char acceptor_flag;
+ krb5_checksum sum;
+ krb5_error_code err;
+ krb5_boolean valid;
+ krb5_key key;
+ krb5_cksumtype cksumtype;
+
+ if (qop_state)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ acceptor_flag = ctx->initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
+ key_usage = (toktype == KG_TOK_WRAP_MSG
+ ? (!ctx->initiate
+ ? KG_USAGE_INITIATOR_SEAL
+ : KG_USAGE_ACCEPTOR_SEAL)
+ : (!ctx->initiate
+ ? KG_USAGE_INITIATOR_SIGN
+ : KG_USAGE_ACCEPTOR_SIGN));
+
+ /* Oops. I wrote this code assuming ptr would be at the start of
+ the token header. */
+ ptr -= 2;
+ bodysize += 2;
+
+ if (bodysize < 16) {
+ defective:
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ if ((ptr[2] & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
+ *minor_status = (OM_uint32)G_BAD_DIRECTION;
+ return GSS_S_BAD_SIG;
+ }
+
+ /* Two things to note here.
+
+ First, we can't really enforce the use of the acceptor's subkey,
+ if we're the acceptor; the initiator may have sent messages
+ before getting the subkey. We could probably enforce it if
+ we're the initiator.
+
+ Second, if someone tweaks the code to not set the flag telling
+ the krb5 library to generate a new subkey in the AP-REP
+ message, the MIT library may include a subkey anyways --
+ namely, a copy of the AP-REQ subkey, if it was provided. So
+ the initiator may think we wanted a subkey, and set the flag,
+ even though we weren't trying to set the subkey. The "other"
+ key, the one not asserted by the acceptor, will have the same
+ value in that case, though, so we can just ignore the flag. */
+ if (ctx->have_acceptor_subkey && (ptr[2] & FLAG_ACCEPTOR_SUBKEY)) {
+ key = ctx->acceptor_subkey;
+ cksumtype = ctx->acceptor_subkey_cksumtype;
+ } else {
+ key = ctx->subkey;
+ cksumtype = ctx->cksumtype;
+ }
+ assert(key != NULL);
+
+ if (toktype == KG_TOK_WRAP_MSG) {
+ if (load_16_be(ptr) != KG2_TOK_WRAP_MSG)
+ goto defective;
+ if (ptr[3] != 0xff)
+ goto defective;
+ ec = load_16_be(ptr+4);
+ rrc = load_16_be(ptr+6);
+ seqnum = load_64_be(ptr+8);
+ if (!gss_krb5int_rotate_left(ptr+16, bodysize-16, rrc)) {
+ no_mem:
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ if (ptr[2] & FLAG_WRAP_CONFIDENTIAL) {
+ /* confidentiality */
+ krb5_enc_data cipher;
+ unsigned char *althdr;
+
+ if (conf_state)
+ *conf_state = 1;
+ /* Do we have no decrypt_size function?
+
+ For all current cryptosystems, the ciphertext size will
+ be larger than the plaintext size. */
+ cipher.enctype = key->keyblock.enctype;
+ cipher.ciphertext.length = bodysize - 16;
+ cipher.ciphertext.data = (char *)ptr + 16;
+ plain.length = bodysize - 16;
+ plain.data = gssalloc_malloc(plain.length);
+ if (plain.data == NULL)
+ goto no_mem;
+ err = krb5_k_decrypt(context, key, key_usage, 0,
+ &cipher, &plain);
+ if (err) {
+ gssalloc_free(plain.data);
+ goto error;
+ }
+ /* Don't use bodysize here! Use the fact that
+ cipher.ciphertext.length has been adjusted to the
+ correct length. */
+ althdr = (unsigned char *)plain.data + plain.length - 16;
+ if (load_16_be(althdr) != KG2_TOK_WRAP_MSG
+ || althdr[2] != ptr[2]
+ || althdr[3] != ptr[3]
+ || memcmp(althdr+8, ptr+8, 8)) {
+ free(plain.data);
+ goto defective;
+ }
+ message_buffer->value = plain.data;
+ message_buffer->length = plain.length - ec - 16;
+ if(message_buffer->length == 0) {
+ gssalloc_free(message_buffer->value);
+ message_buffer->value = NULL;
+ }
+ } else {
+ size_t cksumsize;
+
+ err = krb5_c_checksum_length(context, cksumtype, &cksumsize);
+ if (err)
+ goto error;
+
+ /* no confidentiality */
+ if (conf_state)
+ *conf_state = 0;
+ if (ec + 16 < ec)
+ /* overflow check */
+ goto defective;
+ if (ec + 16 > bodysize)
+ goto defective;
+ /* We have: header | msg | cksum.
+ We need cksum(msg | header).
+ Rotate the first two. */
+ store_16_be(0, ptr+4);
+ store_16_be(0, ptr+6);
+ plain = make_data(ptr, bodysize - ec);
+ if (!gss_krb5int_rotate_left(ptr, bodysize-ec, 16))
+ goto no_mem;
+ sum.length = ec;
+ if (sum.length != cksumsize) {
+ *minor_status = 0;
+ return GSS_S_BAD_SIG;
+ }
+ sum.contents = ptr+bodysize-ec;
+ sum.checksum_type = cksumtype;
+ err = krb5_k_verify_checksum(context, key, key_usage,
+ &plain, &sum, &valid);
+ if (err)
+ goto error;
+ if (!valid) {
+ *minor_status = 0;
+ return GSS_S_BAD_SIG;
+ }
+ message_buffer->length = plain.length - 16;
+ message_buffer->value = gssalloc_malloc(message_buffer->length);
+ if (message_buffer->value == NULL)
+ goto no_mem;
+ memcpy(message_buffer->value, plain.data, message_buffer->length);
+ }
+ err = g_seqstate_check(ctx->seqstate, seqnum);
+ *minor_status = 0;
+ return err;
+ } else if (toktype == KG_TOK_MIC_MSG) {
+ /* wrap token, no confidentiality */
+ if (load_16_be(ptr) != KG2_TOK_MIC_MSG)
+ goto defective;
+ verify_mic_1:
+ if (ptr[3] != 0xff)
+ goto defective;
+ if (load_32_be(ptr+4) != 0xffffffffL)
+ goto defective;
+ seqnum = load_64_be(ptr+8);
+ plain.length = message_buffer->length + 16;
+ plain.data = malloc(plain.length);
+ if (plain.data == NULL)
+ goto no_mem;
+ if (message_buffer->length)
+ memcpy(plain.data, message_buffer->value, message_buffer->length);
+ memcpy(plain.data + message_buffer->length, ptr, 16);
+ sum.length = bodysize - 16;
+ sum.contents = ptr + 16;
+ sum.checksum_type = cksumtype;
+ err = krb5_k_verify_checksum(context, key, key_usage,
+ &plain, &sum, &valid);
+ free(plain.data);
+ plain.data = NULL;
+ if (err) {
+ error:
+ *minor_status = err;
+ save_error_info(*minor_status, context);
+ return GSS_S_BAD_SIG; /* XXX */
+ }
+ if (!valid) {
+ *minor_status = 0;
+ return GSS_S_BAD_SIG;
+ }
+ err = g_seqstate_check(ctx->seqstate, seqnum);
+ *minor_status = 0;
+ return err;
+ } else if (toktype == KG_TOK_DEL_CTX) {
+ if (load_16_be(ptr) != KG2_TOK_DEL_CTX)
+ goto defective;
+ message_buffer = (gss_buffer_t)&empty_message;
+ goto verify_mic_1;
+ } else {
+ goto defective;
+ }
+}
diff --git a/src/lib/gssapi/krb5/k5sealv3iov.c b/src/lib/gssapi/krb5/k5sealv3iov.c
new file mode 100644
index 000000000000..a73edb6a4ffd
--- /dev/null
+++ b/src/lib/gssapi/krb5/k5sealv3iov.c
@@ -0,0 +1,468 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/k5sealv3iov.c */
+/*
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+krb5_error_code
+gss_krb5int_make_seal_token_v3_iov(krb5_context context,
+ krb5_gss_ctx_id_rec *ctx,
+ int conf_req_flag,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ krb5_error_code code = 0;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t padding;
+ gss_iov_buffer_t trailer;
+ unsigned char acceptor_flag;
+ unsigned short tok_id;
+ unsigned char *outbuf = NULL;
+ unsigned char *tbuf = NULL;
+ int key_usage;
+ size_t rrc = 0;
+ unsigned int gss_headerlen, gss_trailerlen;
+ krb5_key key;
+ krb5_cksumtype cksumtype;
+ size_t data_length, assoc_data_length;
+
+ assert(ctx->proto == 1);
+
+ acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
+ key_usage = (toktype == KG_TOK_WRAP_MSG
+ ? (ctx->initiate
+ ? KG_USAGE_INITIATOR_SEAL
+ : KG_USAGE_ACCEPTOR_SEAL)
+ : (ctx->initiate
+ ? KG_USAGE_INITIATOR_SIGN
+ : KG_USAGE_ACCEPTOR_SIGN));
+ if (ctx->have_acceptor_subkey) {
+ key = ctx->acceptor_subkey;
+ cksumtype = ctx->acceptor_subkey_cksumtype;
+ } else {
+ key = ctx->subkey;
+ cksumtype = ctx->cksumtype;
+ }
+ assert(key != NULL);
+ assert(cksumtype != 0);
+
+ kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ if (header == NULL)
+ return EINVAL;
+
+ padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ if (padding != NULL)
+ padding->buffer.length = 0;
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+ if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
+ unsigned int k5_headerlen, k5_trailerlen, k5_padlen;
+ size_t ec = 0;
+ size_t conf_data_length = data_length - assoc_data_length;
+
+ code = krb5_c_crypto_length(context, key->keyblock.enctype,
+ KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_c_padding_length(context, key->keyblock.enctype,
+ conf_data_length + 16 /* E(Header) */, &k5_padlen);
+ if (code != 0)
+ goto cleanup;
+
+ if (k5_padlen == 0 && (ctx->gss_flags & GSS_C_DCE_STYLE)) {
+ /* Windows rejects AEAD tokens with non-zero EC */
+ code = krb5_c_block_size(context, key->keyblock.enctype, &ec);
+ if (code != 0)
+ goto cleanup;
+ } else
+ ec = k5_padlen;
+
+ code = krb5_c_crypto_length(context, key->keyblock.enctype,
+ KRB5_CRYPTO_TYPE_TRAILER, &k5_trailerlen);
+ if (code != 0)
+ goto cleanup;
+
+ gss_headerlen = 16 /* Header */ + k5_headerlen;
+ gss_trailerlen = ec + 16 /* E(Header) */ + k5_trailerlen;
+
+ if (trailer == NULL) {
+ rrc = gss_trailerlen;
+ /* Workaround for Windows bug where it rotates by EC + RRC */
+ if (ctx->gss_flags & GSS_C_DCE_STYLE)
+ rrc -= ec;
+ gss_headerlen += gss_trailerlen;
+ }
+
+ if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
+ code = kg_allocate_iov(header, (size_t) gss_headerlen);
+ } else if (header->buffer.length < gss_headerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+ outbuf = (unsigned char *)header->buffer.value;
+ header->buffer.length = (size_t) gss_headerlen;
+
+ if (trailer != NULL) {
+ if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = kg_allocate_iov(trailer, (size_t) gss_trailerlen);
+ else if (trailer->buffer.length < gss_trailerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+ trailer->buffer.length = (size_t) gss_trailerlen;
+ }
+
+ /* TOK_ID */
+ store_16_be(KG2_TOK_WRAP_MSG, outbuf);
+ /* flags */
+ outbuf[2] = (acceptor_flag
+ | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0)
+ | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
+ /* filler */
+ outbuf[3] = 0xFF;
+ /* EC */
+ store_16_be(ec, outbuf + 4);
+ /* RRC */
+ store_16_be(0, outbuf + 6);
+ store_64_be(ctx->seq_send, outbuf + 8);
+
+ /* EC | copy of header to be encrypted, located in (possibly rotated) trailer */
+ if (trailer == NULL)
+ tbuf = (unsigned char *)header->buffer.value + 16; /* Header */
+ else
+ tbuf = (unsigned char *)trailer->buffer.value;
+
+ memset(tbuf, 0xFF, ec);
+ memcpy(tbuf + ec, header->buffer.value, 16);
+
+ code = kg_encrypt_iov(context, ctx->proto,
+ ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0),
+ ec, rrc, key, key_usage, 0, iov, iov_count);
+ if (code != 0)
+ goto cleanup;
+
+ /* RRC */
+ store_16_be(rrc, outbuf + 6);
+
+ ctx->seq_send++;
+ } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
+ tok_id = KG2_TOK_WRAP_MSG;
+
+ wrap_with_checksum:
+
+ gss_headerlen = 16;
+
+ code = krb5_c_crypto_length(context, key->keyblock.enctype,
+ KRB5_CRYPTO_TYPE_CHECKSUM,
+ &gss_trailerlen);
+ if (code != 0)
+ goto cleanup;
+
+ assert(gss_trailerlen <= 0xFFFF);
+
+ if (trailer == NULL) {
+ rrc = gss_trailerlen;
+ gss_headerlen += gss_trailerlen;
+ }
+
+ if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = kg_allocate_iov(header, (size_t) gss_headerlen);
+ else if (header->buffer.length < gss_headerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+ outbuf = (unsigned char *)header->buffer.value;
+ header->buffer.length = (size_t) gss_headerlen;
+
+ if (trailer != NULL) {
+ if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = kg_allocate_iov(trailer, (size_t) gss_trailerlen);
+ else if (trailer->buffer.length < gss_trailerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+ trailer->buffer.length = (size_t) gss_trailerlen;
+ }
+
+ /* TOK_ID */
+ store_16_be(tok_id, outbuf);
+ /* flags */
+ outbuf[2] = (acceptor_flag
+ | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
+ /* filler */
+ outbuf[3] = 0xFF;
+ if (toktype == KG_TOK_WRAP_MSG) {
+ /* Use 0 for checksum calculation, substitute
+ * checksum length later.
+ */
+ /* EC */
+ store_16_be(0, outbuf + 4);
+ /* RRC */
+ store_16_be(0, outbuf + 6);
+ } else {
+ /* MIC and DEL store 0xFF in EC and RRC */
+ store_16_be(0xFFFF, outbuf + 4);
+ store_16_be(0xFFFF, outbuf + 6);
+ }
+ store_64_be(ctx->seq_send, outbuf + 8);
+
+ code = kg_make_checksum_iov_v3(context, cksumtype,
+ rrc, key, key_usage,
+ iov, iov_count, toktype);
+ if (code != 0)
+ goto cleanup;
+
+ ctx->seq_send++;
+
+ if (toktype == KG_TOK_WRAP_MSG) {
+ /* Fix up EC field */
+ store_16_be(gss_trailerlen, outbuf + 4);
+ /* Fix up RRC field */
+ store_16_be(rrc, outbuf + 6);
+ }
+ } else if (toktype == KG_TOK_MIC_MSG) {
+ tok_id = KG2_TOK_MIC_MSG;
+ trailer = NULL;
+ goto wrap_with_checksum;
+ } else if (toktype == KG_TOK_DEL_CTX) {
+ tok_id = KG2_TOK_DEL_CTX;
+ goto wrap_with_checksum;
+ } else {
+ abort();
+ }
+
+ code = 0;
+ if (conf_state != NULL)
+ *conf_state = conf_req_flag;
+
+cleanup:
+ if (code != 0)
+ kg_release_iov(iov, iov_count);
+
+ return code;
+}
+
+OM_uint32
+gss_krb5int_unseal_v3_iov(krb5_context context,
+ OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ int toktype)
+{
+ OM_uint32 code;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t padding;
+ gss_iov_buffer_t trailer;
+ unsigned char acceptor_flag;
+ unsigned char *ptr = NULL;
+ int key_usage;
+ size_t rrc, ec;
+ size_t data_length, assoc_data_length;
+ krb5_key key;
+ uint64_t seqnum;
+ krb5_boolean valid;
+ krb5_cksumtype cksumtype;
+ int conf_flag = 0;
+
+ if (qop_state != NULL)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ assert(header != NULL);
+
+ padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ if (padding != NULL && padding->buffer.length != 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+ acceptor_flag = ctx->initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
+ key_usage = (toktype == KG_TOK_WRAP_MSG
+ ? (!ctx->initiate
+ ? KG_USAGE_INITIATOR_SEAL
+ : KG_USAGE_ACCEPTOR_SEAL)
+ : (!ctx->initiate
+ ? KG_USAGE_INITIATOR_SIGN
+ : KG_USAGE_ACCEPTOR_SIGN));
+
+ kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
+
+ ptr = (unsigned char *)header->buffer.value;
+
+ if (header->buffer.length < 16) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if ((ptr[2] & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
+ *minor_status = (OM_uint32)G_BAD_DIRECTION;
+ return GSS_S_BAD_SIG;
+ }
+
+ if (ctx->have_acceptor_subkey && (ptr[2] & FLAG_ACCEPTOR_SUBKEY)) {
+ key = ctx->acceptor_subkey;
+ cksumtype = ctx->acceptor_subkey_cksumtype;
+ } else {
+ key = ctx->subkey;
+ cksumtype = ctx->cksumtype;
+ }
+ assert(key != NULL);
+
+
+ if (toktype == KG_TOK_WRAP_MSG) {
+ unsigned int k5_trailerlen;
+
+ if (load_16_be(ptr) != KG2_TOK_WRAP_MSG)
+ goto defective;
+ conf_flag = ((ptr[2] & FLAG_WRAP_CONFIDENTIAL) != 0);
+ if (ptr[3] != 0xFF)
+ goto defective;
+ ec = load_16_be(ptr + 4);
+ rrc = load_16_be(ptr + 6);
+ seqnum = load_64_be(ptr + 8);
+
+ code = krb5_c_crypto_length(context, key->keyblock.enctype,
+ conf_flag ? KRB5_CRYPTO_TYPE_TRAILER :
+ KRB5_CRYPTO_TYPE_CHECKSUM,
+ &k5_trailerlen);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ /* Deal with RRC */
+ if (trailer == NULL) {
+ size_t desired_rrc = k5_trailerlen;
+
+ if (conf_flag) {
+ desired_rrc += 16; /* E(Header) */
+
+ if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0)
+ desired_rrc += ec;
+ }
+
+ /* According to MS, we only need to deal with a fixed RRC for DCE */
+ if (rrc != desired_rrc)
+ goto defective;
+ } else if (rrc != 0) {
+ /* Should have been rotated by kg_unseal_stream_iov() */
+ goto defective;
+ }
+
+ if (conf_flag) {
+ unsigned char *althdr;
+
+ /* Decrypt */
+ code = kg_decrypt_iov(context, ctx->proto,
+ ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0),
+ ec, rrc,
+ key, key_usage, 0, iov, iov_count);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_BAD_SIG;
+ }
+
+ /* Validate header integrity */
+ if (trailer == NULL)
+ althdr = (unsigned char *)header->buffer.value + 16 + ec;
+ else
+ althdr = (unsigned char *)trailer->buffer.value + ec;
+
+ if (load_16_be(althdr) != KG2_TOK_WRAP_MSG
+ || althdr[2] != ptr[2]
+ || althdr[3] != ptr[3]
+ || memcmp(althdr + 8, ptr + 8, 8) != 0) {
+ *minor_status = 0;
+ return GSS_S_BAD_SIG;
+ }
+ } else {
+ /* Verify checksum: note EC is checksum size here, not padding */
+ if (ec != k5_trailerlen)
+ goto defective;
+
+ /* Zero EC, RRC before computing checksum */
+ store_16_be(0, ptr + 4);
+ store_16_be(0, ptr + 6);
+
+ code = kg_verify_checksum_iov_v3(context, cksumtype, rrc,
+ key, key_usage,
+ iov, iov_count, toktype, &valid);
+ if (code != 0 || valid == FALSE) {
+ *minor_status = code;
+ return GSS_S_BAD_SIG;
+ }
+ }
+
+ code = g_seqstate_check(ctx->seqstate, seqnum);
+ } else if (toktype == KG_TOK_MIC_MSG) {
+ if (load_16_be(ptr) != KG2_TOK_MIC_MSG)
+ goto defective;
+
+ verify_mic_1:
+ if (ptr[3] != 0xFF)
+ goto defective;
+ seqnum = load_64_be(ptr + 8);
+
+ /* For MIC tokens, the GSS header and checksum are in the same buffer.
+ * Fake up an RRC so that the checksum is expected in the header. */
+ rrc = (trailer != NULL) ? 0 : header->buffer.length - 16;
+ code = kg_verify_checksum_iov_v3(context, cksumtype, rrc,
+ key, key_usage,
+ iov, iov_count, toktype, &valid);
+ if (code != 0 || valid == FALSE) {
+ *minor_status = code;
+ return GSS_S_BAD_SIG;
+ }
+ code = g_seqstate_check(ctx->seqstate, seqnum);
+ } else if (toktype == KG_TOK_DEL_CTX) {
+ if (load_16_be(ptr) != KG2_TOK_DEL_CTX)
+ goto defective;
+ goto verify_mic_1;
+ } else {
+ goto defective;
+ }
+
+ *minor_status = 0;
+
+ if (conf_state != NULL)
+ *conf_state = conf_flag;
+
+ return code;
+
+defective:
+ *minor_status = 0;
+
+ return GSS_S_DEFECTIVE_TOKEN;
+}
diff --git a/src/lib/gssapi/krb5/k5unseal.c b/src/lib/gssapi/krb5/k5unseal.c
new file mode 100644
index 000000000000..26a2d33e7a2c
--- /dev/null
+++ b/src/lib/gssapi/krb5/k5unseal.c
@@ -0,0 +1,588 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2001, 2007 by the Massachusetts Institute of Technology.
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <assert.h>
+
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+ conf_state is only valid if SEAL. */
+
+static OM_uint32
+kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer,
+ conf_state, qop_state, toktype)
+ krb5_context context;
+ OM_uint32 *minor_status;
+ krb5_gss_ctx_id_rec *ctx;
+ unsigned char *ptr;
+ int bodysize;
+ gss_buffer_t message_buffer;
+ int *conf_state;
+ gss_qop_t *qop_state;
+ int toktype;
+{
+ krb5_error_code code;
+ int conflen = 0;
+ int signalg;
+ int sealalg;
+ int bad_pad = 0;
+ gss_buffer_desc token;
+ krb5_checksum cksum;
+ krb5_checksum md5cksum;
+ krb5_data plaind;
+ char *data_ptr;
+ unsigned char *plain;
+ unsigned int cksum_len = 0;
+ size_t plainlen;
+ int direction;
+ krb5_ui_4 seqnum;
+ OM_uint32 retval;
+ size_t sumlen;
+ size_t padlen;
+ krb5_keyusage sign_usage = KG_USAGE_SIGN;
+
+ if (toktype == KG_TOK_SEAL_MSG) {
+ message_buffer->length = 0;
+ message_buffer->value = NULL;
+ }
+
+ /* Sanity checks */
+
+ if (ctx->seq == NULL) {
+ /* ctx was established using a newer enctype, and cannot process RFC
+ * 1964 tokens. */
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if ((bodysize < 22) || (ptr[4] != 0xff) || (ptr[5] != 0xff)) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ signalg = ptr[0] + (ptr[1]<<8);
+ sealalg = ptr[2] + (ptr[3]<<8);
+
+ if ((toktype != KG_TOK_SEAL_MSG) &&
+ (sealalg != 0xffff)) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ /* in the current spec, there is only one valid seal algorithm per
+ key type, so a simple comparison is ok */
+
+ if ((toktype == KG_TOK_SEAL_MSG) &&
+ !((sealalg == 0xffff) ||
+ (sealalg == ctx->sealalg))) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ /* there are several mappings of seal algorithms to sign algorithms,
+ but few enough that we can try them all. */
+
+ if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
+ (ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
+ (ctx->sealalg == SEAL_ALG_DES3KD &&
+ signalg != SGN_ALG_HMAC_SHA1_DES3_KD)||
+ (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4 &&
+ signalg != SGN_ALG_HMAC_MD5)) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ case SGN_ALG_HMAC_MD5:
+ cksum_len = 8;
+ if (toktype != KG_TOK_SEAL_MSG)
+ sign_usage = 15;
+ break;
+ case SGN_ALG_3:
+ cksum_len = 16;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ cksum_len = 20;
+ break;
+ default:
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if ((size_t)bodysize < 14 + cksum_len) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ /* get the token parameters */
+
+ if ((code = kg_get_seq_num(context, ctx->seq, ptr+14, ptr+6, &direction,
+ &seqnum))) {
+ *minor_status = code;
+ return(GSS_S_BAD_SIG);
+ }
+
+ /* decode the message, if SEAL */
+
+ if (toktype == KG_TOK_SEAL_MSG) {
+ size_t tmsglen = bodysize-(14+cksum_len);
+ if (sealalg != 0xffff) {
+ if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ if (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) {
+ unsigned char bigend_seqnum[4];
+ krb5_keyblock *enc_key;
+ int i;
+ store_32_be(seqnum, bigend_seqnum);
+ code = krb5_k_key_keyblock(context, ctx->enc, &enc_key);
+ if (code)
+ {
+ xfree(plain);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ assert (enc_key->length == 16);
+ for (i = 0; i <= 15; i++)
+ ((char *) enc_key->contents)[i] ^=0xf0;
+ code = kg_arcfour_docrypt (enc_key, 0,
+ &bigend_seqnum[0], 4,
+ ptr+14+cksum_len, tmsglen,
+ plain);
+ krb5_free_keyblock (context, enc_key);
+ } else {
+ code = kg_decrypt(context, ctx->enc, KG_USAGE_SEAL, NULL,
+ ptr+14+cksum_len, plain, tmsglen);
+ }
+ if (code) {
+ xfree(plain);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+ } else {
+ plain = ptr+14+cksum_len;
+ }
+
+ plainlen = tmsglen;
+
+ conflen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
+ if (tmsglen < conflen) {
+ if (sealalg != 0xffff)
+ xfree(plain);
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+ padlen = plain[tmsglen - 1];
+ if (tmsglen - conflen < padlen) {
+ /* Don't error out yet, to avoid padding oracle attacks. We will
+ * treat this as a checksum failure later on. */
+ padlen = 0;
+ bad_pad = 1;
+ }
+ token.length = tmsglen - conflen - padlen;
+
+ if (token.length) {
+ if ((token.value = (void *) gssalloc_malloc(token.length)) == NULL) {
+ if (sealalg != 0xffff)
+ xfree(plain);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ memcpy(token.value, plain+conflen, token.length);
+ } else {
+ token.value = NULL;
+ }
+ } else if (toktype == KG_TOK_SIGN_MSG) {
+ token = *message_buffer;
+ plain = token.value;
+ plainlen = token.length;
+ } else {
+ token.length = 0;
+ token.value = NULL;
+ plain = token.value;
+ plainlen = token.length;
+ }
+
+ /* compute the checksum of the message */
+
+ /* initialize the the cksum */
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ case SGN_ALG_DES_MAC:
+ case SGN_ALG_3:
+ md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+ break;
+ case SGN_ALG_HMAC_MD5:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
+ break;
+ default:
+ abort ();
+ }
+
+ code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
+ if (code)
+ return(code);
+ md5cksum.length = sumlen;
+
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_3:
+ /* compute the checksum of the message */
+
+ /* 8 = bytes of token body to be checksummed according to spec */
+
+ if (! (data_ptr = xmalloc(8 + plainlen))) {
+ if (sealalg != 0xffff)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ (void) memcpy(data_ptr, ptr-2, 8);
+
+ (void) memcpy(data_ptr+8, plain, plainlen);
+
+ plaind.length = 8 + plainlen;
+ plaind.data = data_ptr;
+ code = krb5_k_make_checksum(context, md5cksum.checksum_type,
+ ctx->seq, sign_usage,
+ &plaind, &md5cksum);
+ xfree(data_ptr);
+
+ if (code) {
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ code = kg_encrypt_inplace(context, ctx->seq, KG_USAGE_SEAL,
+ (g_OID_equal(ctx->mech_used,
+ gss_mech_krb5_old) ?
+ ctx->seq->keyblock.contents : NULL),
+ md5cksum.contents, 16);
+ if (code) {
+ krb5_free_checksum_contents(context, &md5cksum);
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (signalg == 0)
+ cksum.length = 8;
+ else
+ cksum.length = 16;
+ cksum.contents = md5cksum.contents + 16 - cksum.length;
+
+ code = k5_bcmp(cksum.contents, ptr + 14, cksum.length);
+ break;
+
+ case SGN_ALG_MD2_5:
+ if (!ctx->seed_init &&
+ (code = kg_make_seed(context, ctx->subkey, ctx->seed))) {
+ krb5_free_checksum_contents(context, &md5cksum);
+ if (sealalg != 0xffff)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ if (! (data_ptr = xmalloc(sizeof(ctx->seed) + 8 + plainlen))) {
+ krb5_free_checksum_contents(context, &md5cksum);
+ if (sealalg == 0)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ (void) memcpy(data_ptr, ptr-2, 8);
+ (void) memcpy(data_ptr+8, ctx->seed, sizeof(ctx->seed));
+ (void) memcpy(data_ptr+8+sizeof(ctx->seed), plain, plainlen);
+ plaind.length = 8 + sizeof(ctx->seed) + plainlen;
+ plaind.data = data_ptr;
+ krb5_free_checksum_contents(context, &md5cksum);
+ code = krb5_k_make_checksum(context, md5cksum.checksum_type,
+ ctx->seq, sign_usage,
+ &plaind, &md5cksum);
+ xfree(data_ptr);
+
+ if (code) {
+ if (sealalg == 0)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ code = k5_bcmp(md5cksum.contents, ptr + 14, 8);
+ /* Falls through to defective-token?? */
+
+ default:
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
+
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ case SGN_ALG_HMAC_MD5:
+ /* compute the checksum of the message */
+
+ /* 8 = bytes of token body to be checksummed according to spec */
+
+ if (! (data_ptr = xmalloc(8 + plainlen))) {
+ if (sealalg != 0xffff)
+ xfree(plain);
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ (void) memcpy(data_ptr, ptr-2, 8);
+
+ (void) memcpy(data_ptr+8, plain, plainlen);
+
+ plaind.length = 8 + plainlen;
+ plaind.data = data_ptr;
+ code = krb5_k_make_checksum(context, md5cksum.checksum_type,
+ ctx->seq, sign_usage,
+ &plaind, &md5cksum);
+ xfree(data_ptr);
+
+ if (code) {
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ code = k5_bcmp(md5cksum.contents, ptr + 14, cksum_len);
+ break;
+ }
+
+ krb5_free_checksum_contents(context, &md5cksum);
+ if (sealalg != 0xffff)
+ xfree(plain);
+
+ /* compare the computed checksum against the transmitted checksum */
+
+ if (code || bad_pad) {
+ if (toktype == KG_TOK_SEAL_MSG)
+ gssalloc_free(token.value);
+ *minor_status = 0;
+ return(GSS_S_BAD_SIG);
+ }
+
+
+ /* It got through unscathed. Make sure the context is unexpired. */
+
+ if (toktype == KG_TOK_SEAL_MSG)
+ *message_buffer = token;
+
+ if (conf_state)
+ *conf_state = (sealalg != 0xffff);
+
+ if (qop_state)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ /* do sequencing checks */
+
+ if ((ctx->initiate && direction != 0xff) ||
+ (!ctx->initiate && direction != 0)) {
+ if (toktype == KG_TOK_SEAL_MSG) {
+ gssalloc_free(token.value);
+ message_buffer->value = NULL;
+ message_buffer->length = 0;
+ }
+ *minor_status = (OM_uint32)G_BAD_DIRECTION;
+ return(GSS_S_BAD_SIG);
+ }
+
+ retval = g_seqstate_check(ctx->seqstate, (uint64_t)seqnum);
+
+ /* success or ordering violation */
+
+ *minor_status = 0;
+ return(retval);
+}
+
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+ conf_state is only valid if SEAL. */
+
+OM_uint32
+kg_unseal(minor_status, context_handle, input_token_buffer,
+ message_buffer, conf_state, qop_state, toktype)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ gss_buffer_t input_token_buffer;
+ gss_buffer_t message_buffer;
+ int *conf_state;
+ gss_qop_t *qop_state;
+ int toktype;
+{
+ krb5_gss_ctx_id_rec *ctx;
+ unsigned char *ptr;
+ unsigned int bodysize;
+ int err;
+ int toktype2;
+ int vfyflags = 0;
+ OM_uint32 ret;
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return(GSS_S_NO_CONTEXT);
+ }
+
+ /* parse the token, leave the data in message_buffer, setting conf_state */
+
+ /* verify the header */
+
+ ptr = (unsigned char *) input_token_buffer->value;
+
+
+ err = g_verify_token_header(ctx->mech_used,
+ &bodysize, &ptr, -1,
+ input_token_buffer->length,
+ vfyflags);
+ if (err) {
+ *minor_status = err;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (bodysize < 2) {
+ *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ toktype2 = load_16_be(ptr);
+
+ ptr += 2;
+ bodysize -= 2;
+
+ switch (toktype2) {
+ case KG2_TOK_MIC_MSG:
+ case KG2_TOK_WRAP_MSG:
+ case KG2_TOK_DEL_CTX:
+ ret = gss_krb5int_unseal_token_v3(&ctx->k5_context, minor_status, ctx,
+ ptr, bodysize, message_buffer,
+ conf_state, qop_state, toktype);
+ break;
+ case KG_TOK_MIC_MSG:
+ case KG_TOK_WRAP_MSG:
+ case KG_TOK_DEL_CTX:
+ ret = kg_unseal_v1(ctx->k5_context, minor_status, ctx, ptr, bodysize,
+ message_buffer, conf_state, qop_state,
+ toktype);
+ break;
+ default:
+ *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ break;
+ }
+
+ if (ret != 0)
+ save_error_info (*minor_status, ctx->k5_context);
+
+ return ret;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_unwrap(minor_status, context_handle,
+ input_message_buffer, output_message_buffer,
+ conf_state, qop_state)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ gss_buffer_t input_message_buffer;
+ gss_buffer_t output_message_buffer;
+ int *conf_state;
+ gss_qop_t *qop_state;
+{
+ OM_uint32 rstat;
+
+ rstat = kg_unseal(minor_status, context_handle,
+ input_message_buffer, output_message_buffer,
+ conf_state, qop_state, KG_TOK_WRAP_MSG);
+ return(rstat);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_verify_mic(minor_status, context_handle,
+ message_buffer, token_buffer,
+ qop_state)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ gss_buffer_t message_buffer;
+ gss_buffer_t token_buffer;
+ gss_qop_t *qop_state;
+{
+ OM_uint32 rstat;
+
+ rstat = kg_unseal(minor_status, context_handle,
+ token_buffer, message_buffer,
+ NULL, qop_state, KG_TOK_MIC_MSG);
+ return(rstat);
+}
diff --git a/src/lib/gssapi/krb5/k5unsealiov.c b/src/lib/gssapi/krb5/k5unsealiov.c
new file mode 100644
index 000000000000..8b6704274db8
--- /dev/null
+++ b/src/lib/gssapi/krb5/k5unsealiov.c
@@ -0,0 +1,675 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/k5unsealiov.c */
+/*
+ * Copyright 2008, 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+static OM_uint32
+kg_unseal_v1_iov(krb5_context context,
+ OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ size_t token_wrapper_len,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ int toktype)
+{
+ OM_uint32 code;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t trailer;
+ unsigned char *ptr;
+ int sealalg;
+ int signalg;
+ krb5_checksum cksum;
+ krb5_checksum md5cksum;
+ size_t cksum_len = 0;
+ size_t conflen = 0;
+ int direction;
+ krb5_ui_4 seqnum;
+ OM_uint32 retval;
+ size_t sumlen;
+ krb5_keyusage sign_usage = KG_USAGE_SIGN;
+
+ md5cksum.length = cksum.length = 0;
+ md5cksum.contents = cksum.contents = NULL;
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ assert(header != NULL);
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ if (trailer != NULL && trailer->buffer.length != 0) {
+ *minor_status = (OM_uint32)KRB5_BAD_MSIZE;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (ctx->seq == NULL) {
+ /* ctx was established using a newer enctype, and cannot process RFC
+ * 1964 tokens. */
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (header->buffer.length < token_wrapper_len + 22) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ ptr = (unsigned char *)header->buffer.value + token_wrapper_len;
+
+ signalg = ptr[0];
+ signalg |= ptr[1] << 8;
+
+ sealalg = ptr[2];
+ sealalg |= ptr[3] << 8;
+
+ if (ptr[4] != 0xFF || ptr[5] != 0xFF) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (toktype != KG_TOK_WRAP_MSG && sealalg != 0xFFFF) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (toktype == KG_TOK_WRAP_MSG &&
+ !(sealalg == 0xFFFF || sealalg == ctx->sealalg)) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
+ (ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
+ (ctx->sealalg == SEAL_ALG_DES3KD &&
+ signalg != SGN_ALG_HMAC_SHA1_DES3_KD)||
+ (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4 &&
+ signalg != SGN_ALG_HMAC_MD5)) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ case SGN_ALG_HMAC_MD5:
+ cksum_len = 8;
+ if (toktype != KG_TOK_WRAP_MSG)
+ sign_usage = 15;
+ break;
+ case SGN_ALG_3:
+ cksum_len = 16;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ cksum_len = 20;
+ break;
+ default:
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ /* get the token parameters */
+ code = kg_get_seq_num(context, ctx->seq, ptr + 14, ptr + 6, &direction,
+ &seqnum);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_BAD_SIG;
+ }
+
+ /* decode the message, if SEAL */
+ if (toktype == KG_TOK_WRAP_MSG) {
+ if (sealalg != 0xFFFF) {
+ if (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) {
+ unsigned char bigend_seqnum[4];
+ krb5_keyblock *enc_key;
+ size_t i;
+
+ store_32_be(seqnum, bigend_seqnum);
+
+ code = krb5_k_key_keyblock(context, ctx->enc, &enc_key);
+ if (code != 0) {
+ retval = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ assert(enc_key->length == 16);
+
+ for (i = 0; i < enc_key->length; i++)
+ ((char *)enc_key->contents)[i] ^= 0xF0;
+
+ code = kg_arcfour_docrypt_iov(context, enc_key, 0,
+ &bigend_seqnum[0], 4,
+ iov, iov_count);
+ krb5_free_keyblock(context, enc_key);
+ } else {
+ code = kg_decrypt_iov(context, 0,
+ ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0),
+ 0 /*EC*/, 0 /*RRC*/,
+ ctx->enc, KG_USAGE_SEAL, NULL,
+ iov, iov_count);
+ }
+ if (code != 0) {
+ retval = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ }
+ conflen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
+ }
+
+ if (header->buffer.length != token_wrapper_len + 14 + cksum_len + conflen) {
+ retval = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+
+ /* compute the checksum of the message */
+
+ /* initialize the checksum */
+
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_MD2_5:
+ case SGN_ALG_DES_MAC:
+ case SGN_ALG_3:
+ md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+ break;
+ case SGN_ALG_HMAC_MD5:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
+ break;
+ default:
+ abort();
+ }
+
+ code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
+ if (code != 0) {
+ retval = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ md5cksum.length = sumlen;
+
+ /* compute the checksum of the message */
+ code = kg_make_checksum_iov_v1(context, md5cksum.checksum_type,
+ cksum_len, ctx->seq, ctx->enc,
+ sign_usage, iov, iov_count, toktype,
+ &md5cksum);
+ if (code != 0) {
+ retval = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ switch (signalg) {
+ case SGN_ALG_DES_MAC_MD5:
+ case SGN_ALG_3:
+ code = kg_encrypt_inplace(context, ctx->seq, KG_USAGE_SEAL,
+ (g_OID_equal(ctx->mech_used,
+ gss_mech_krb5_old) ?
+ ctx->seq->keyblock.contents : NULL),
+ md5cksum.contents, 16);
+ if (code != 0) {
+ retval = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ cksum.length = cksum_len;
+ cksum.contents = md5cksum.contents + 16 - cksum.length;
+
+ code = k5_bcmp(cksum.contents, ptr + 14, cksum.length);
+ break;
+ case SGN_ALG_HMAC_SHA1_DES3_KD:
+ case SGN_ALG_HMAC_MD5:
+ code = k5_bcmp(md5cksum.contents, ptr + 14, cksum_len);
+ break;
+ default:
+ code = 0;
+ retval = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ break;
+ }
+
+ if (code != 0) {
+ code = 0;
+ retval = GSS_S_BAD_SIG;
+ goto cleanup;
+ }
+
+ /*
+ * For GSS_C_DCE_STYLE, the caller manages the padding, because the
+ * pad length is in the RPC PDU. The value of the padding may be
+ * uninitialized. For normal GSS, the last bytes of the decrypted
+ * data contain the pad length. kg_fixup_padding_iov() will find
+ * this and fixup the last data IOV appropriately.
+ */
+ if (toktype == KG_TOK_WRAP_MSG &&
+ (ctx->gss_flags & GSS_C_DCE_STYLE) == 0) {
+ retval = kg_fixup_padding_iov(&code, iov, iov_count);
+ if (retval != GSS_S_COMPLETE)
+ goto cleanup;
+ }
+
+ if (conf_state != NULL)
+ *conf_state = (sealalg != 0xFFFF);
+
+ if (qop_state != NULL)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ if ((ctx->initiate && direction != 0xff) ||
+ (!ctx->initiate && direction != 0)) {
+ *minor_status = (OM_uint32)G_BAD_DIRECTION;
+ retval = GSS_S_BAD_SIG;
+ }
+
+ code = 0;
+ retval = g_seqstate_check(ctx->seqstate, (uint64_t)seqnum);
+
+cleanup:
+ krb5_free_checksum_contents(context, &md5cksum);
+
+ *minor_status = code;
+
+ return retval;
+}
+
+/*
+ * Caller must provide TOKEN | DATA | PADDING | TRAILER, except
+ * for DCE in which case it can just provide TOKEN | DATA (must
+ * guarantee that DATA is padded)
+ */
+static OM_uint32
+kg_unseal_iov_token(OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ krb5_error_code code;
+ krb5_context context = ctx->k5_context;
+ unsigned char *ptr;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t padding;
+ gss_iov_buffer_t trailer;
+ size_t input_length;
+ unsigned int bodysize;
+ int toktype2;
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ if (header == NULL) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+ ptr = (unsigned char *)header->buffer.value;
+ input_length = header->buffer.length;
+
+ if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0 &&
+ toktype == KG_TOK_WRAP_MSG) {
+ size_t data_length, assoc_data_length;
+
+ kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
+
+ input_length += data_length - assoc_data_length;
+
+ if (padding != NULL)
+ input_length += padding->buffer.length;
+
+ if (trailer != NULL)
+ input_length += trailer->buffer.length;
+ }
+
+ code = g_verify_token_header(ctx->mech_used,
+ &bodysize, &ptr, -1,
+ input_length, 0);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (bodysize < 2) {
+ *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ toktype2 = load_16_be(ptr);
+
+ ptr += 2;
+ bodysize -= 2;
+
+ switch (toktype2) {
+ case KG2_TOK_MIC_MSG:
+ case KG2_TOK_WRAP_MSG:
+ case KG2_TOK_DEL_CTX:
+ code = gss_krb5int_unseal_v3_iov(context, minor_status, ctx, iov, iov_count,
+ conf_state, qop_state, toktype);
+ break;
+ case KG_TOK_MIC_MSG:
+ case KG_TOK_WRAP_MSG:
+ case KG_TOK_DEL_CTX:
+ code = kg_unseal_v1_iov(context, minor_status, ctx, iov, iov_count,
+ (size_t)(ptr - (unsigned char *)header->buffer.value),
+ conf_state, qop_state, toktype);
+ break;
+ default:
+ *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+ code = GSS_S_DEFECTIVE_TOKEN;
+ break;
+ }
+
+ if (code != 0)
+ save_error_info(*minor_status, context);
+
+ return code;
+}
+
+/*
+ * Split a STREAM | SIGN_DATA | DATA into
+ * HEADER | SIGN_DATA | DATA | PADDING | TRAILER
+ */
+static OM_uint32
+kg_unseal_stream_iov(OM_uint32 *minor_status,
+ krb5_gss_ctx_id_rec *ctx,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ unsigned char *ptr;
+ unsigned int bodysize;
+ OM_uint32 code = 0, major_status = GSS_S_FAILURE;
+ krb5_context context = ctx->k5_context;
+ int conf_req_flag, toktype2;
+ int i = 0, j;
+ gss_iov_buffer_desc *tiov = NULL;
+ gss_iov_buffer_t stream, data = NULL;
+ gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer;
+
+ assert(toktype == KG_TOK_WRAP_MSG);
+
+ if (toktype != KG_TOK_WRAP_MSG || (ctx->gss_flags & GSS_C_DCE_STYLE)) {
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ stream = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM);
+ assert(stream != NULL);
+
+ ptr = (unsigned char *)stream->buffer.value;
+
+ code = g_verify_token_header(ctx->mech_used,
+ &bodysize, &ptr, -1,
+ stream->buffer.length, 0);
+ if (code != 0) {
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+
+ if (bodysize < 2) {
+ *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ toktype2 = load_16_be(ptr);
+
+ ptr += 2;
+ bodysize -= 2;
+
+ tiov = (gss_iov_buffer_desc *)calloc((size_t)iov_count + 2, sizeof(gss_iov_buffer_desc));
+ if (tiov == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ /* HEADER */
+ theader = &tiov[i++];
+ theader->type = GSS_IOV_BUFFER_TYPE_HEADER;
+ theader->buffer.value = stream->buffer.value;
+ theader->buffer.length = ptr - (unsigned char *)stream->buffer.value;
+ if (bodysize < 14 ||
+ stream->buffer.length != theader->buffer.length + bodysize) {
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+ theader->buffer.length += 14;
+
+ /* n[SIGN_DATA] | DATA | m[SIGN_DATA] */
+ for (j = 0; j < iov_count; j++) {
+ OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[j].type);
+
+ if (type == GSS_IOV_BUFFER_TYPE_DATA) {
+ if (data != NULL) {
+ /* only a single DATA buffer can appear */
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ data = &iov[j];
+ tdata = &tiov[i];
+ }
+ if (type == GSS_IOV_BUFFER_TYPE_DATA ||
+ type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
+ tiov[i++] = iov[j];
+ }
+
+ if (data == NULL) {
+ /* a single DATA buffer must be present */
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ /* PADDING | TRAILER */
+ tpadding = &tiov[i++];
+ tpadding->type = GSS_IOV_BUFFER_TYPE_PADDING;
+ tpadding->buffer.length = 0;
+ tpadding->buffer.value = NULL;
+
+ ttrailer = &tiov[i++];
+ ttrailer->type = GSS_IOV_BUFFER_TYPE_TRAILER;
+
+ switch (toktype2) {
+ case KG2_TOK_MIC_MSG:
+ case KG2_TOK_WRAP_MSG:
+ case KG2_TOK_DEL_CTX: {
+ size_t ec, rrc;
+ krb5_enctype enctype;
+ unsigned int k5_headerlen = 0;
+ unsigned int k5_trailerlen = 0;
+
+ if (ctx->have_acceptor_subkey)
+ enctype = ctx->acceptor_subkey->keyblock.enctype;
+ else
+ enctype = ctx->subkey->keyblock.enctype;
+ conf_req_flag = ((ptr[0] & FLAG_WRAP_CONFIDENTIAL) != 0);
+ ec = conf_req_flag ? load_16_be(ptr + 2) : 0;
+ rrc = load_16_be(ptr + 4);
+
+ if (rrc != 0) {
+ if (!gss_krb5int_rotate_left((unsigned char *)stream->buffer.value + 16,
+ stream->buffer.length - 16, rrc)) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ store_16_be(0, ptr + 4); /* set RRC to zero */
+ }
+
+ if (conf_req_flag) {
+ code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen);
+ if (code != 0)
+ goto cleanup;
+ theader->buffer.length += k5_headerlen; /* length validated later */
+ }
+
+ /* no PADDING for CFX, EC is used instead */
+ code = krb5_c_crypto_length(context, enctype,
+ conf_req_flag ? KRB5_CRYPTO_TYPE_TRAILER : KRB5_CRYPTO_TYPE_CHECKSUM,
+ &k5_trailerlen);
+ if (code != 0)
+ goto cleanup;
+
+ ttrailer->buffer.length = ec + (conf_req_flag ? 16 : 0 /* E(Header) */) + k5_trailerlen;
+ ttrailer->buffer.value = (unsigned char *)stream->buffer.value +
+ stream->buffer.length - ttrailer->buffer.length;
+ break;
+ }
+ case KG_TOK_MIC_MSG:
+ case KG_TOK_WRAP_MSG:
+ case KG_TOK_DEL_CTX:
+ theader->buffer.length += ctx->cksum_size +
+ kg_confounder_size(context, ctx->enc->keyblock.enctype);
+
+ /*
+ * we can't set the padding accurately until decryption;
+ * kg_fixup_padding_iov() will take care of this
+ */
+ tpadding->buffer.length = 1;
+ tpadding->buffer.value = (unsigned char *)stream->buffer.value + stream->buffer.length - 1;
+
+ /* no TRAILER for pre-CFX */
+ ttrailer->buffer.length = 0;
+ ttrailer->buffer.value = NULL;
+
+ break;
+ default:
+ code = (OM_uint32)G_BAD_TOK_HEADER;
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ break;
+ }
+
+ /* IOV: -----------0-------------+---1---+--2--+----------------3--------------*/
+ /* Old: GSS-Header | Conf | Data | Pad | */
+ /* CFX: GSS-Header | Kerb-Header | Data | | EC | E(Header) | Kerb-Trailer */
+ /* GSS: -------GSS-HEADER--------+-DATA--+-PAD-+----------GSS-TRAILER----------*/
+
+ /* validate lengths */
+ if (stream->buffer.length < theader->buffer.length +
+ tpadding->buffer.length +
+ ttrailer->buffer.length)
+ {
+ code = (OM_uint32)KRB5_BAD_MSIZE;
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+
+ /* setup data */
+ tdata->buffer.length = stream->buffer.length - ttrailer->buffer.length -
+ tpadding->buffer.length - theader->buffer.length;
+
+ assert(data != NULL);
+
+ if (data->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
+ code = kg_allocate_iov(tdata, tdata->buffer.length);
+ if (code != 0)
+ goto cleanup;
+ memcpy(tdata->buffer.value,
+ (unsigned char *)stream->buffer.value + theader->buffer.length, tdata->buffer.length);
+ } else
+ tdata->buffer.value = (unsigned char *)stream->buffer.value + theader->buffer.length;
+
+ assert(i <= iov_count + 2);
+
+ major_status = kg_unseal_iov_token(&code, ctx, conf_state, qop_state,
+ tiov, i, toktype);
+ if (major_status == GSS_S_COMPLETE)
+ *data = *tdata;
+ else
+ kg_release_iov(tdata, 1);
+
+cleanup:
+ if (tiov != NULL)
+ free(tiov);
+
+ *minor_status = code;
+
+ return major_status;
+}
+
+OM_uint32
+kg_unseal_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ krb5_gss_ctx_id_rec *ctx;
+ OM_uint32 code;
+
+ ctx = (krb5_gss_ctx_id_rec *)context_handle;
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ if (kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM) != NULL) {
+ code = kg_unseal_stream_iov(minor_status, ctx, conf_state, qop_state,
+ iov, iov_count, toktype);
+ } else {
+ code = kg_unseal_iov_token(minor_status, ctx, conf_state, qop_state,
+ iov, iov_count, toktype);
+ }
+
+ return code;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_unwrap_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major_status;
+
+ major_status = kg_unseal_iov(minor_status, context_handle,
+ conf_state, qop_state,
+ iov, iov_count, KG_TOK_WRAP_MSG);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_verify_mic_iov(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ OM_uint32 major_status;
+
+ major_status = kg_unseal_iov(minor_status, context_handle,
+ NULL, qop_state,
+ iov, iov_count, KG_TOK_MIC_MSG);
+
+ return major_status;
+}
diff --git a/src/lib/gssapi/krb5/krb5_gss_glue.c b/src/lib/gssapi/krb5/krb5_gss_glue.c
new file mode 100644
index 000000000000..b35a2152344e
--- /dev/null
+++ b/src/lib/gssapi/krb5/krb5_gss_glue.c
@@ -0,0 +1,445 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (c) 2006-2008, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * The copyright holder's name is not used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_get_tkt_flags(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ krb5_flags *ticket_flags)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_GET_TKT_FLAGS_OID_LENGTH,
+ GSS_KRB5_GET_TKT_FLAGS_OID };
+ OM_uint32 major_status;
+ gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
+
+ if (ticket_flags == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ major_status = gss_inquire_sec_context_by_oid(minor_status,
+ context_handle,
+ (gss_OID)&req_oid,
+ &data_set);
+ if (major_status != GSS_S_COMPLETE)
+ return major_status;
+
+ if (data_set == GSS_C_NO_BUFFER_SET ||
+ data_set->count != 1 ||
+ data_set->elements[0].length != sizeof(*ticket_flags)) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ *ticket_flags = *((krb5_flags *)data_set->elements[0].value);
+
+ gss_release_buffer_set(minor_status, &data_set);
+
+ *minor_status = 0;
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_copy_ccache(OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ krb5_ccache out_ccache)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_COPY_CCACHE_OID_LENGTH,
+ GSS_KRB5_COPY_CCACHE_OID };
+ OM_uint32 major_status;
+ gss_buffer_desc req_buffer;
+
+ if (out_ccache == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ req_buffer.value = out_ccache;
+ req_buffer.length = sizeof(out_ccache);
+
+ major_status = gss_set_cred_option(minor_status,
+ &cred_handle,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_import_cred(OM_uint32 *minor_status,
+ krb5_ccache id,
+ krb5_principal keytab_principal,
+ krb5_keytab keytab,
+ gss_cred_id_t *cred)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_IMPORT_CRED_OID_LENGTH,
+ GSS_KRB5_IMPORT_CRED_OID };
+ OM_uint32 major_status;
+ struct krb5_gss_import_cred_req req;
+ gss_buffer_desc req_buffer;
+
+ if (cred == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *cred = GSS_C_NO_CREDENTIAL;
+
+ req.id = id;
+ req.keytab_principal = keytab_principal;
+ req.keytab = keytab;
+
+ req_buffer.value = &req;
+ req_buffer.length = sizeof(req);
+
+ major_status = gss_set_cred_option(minor_status,
+ cred,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ OM_uint32 version,
+ void **kctx)
+{
+ unsigned char oid_buf[GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH + 6];
+ gss_OID_desc req_oid;
+ OM_uint32 major_status, minor;
+ gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
+
+ if (kctx == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ *kctx = NULL;
+
+ req_oid.elements = oid_buf;
+ req_oid.length = sizeof(oid_buf);
+
+ major_status = generic_gss_oid_compose(minor_status,
+ GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID,
+ GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH,
+ (int)version,
+ &req_oid);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+ major_status = gss_inquire_sec_context_by_oid(minor_status,
+ *context_handle,
+ &req_oid,
+ &data_set);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+ if (data_set == GSS_C_NO_BUFFER_SET ||
+ data_set->count != 1 ||
+ data_set->elements[0].length != sizeof(void *)) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ *kctx = *((void **)data_set->elements[0].value);
+
+ /* Clean up the context state (it is an error for
+ * someone to attempt to use this context again)
+ */
+ (void)gss_delete_sec_context(minor_status, context_handle, NULL);
+ *context_handle = GSS_C_NO_CONTEXT;
+
+ generic_gss_release_buffer_set(&minor, &data_set);
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ OM_uint32 num_ktypes,
+ krb5_enctype *ktypes)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID_LENGTH,
+ GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID };
+ OM_uint32 major_status;
+ struct krb5_gss_set_allowable_enctypes_req req;
+ gss_buffer_desc req_buffer;
+
+ req.num_ktypes = num_ktypes;
+ req.ktypes = ktypes;
+
+ req_buffer.length = sizeof(req);
+ req_buffer.value = &req;
+
+ major_status = gss_set_cred_option(minor_status,
+ &cred,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_ccache_name(OM_uint32 *minor_status,
+ const char *name,
+ const char **out_name)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_CCACHE_NAME_OID_LENGTH,
+ GSS_KRB5_CCACHE_NAME_OID };
+ OM_uint32 major_status;
+ struct krb5_gss_ccache_name_req req;
+ gss_buffer_desc req_buffer;
+
+ req.name = name;
+ req.out_name = out_name;
+
+ req_buffer.length = sizeof(req);
+ req_buffer.value = &req;
+
+ major_status = gssspi_mech_invoke(minor_status,
+ (gss_OID)gss_mech_krb5,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *kctx)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID_LENGTH,
+ GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID };
+ OM_uint32 major_status;
+ gss_buffer_desc req_buffer;
+
+ req_buffer.length = sizeof(kctx);
+ req_buffer.value = kctx;
+
+ major_status = gssspi_mech_invoke(minor_status,
+ (gss_OID)gss_mech_krb5,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_register_acceptor_identity(const char *keytab)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID_LENGTH,
+ GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID };
+ OM_uint32 major_status;
+ OM_uint32 minor_status;
+ gss_buffer_desc req_buffer;
+
+ req_buffer.length = (keytab == NULL) ? 0 : strlen(keytab);
+ req_buffer.value = (char *)keytab;
+
+ major_status = gssspi_mech_invoke(&minor_status,
+ (gss_OID)gss_mech_krb5,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+#ifndef _WIN32
+krb5_error_code
+krb5_gss_use_kdc_context(void)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_USE_KDC_CONTEXT_OID_LENGTH,
+ GSS_KRB5_USE_KDC_CONTEXT_OID };
+ OM_uint32 major_status;
+ OM_uint32 minor_status;
+ gss_buffer_desc req_buffer;
+ krb5_error_code ret;
+
+ req_buffer.length = 0;
+ req_buffer.value = NULL;
+
+ major_status = gssspi_mech_invoke(&minor_status,
+ (gss_OID)gss_mech_krb5,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ if (major_status != GSS_S_COMPLETE) {
+ if (minor_status != 0)
+ ret = (krb5_error_code)minor_status;
+ else
+ ret = KRB5KRB_ERR_GENERIC;
+ } else
+ ret = 0;
+
+ return ret;
+}
+#endif
+
+/*
+ * This API should go away and be replaced with an accessor
+ * into a gss_name_t.
+ */
+OM_uint32 KRB5_CALLCONV
+gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int ad_type,
+ gss_buffer_t ad_data)
+{
+ gss_OID_desc req_oid;
+ unsigned char oid_buf[GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH + 6];
+ OM_uint32 major_status;
+ gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
+
+ if (ad_data == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ req_oid.elements = oid_buf;
+ req_oid.length = sizeof(oid_buf);
+
+ major_status = generic_gss_oid_compose(minor_status,
+ GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID,
+ GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH,
+ ad_type,
+ &req_oid);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+ major_status = gss_inquire_sec_context_by_oid(minor_status,
+ context_handle,
+ (gss_OID)&req_oid,
+ &data_set);
+ if (major_status != GSS_S_COMPLETE) {
+ return major_status;
+ }
+
+ if (data_set == GSS_C_NO_BUFFER_SET ||
+ data_set->count != 1) {
+ return GSS_S_FAILURE;
+ }
+
+ ad_data->length = data_set->elements[0].length;
+ ad_data->value = data_set->elements[0].value;
+
+ data_set->elements[0].length = 0;
+ data_set->elements[0].value = NULL;
+
+ data_set->count = 0;
+
+ gss_release_buffer_set(minor_status, &data_set);
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_set_cred_rcache(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ krb5_rcache rcache)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH,
+ GSS_KRB5_SET_CRED_RCACHE_OID };
+ OM_uint32 major_status;
+ gss_buffer_desc req_buffer;
+
+ req_buffer.length = sizeof(rcache);
+ req_buffer.value = rcache;
+
+ major_status = gss_set_cred_option(minor_status,
+ &cred,
+ (gss_OID)&req_oid,
+ &req_buffer);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ krb5_timestamp *authtime)
+{
+ static const gss_OID_desc req_oid = {
+ GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH,
+ GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID };
+ OM_uint32 major_status;
+ gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
+
+ if (authtime == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ major_status = gss_inquire_sec_context_by_oid(minor_status,
+ context_handle,
+ (gss_OID)&req_oid,
+ &data_set);
+ if (major_status != GSS_S_COMPLETE)
+ return major_status;
+
+ if (data_set == GSS_C_NO_BUFFER_SET ||
+ data_set->count != 1 ||
+ data_set->elements[0].length != sizeof(*authtime)) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ *authtime = *((krb5_timestamp *)data_set->elements[0].value);
+
+ gss_release_buffer_set(minor_status, &data_set);
+
+ *minor_status = 0;
+
+ return GSS_S_COMPLETE;
+}
diff --git a/src/lib/gssapi/krb5/lucid_context.c b/src/lib/gssapi/krb5/lucid_context.c
new file mode 100644
index 000000000000..a894f0e7355c
--- /dev/null
+++ b/src/lib/gssapi/krb5/lucid_context.c
@@ -0,0 +1,292 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/lucid_context.c */
+/*
+ * Copyright 2004, 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/* Externalize a "lucid" security context from a krb5_gss_ctx_id_rec
+ * structure. */
+#include "gssapiP_krb5.h"
+#include "gssapi_krb5.h"
+
+/*
+ * Local routine prototypes
+ */
+static void
+free_external_lucid_ctx_v1(
+ gss_krb5_lucid_context_v1_t *ctx);
+
+static void
+free_lucid_key_data(
+ gss_krb5_lucid_key_t *key);
+
+static krb5_error_code
+copy_keyblock_to_lucid_key(
+ krb5_keyblock *k5key,
+ gss_krb5_lucid_key_t *lkey);
+
+static krb5_error_code
+make_external_lucid_ctx_v1(
+ krb5_gss_ctx_id_rec * gctx,
+ int version,
+ void **out_ptr);
+
+
+/*
+ * Exported routines
+ */
+
+OM_uint32
+gss_krb5int_export_lucid_sec_context(
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ krb5_error_code kret = 0;
+ OM_uint32 retval;
+ krb5_gss_ctx_id_t ctx = (krb5_gss_ctx_id_t)context_handle;
+ void *lctx = NULL;
+ int version = 0;
+ gss_buffer_desc rep;
+
+ /* Assume failure */
+ retval = GSS_S_FAILURE;
+ *minor_status = 0;
+ *data_set = GSS_C_NO_BUFFER_SET;
+
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ retval = generic_gss_oid_decompose(minor_status,
+ GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID,
+ GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH,
+ desired_object,
+ &version);
+ if (GSS_ERROR(retval))
+ return retval;
+
+ /* Externalize a structure of the right version */
+ switch (version) {
+ case 1:
+ kret = make_external_lucid_ctx_v1((krb5_pointer)ctx,
+ version, &lctx);
+ break;
+ default:
+ kret = (OM_uint32) KG_LUCID_VERSION;
+ break;
+ }
+
+ if (kret)
+ goto error_out;
+
+ rep.value = &lctx;
+ rep.length = sizeof(lctx);
+
+ retval = generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
+ if (GSS_ERROR(retval))
+ goto error_out;
+
+error_out:
+ if (*minor_status == 0)
+ *minor_status = (OM_uint32) kret;
+ return(retval);
+}
+
+/*
+ * Frees the storage associated with an
+ * exported lucid context structure.
+ */
+OM_uint32
+gss_krb5int_free_lucid_sec_context(
+ OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ const gss_OID desired_object,
+ gss_buffer_t value)
+{
+ OM_uint32 retval;
+ krb5_error_code kret = 0;
+ int version;
+ void *kctx;
+
+ /* Assume failure */
+ retval = GSS_S_FAILURE;
+ *minor_status = 0;
+
+ kctx = value->value;
+ if (!kctx) {
+ kret = EINVAL;
+ goto error_out;
+ }
+
+ /* Determine version and call correct free routine */
+ version = ((gss_krb5_lucid_context_version_t *)kctx)->version;
+ switch (version) {
+ case 1:
+ free_external_lucid_ctx_v1((gss_krb5_lucid_context_v1_t*) kctx);
+ break;
+ default:
+ kret = EINVAL;
+ break;
+ }
+
+ if (kret)
+ goto error_out;
+
+ /* Success! */
+ *minor_status = 0;
+ retval = GSS_S_COMPLETE;
+
+ return (retval);
+
+error_out:
+ if (*minor_status == 0)
+ *minor_status = (OM_uint32) kret;
+ return(retval);
+}
+
+/*
+ * Local routines
+ */
+
+static krb5_error_code
+make_external_lucid_ctx_v1(
+ krb5_gss_ctx_id_rec * gctx,
+ int version,
+ void **out_ptr)
+{
+ gss_krb5_lucid_context_v1_t *lctx = NULL;
+ unsigned int bufsize = sizeof(gss_krb5_lucid_context_v1_t);
+ krb5_error_code retval;
+
+ /* Allocate the structure */
+ if ((lctx = xmalloc(bufsize)) == NULL) {
+ retval = ENOMEM;
+ goto error_out;
+ }
+
+ memset(lctx, 0, bufsize);
+
+ lctx->version = 1;
+ lctx->initiate = gctx->initiate ? 1 : 0;
+ lctx->endtime = gctx->krb_times.endtime;
+ lctx->send_seq = gctx->seq_send;
+ lctx->recv_seq = gctx->seq_recv;
+ lctx->protocol = gctx->proto;
+ /* gctx->proto == 0 ==> rfc1964-style key information
+ gctx->proto == 1 ==> cfx-style (draft-ietf-krb-wg-gssapi-cfx-07) keys */
+ if (gctx->proto == 0) {
+ lctx->rfc1964_kd.sign_alg = gctx->signalg;
+ lctx->rfc1964_kd.seal_alg = gctx->sealalg;
+ /* Copy key */
+ if ((retval = copy_keyblock_to_lucid_key(&gctx->seq->keyblock,
+ &lctx->rfc1964_kd.ctx_key)))
+ goto error_out;
+ }
+ else if (gctx->proto == 1) {
+ /* Copy keys */
+ /* (subkey is always present, either a copy of the kerberos
+ session key or a subkey) */
+ if ((retval = copy_keyblock_to_lucid_key(&gctx->subkey->keyblock,
+ &lctx->cfx_kd.ctx_key)))
+ goto error_out;
+ if (gctx->have_acceptor_subkey) {
+ if ((retval = copy_keyblock_to_lucid_key(&gctx->acceptor_subkey->keyblock,
+ &lctx->cfx_kd.acceptor_subkey)))
+ goto error_out;
+ lctx->cfx_kd.have_acceptor_subkey = 1;
+ }
+ }
+ else {
+ xfree(lctx);
+ return EINVAL; /* XXX better error code? */
+ }
+
+ /* Success! */
+ *out_ptr = lctx;
+ return 0;
+
+error_out:
+ if (lctx) {
+ free_external_lucid_ctx_v1(lctx);
+ }
+ return retval;
+
+}
+
+/* Copy the contents of a krb5_keyblock to a gss_krb5_lucid_key_t structure */
+static krb5_error_code
+copy_keyblock_to_lucid_key(
+ krb5_keyblock *k5key,
+ gss_krb5_lucid_key_t *lkey)
+{
+ if (!k5key || !k5key->contents || k5key->length == 0)
+ return EINVAL;
+
+ memset(lkey, 0, sizeof(gss_krb5_lucid_key_t));
+
+ /* Allocate storage for the key data */
+ if ((lkey->data = xmalloc(k5key->length)) == NULL) {
+ return ENOMEM;
+ }
+ memcpy(lkey->data, k5key->contents, k5key->length);
+ lkey->length = k5key->length;
+ lkey->type = k5key->enctype;
+
+ return 0;
+}
+
+
+/* Free any storage associated with a gss_krb5_lucid_key_t structure */
+static void
+free_lucid_key_data(
+ gss_krb5_lucid_key_t *key)
+{
+ if (key) {
+ if (key->data && key->length) {
+ zap(key->data, key->length);
+ xfree(key->data);
+ zap(key, sizeof(gss_krb5_lucid_key_t));
+ }
+ }
+}
+/* Free any storage associated with a gss_krb5_lucid_context_v1 structure */
+static void
+free_external_lucid_ctx_v1(
+ gss_krb5_lucid_context_v1_t *ctx)
+{
+ if (ctx) {
+ if (ctx->protocol == 0) {
+ free_lucid_key_data(&ctx->rfc1964_kd.ctx_key);
+ }
+ if (ctx->protocol == 1) {
+ free_lucid_key_data(&ctx->cfx_kd.ctx_key);
+ if (ctx->cfx_kd.have_acceptor_subkey)
+ free_lucid_key_data(&ctx->cfx_kd.acceptor_subkey);
+ }
+ xfree(ctx);
+ ctx = NULL;
+ }
+}
diff --git a/src/lib/gssapi/krb5/naming_exts.c b/src/lib/gssapi/krb5/naming_exts.c
new file mode 100644
index 000000000000..6062a6dd8052
--- /dev/null
+++ b/src/lib/gssapi/krb5/naming_exts.c
@@ -0,0 +1,684 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/naming_exts.c */
+/*
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+krb5_error_code
+kg_init_name(krb5_context context, krb5_principal principal,
+ char *service, char *host, krb5_authdata_context ad_context,
+ krb5_flags flags, krb5_gss_name_t *ret_name)
+{
+ krb5_error_code code;
+ krb5_gss_name_t name;
+
+ *ret_name = NULL;
+
+ assert(principal != NULL);
+
+ if (principal == NULL)
+ return EINVAL;
+
+ name = xmalloc(sizeof(krb5_gss_name_rec));
+ if (name == NULL)
+ return ENOMEM;
+
+ memset(name, 0, sizeof(krb5_gss_name_rec));
+
+ code = k5_mutex_init(&name->lock);
+ if (code != 0)
+ goto cleanup;
+
+ if ((flags & KG_INIT_NAME_NO_COPY) == 0) {
+ code = krb5_copy_principal(context, principal, &name->princ);
+ if (code != 0)
+ goto cleanup;
+
+ if (ad_context != NULL) {
+ code = krb5_authdata_context_copy(context,
+ ad_context,
+ &name->ad_context);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = ENOMEM;
+ if (service != NULL) {
+ name->service = strdup(service);
+ if (name->service == NULL)
+ goto cleanup;
+ }
+ if (host != NULL) {
+ name->host = strdup(host);
+ if (name->host == NULL)
+ goto cleanup;
+ }
+ code = 0;
+ } else {
+ name->princ = principal;
+ name->service = service;
+ name->host = host;
+ name->ad_context = ad_context;
+ }
+
+ *ret_name = name;
+
+cleanup:
+ if (code != 0)
+ kg_release_name(context, &name);
+
+ return code;
+}
+
+krb5_error_code
+kg_release_name(krb5_context context,
+ krb5_gss_name_t *name)
+{
+ if (*name != NULL) {
+ krb5_free_principal(context, (*name)->princ);
+ free((*name)->service);
+ free((*name)->host);
+ krb5_authdata_context_free(context, (*name)->ad_context);
+ k5_mutex_destroy(&(*name)->lock);
+ free(*name);
+ *name = NULL;
+ }
+
+ return 0;
+}
+
+krb5_error_code
+kg_duplicate_name(krb5_context context,
+ const krb5_gss_name_t src,
+ krb5_gss_name_t *dst)
+{
+ krb5_error_code code;
+
+ k5_mutex_lock(&src->lock);
+ code = kg_init_name(context, src->princ, src->service, src->host,
+ src->ad_context, 0, dst);
+ k5_mutex_unlock(&src->lock);
+ return code;
+}
+
+
+krb5_boolean
+kg_compare_name(krb5_context context,
+ krb5_gss_name_t name1,
+ krb5_gss_name_t name2)
+{
+ return krb5_principal_compare(context, name1->princ, name2->princ);
+}
+
+/* Determine the principal to use for an acceptor name, which is different from
+ * name->princ for host-based names. */
+krb5_boolean
+kg_acceptor_princ(krb5_context context, krb5_gss_name_t name,
+ krb5_principal *princ_out)
+{
+ krb5_error_code code;
+ const char *host;
+ char *tmp = NULL;
+
+ *princ_out = NULL;
+ if (name == NULL)
+ return 0;
+
+ /* If it's not a host-based name, just copy name->princ. */
+ if (name->service == NULL)
+ return krb5_copy_principal(context, name->princ, princ_out);
+
+ if (name->host != NULL && name->princ->length == 2) {
+ /* If a host was given, we have to use the canonicalized form of it (as
+ * given by krb5_sname_to_principal) for backward compatibility. */
+ const krb5_data *d = &name->princ->data[1];
+ tmp = k5memdup0(d->data, d->length, &code);
+ if (tmp == NULL)
+ return ENOMEM;
+ host = tmp;
+ } else /* No host was given; use an empty string. */
+ host = "";
+
+ code = krb5_build_principal(context, princ_out, 0, "", name->service, host,
+ (char *)NULL);
+ if (*princ_out != NULL)
+ (*princ_out)->type = KRB5_NT_SRV_HST;
+ free(tmp);
+ return code;
+}
+
+static OM_uint32
+kg_map_name_error(OM_uint32 *minor_status, krb5_error_code code)
+{
+ OM_uint32 major_status;
+
+ switch (code) {
+ case 0:
+ major_status = GSS_S_COMPLETE;
+ break;
+ case ENOENT:
+ case EPERM:
+ major_status = GSS_S_UNAVAILABLE;
+ break;
+ default:
+ major_status = GSS_S_FAILURE;
+ break;
+ }
+
+ *minor_status = code;
+
+ return major_status;
+}
+
+/* Owns data on success */
+static krb5_error_code
+data_list_to_buffer_set(krb5_context context,
+ krb5_data *data,
+ gss_buffer_set_t *buffer_set)
+{
+ gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
+ OM_uint32 minor_status;
+ int i;
+ krb5_error_code code = 0;
+
+ if (data == NULL)
+ goto cleanup;
+
+ if (buffer_set == NULL)
+ goto cleanup;
+
+ if (GSS_ERROR(gss_create_empty_buffer_set(&minor_status,
+ &set))) {
+ assert(minor_status != 0);
+ code = minor_status;
+ goto cleanup;
+ }
+
+ for (i = 0; data[i].data != NULL; i++)
+ ;
+
+ set->count = i;
+ set->elements = gssalloc_calloc(i, sizeof(gss_buffer_desc));
+ if (set->elements == NULL) {
+ gss_release_buffer_set(&minor_status, &set);
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ /*
+ * Copy last element first so data remains properly
+ * NULL-terminated in case of allocation failure
+ * in data_to_gss() on windows.
+ */
+ for (i = set->count-1; i >= 0; i--) {
+ if (data_to_gss(&data[i], &set->elements[i])) {
+ gss_release_buffer_set(&minor_status, &set);
+ code = ENOMEM;
+ goto cleanup;
+ }
+ }
+cleanup:
+ krb5int_free_data_list(context, data);
+
+ if (buffer_set != NULL)
+ *buffer_set = set;
+
+ return code;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_inquire_name(OM_uint32 *minor_status,
+ gss_name_t name,
+ int *name_is_MN,
+ gss_OID *MN_mech,
+ gss_buffer_set_t *attrs)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ krb5_data *kattrs = NULL;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (attrs != NULL)
+ *attrs = GSS_C_NO_BUFFER_SET;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+
+ k5_mutex_lock(&kname->lock);
+
+ if (kname->ad_context == NULL) {
+ code = krb5_authdata_context_init(context, &kname->ad_context);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_authdata_get_attribute_types(context,
+ kname->ad_context,
+ &kattrs);
+ if (code != 0)
+ goto cleanup;
+
+ code = data_list_to_buffer_set(context, kattrs, attrs);
+ kattrs = NULL;
+ if (code != 0)
+ goto cleanup;
+
+cleanup:
+ k5_mutex_unlock(&kname->lock);
+ krb5int_free_data_list(context, kattrs);
+
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_get_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ krb5_data kattr;
+ krb5_boolean kauthenticated;
+ krb5_boolean kcomplete;
+ krb5_data kvalue;
+ krb5_data kdisplay_value;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+ k5_mutex_lock(&kname->lock);
+
+ if (kname->ad_context == NULL) {
+ code = krb5_authdata_context_init(context, &kname->ad_context);
+ if (code != 0) {
+ *minor_status = code;
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+ }
+
+ kattr.data = (char *)attr->value;
+ kattr.length = attr->length;
+
+ kauthenticated = FALSE;
+ kcomplete = FALSE;
+
+ code = krb5_authdata_get_attribute(context,
+ kname->ad_context,
+ &kattr,
+ &kauthenticated,
+ &kcomplete,
+ value ? &kvalue : NULL,
+ display_value ? &kdisplay_value : NULL,
+ more);
+ if (code == 0) {
+ if (value != NULL)
+ code = data_to_gss(&kvalue, value);
+
+ if (authenticated != NULL)
+ *authenticated = kauthenticated;
+ if (complete != NULL)
+ *complete = kcomplete;
+
+ if (display_value != NULL) {
+ if (code == 0)
+ code = data_to_gss(&kdisplay_value, display_value);
+ else
+ free(kdisplay_value.data);
+ }
+ }
+
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_set_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ int complete,
+ gss_buffer_t attr,
+ gss_buffer_t value)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ krb5_data kattr;
+ krb5_data kvalue;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+ k5_mutex_lock(&kname->lock);
+
+ if (kname->ad_context == NULL) {
+ code = krb5_authdata_context_init(context, &kname->ad_context);
+ if (code != 0) {
+ *minor_status = code;
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+ }
+
+ kattr.data = (char *)attr->value;
+ kattr.length = attr->length;
+
+ kvalue.data = (char *)value->value;
+ kvalue.length = value->length;
+
+ code = krb5_authdata_set_attribute(context,
+ kname->ad_context,
+ complete,
+ &kattr,
+ &kvalue);
+
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_delete_name_attribute(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t attr)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ krb5_data kattr;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+ k5_mutex_lock(&kname->lock);
+
+ if (kname->ad_context == NULL) {
+ code = krb5_authdata_context_init(context, &kname->ad_context);
+ if (code != 0) {
+ *minor_status = code;
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+ }
+
+ kattr.data = (char *)attr->value;
+ kattr.length = attr->length;
+
+ code = krb5_authdata_delete_attribute(context,
+ kname->ad_context,
+ &kattr);
+
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_map_name_to_any(OM_uint32 *minor_status,
+ gss_name_t name,
+ int authenticated,
+ gss_buffer_t type_id,
+ gss_any_t *output)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ char *kmodule;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+ k5_mutex_lock(&kname->lock);
+
+ if (kname->ad_context == NULL) {
+ code = krb5_authdata_context_init(context, &kname->ad_context);
+ if (code != 0) {
+ *minor_status = code;
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+ }
+
+ kmodule = (char *)type_id->value;
+ if (kmodule[type_id->length] != '\0') {
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+
+ code = krb5_authdata_export_internal(context,
+ kname->ad_context,
+ authenticated,
+ kmodule,
+ (void **)output);
+
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_release_any_name_mapping(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t type_id,
+ gss_any_t *input)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ char *kmodule;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+ k5_mutex_lock(&kname->lock);
+
+ if (kname->ad_context == NULL) {
+ code = krb5_authdata_context_init(context, &kname->ad_context);
+ if (code != 0) {
+ *minor_status = code;
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+ }
+
+ kmodule = (char *)type_id->value;
+ if (kmodule[type_id->length] != '\0') {
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+ return GSS_S_UNAVAILABLE;
+ }
+
+ code = krb5_authdata_free_internal(context,
+ kname->ad_context,
+ kmodule,
+ *input);
+ if (code == 0)
+ *input = NULL;
+
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_export_name_composite(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_buffer_t exp_composite_name)
+{
+ krb5_context context;
+ krb5_error_code code;
+ krb5_gss_name_t kname;
+ krb5_data *attrs = NULL;
+ char *princstr = NULL;
+ unsigned char *cp;
+ size_t princlen;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kname = (krb5_gss_name_t)name;
+ k5_mutex_lock(&kname->lock);
+
+ code = krb5_unparse_name(context, kname->princ, &princstr);
+ if (code != 0)
+ goto cleanup;
+
+ princlen = strlen(princstr);
+
+ if (kname->ad_context != NULL) {
+ code = krb5_authdata_export_attributes(context,
+ kname->ad_context,
+ AD_USAGE_MASK,
+ &attrs);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ /* 04 02 OID Name AuthData */
+
+ exp_composite_name->length = 10 + gss_mech_krb5->length + princlen;
+ exp_composite_name->length += 4; /* length of encoded attributes */
+ if (attrs != NULL)
+ exp_composite_name->length += attrs->length;
+ exp_composite_name->value = malloc(exp_composite_name->length);
+ if (exp_composite_name->value == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ cp = exp_composite_name->value;
+
+ /* Note: we assume the OID will be less than 128 bytes... */
+ *cp++ = 0x04;
+ *cp++ = 0x02;
+
+ store_16_be(gss_mech_krb5->length + 2, cp);
+ cp += 2;
+ *cp++ = 0x06;
+ *cp++ = (gss_mech_krb5->length) & 0xFF;
+ memcpy(cp, gss_mech_krb5->elements, gss_mech_krb5->length);
+ cp += gss_mech_krb5->length;
+
+ store_32_be(princlen, cp);
+ cp += 4;
+ memcpy(cp, princstr, princlen);
+ cp += princlen;
+
+ store_32_be(attrs != NULL ? attrs->length : 0, cp);
+ cp += 4;
+
+ if (attrs != NULL) {
+ memcpy(cp, attrs->data, attrs->length);
+ cp += attrs->length;
+ }
+
+cleanup:
+ krb5_free_unparsed_name(context, princstr);
+ krb5_free_data(context, attrs);
+ k5_mutex_unlock(&kname->lock);
+ krb5_free_context(context);
+
+ return kg_map_name_error(minor_status, code);
+}
+
+#if 0
+OM_uint32
+krb5_gss_display_name_ext(OM_uint32 *minor_status,
+ gss_name_t name,
+ gss_OID display_as_name_type,
+ gss_buffer_t display_name)
+{
+}
+#endif
diff --git a/src/lib/gssapi/krb5/prf.c b/src/lib/gssapi/krb5/prf.c
new file mode 100644
index 000000000000..e897074fc193
--- /dev/null
+++ b/src/lib/gssapi/krb5/prf.c
@@ -0,0 +1,139 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/prf.c */
+/*
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+#ifndef MIN /* Usually found in <sys/param.h>. */
+#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
+#endif
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_pseudo_random(OM_uint32 *minor_status,
+ gss_ctx_id_t context,
+ int prf_key,
+ const gss_buffer_t prf_in,
+ ssize_t desired_output_len,
+ gss_buffer_t prf_out)
+{
+ krb5_error_code code;
+ krb5_key key = NULL;
+ krb5_gss_ctx_id_t ctx;
+ int i;
+ OM_uint32 minor;
+ size_t prflen;
+ krb5_data t, ns;
+ unsigned char *p;
+
+ prf_out->length = 0;
+ prf_out->value = NULL;
+
+ t.length = 0;
+ t.data = NULL;
+
+ ns.length = 0;
+ ns.data = NULL;
+
+ ctx = (krb5_gss_ctx_id_t)context;
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return GSS_S_NO_CONTEXT;
+ }
+
+ switch (prf_key) {
+ case GSS_C_PRF_KEY_FULL:
+ if (ctx->have_acceptor_subkey) {
+ key = ctx->acceptor_subkey;
+ break;
+ }
+ /* fallthrough */
+ case GSS_C_PRF_KEY_PARTIAL:
+ key = ctx->subkey;
+ break;
+ default:
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ if (key == NULL) {
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ if (desired_output_len == 0)
+ return GSS_S_COMPLETE;
+
+ prf_out->value = k5alloc(desired_output_len, &code);
+ if (prf_out->value == NULL) {
+ code = KG_INPUT_TOO_LONG;
+ goto cleanup;
+ }
+ prf_out->length = desired_output_len;
+
+ code = krb5_c_prf_length(ctx->k5_context,
+ krb5_k_key_enctype(ctx->k5_context, key),
+ &prflen);
+ if (code != 0)
+ goto cleanup;
+
+ ns.length = 4 + prf_in->length;
+ ns.data = k5alloc(ns.length, &code);
+ if (ns.data == NULL) {
+ code = KG_INPUT_TOO_LONG;
+ goto cleanup;
+ }
+
+ t.length = prflen;
+ t.data = k5alloc(t.length, &code);
+ if (t.data == NULL)
+ goto cleanup;
+
+ memcpy(ns.data + 4, prf_in->value, prf_in->length);
+ i = 0;
+ p = (unsigned char *)prf_out->value;
+ while (desired_output_len > 0) {
+ store_32_be(i, ns.data);
+
+ code = krb5_k_prf(ctx->k5_context, key, &ns, &t);
+ if (code != 0)
+ goto cleanup;
+
+ memcpy(p, t.data, MIN(t.length, desired_output_len));
+
+ p += t.length;
+ desired_output_len -= t.length;
+ i++;
+ }
+
+cleanup:
+ if (code != 0)
+ gss_release_buffer(&minor, prf_out);
+ krb5_free_data_contents(ctx->k5_context, &ns);
+ krb5_free_data_contents(ctx->k5_context, &t);
+
+ *minor_status = (OM_uint32)code;
+ return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
diff --git a/src/lib/gssapi/krb5/process_context_token.c b/src/lib/gssapi/krb5/process_context_token.c
new file mode 100644
index 000000000000..a672f48c859b
--- /dev/null
+++ b/src/lib/gssapi/krb5/process_context_token.c
@@ -0,0 +1,66 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_process_context_token(minor_status, context_handle,
+ token_buffer)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ gss_buffer_t token_buffer;
+{
+ krb5_gss_ctx_id_rec *ctx;
+ OM_uint32 majerr;
+
+ ctx = (krb5_gss_ctx_id_t) context_handle;
+
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return(GSS_S_NO_CONTEXT);
+ }
+
+ /* We only support context deletion tokens for now, and RFC 4121 does not
+ * define a context deletion token. */
+ if (ctx->proto) {
+ *minor_status = 0;
+ return(GSS_S_DEFECTIVE_TOKEN);
+ }
+
+ /* "unseal" the token */
+
+ if (GSS_ERROR(majerr = kg_unseal(minor_status, context_handle,
+ token_buffer,
+ GSS_C_NO_BUFFER, NULL, NULL,
+ KG_TOK_DEL_CTX)))
+ return(majerr);
+
+ /* Mark the context as terminated, but do not delete it (as that would
+ * leave the caller with a dangling context handle). */
+ ctx->terminated = 1;
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/rel_cred.c b/src/lib/gssapi/krb5/rel_cred.c
new file mode 100644
index 000000000000..8db745086009
--- /dev/null
+++ b/src/lib/gssapi/krb5/rel_cred.c
@@ -0,0 +1,101 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_release_cred(minor_status, cred_handle)
+ OM_uint32 *minor_status;
+ gss_cred_id_t *cred_handle;
+{
+ krb5_context context;
+ krb5_gss_cred_id_t cred;
+ krb5_error_code code1, code2, code3;
+
+ code1 = krb5_gss_init_context(&context);
+ if (code1) {
+ *minor_status = code1;
+ return GSS_S_FAILURE;
+ }
+
+ if (*cred_handle == GSS_C_NO_CREDENTIAL) {
+ *minor_status = 0;
+ krb5_free_context(context);
+ return(GSS_S_COMPLETE);
+ }
+
+ cred = (krb5_gss_cred_id_t)*cred_handle;
+
+ k5_mutex_destroy(&cred->lock);
+ /* ignore error destroying mutex */
+
+ if (cred->ccache) {
+ if (cred->destroy_ccache)
+ code1 = krb5_cc_destroy(context, cred->ccache);
+ else
+ code1 = krb5_cc_close(context, cred->ccache);
+ } else
+ code1 = 0;
+
+ if (cred->client_keytab)
+ krb5_kt_close(context, cred->client_keytab);
+
+#ifndef LEAN_CLIENT
+ if (cred->keytab)
+ code2 = krb5_kt_close(context, cred->keytab);
+ else
+#endif /* LEAN_CLIENT */
+ code2 = 0;
+
+ if (cred->rcache)
+ code3 = krb5_rc_close(context, cred->rcache);
+ else
+ code3 = 0;
+ if (cred->name)
+ kg_release_name(context, &cred->name);
+
+ krb5_free_principal(context, cred->impersonator);
+
+ if (cred->req_enctypes)
+ free(cred->req_enctypes);
+
+ if (cred->password != NULL)
+ zapfree(cred->password, strlen(cred->password));
+
+ xfree(cred);
+
+ *cred_handle = NULL;
+
+ *minor_status = 0;
+ if (code1)
+ *minor_status = code1;
+ if (code2)
+ *minor_status = code2;
+ if (code3)
+ *minor_status = code3;
+
+ if (*minor_status)
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return(*minor_status?GSS_S_FAILURE:GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/rel_name.c b/src/lib/gssapi/krb5/rel_name.c
new file mode 100644
index 000000000000..3dabe32f3342
--- /dev/null
+++ b/src/lib/gssapi/krb5/rel_name.c
@@ -0,0 +1,47 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_release_name(minor_status, input_name)
+ OM_uint32 *minor_status;
+ gss_name_t *input_name;
+{
+ krb5_context context;
+ krb5_error_code code;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ kg_release_name(context, (krb5_gss_name_t *)input_name);
+ krb5_free_context(context);
+
+ *input_name = (gss_name_t) NULL;
+
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}
diff --git a/src/lib/gssapi/krb5/rel_oid.c b/src/lib/gssapi/krb5/rel_oid.c
new file mode 100644
index 000000000000..739efe4680b7
--- /dev/null
+++ b/src/lib/gssapi/krb5/rel_oid.c
@@ -0,0 +1,78 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/rel_oid.c - Release an OID */
+/*
+ * Copyright 1995, 2007 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32
+krb5_gss_release_oid(minor_status, oid)
+ OM_uint32 *minor_status;
+ gss_OID *oid;
+{
+ /*
+ * The V2 API says the following!
+ *
+ * gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
+ * and will silently ignore attempts to free these OIDs; for other OIDs
+ * it will call the C free() routine for both the OID data and the
+ * descriptor. This allows applications to freely mix their own heap-
+ * allocated OID values with OIDs returned by GSS-API.
+ */
+ if (krb5_gss_internal_release_oid(minor_status, oid) != GSS_S_COMPLETE) {
+ /* Pawn it off on the generic routine */
+ return(generic_gss_release_oid(minor_status, oid));
+ }
+ else {
+ *oid = GSS_C_NO_OID;
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+ }
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_internal_release_oid(minor_status, oid)
+ OM_uint32 *minor_status;
+ gss_OID *oid;
+{
+ /*
+ * This function only knows how to release internal OIDs. It will
+ * return GSS_S_CONTINUE_NEEDED for any OIDs it does not recognize.
+ */
+
+ *minor_status = 0;
+ if ((*oid != gss_mech_krb5) &&
+ (*oid != gss_mech_krb5_old) &&
+ (*oid != gss_mech_krb5_wrong) &&
+ (*oid != gss_mech_iakerb) &&
+ (*oid != gss_nt_krb5_name) &&
+ (*oid != gss_nt_krb5_principal)) {
+ /* We don't know about this OID */
+ return(GSS_S_CONTINUE_NEEDED);
+ }
+ else {
+ *oid = GSS_C_NO_OID;
+ return(GSS_S_COMPLETE);
+ }
+}
diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c
new file mode 100644
index 000000000000..ff1c310bce5e
--- /dev/null
+++ b/src/lib/gssapi/krb5/s4u_gss_glue.c
@@ -0,0 +1,308 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <assert.h>
+
+static int
+kg_is_initiator_cred(krb5_gss_cred_id_t cred)
+{
+ return (cred->usage == GSS_C_INITIATE || cred->usage == GSS_C_BOTH) &&
+ (cred->ccache != NULL);
+}
+
+static OM_uint32
+kg_impersonate_name(OM_uint32 *minor_status,
+ const krb5_gss_cred_id_t impersonator_cred,
+ const krb5_gss_name_t user,
+ OM_uint32 time_req,
+ krb5_gss_cred_id_t *output_cred,
+ OM_uint32 *time_rec,
+ krb5_context context)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_creds in_creds, *out_creds = NULL;
+
+ *output_cred = NULL;
+ memset(&in_creds, 0, sizeof(in_creds));
+
+ in_creds.client = user->princ;
+ in_creds.server = impersonator_cred->name->princ;
+
+ if (impersonator_cred->req_enctypes != NULL)
+ in_creds.keyblock.enctype = impersonator_cred->req_enctypes[0];
+
+ k5_mutex_lock(&user->lock);
+
+ if (user->ad_context != NULL) {
+ code = krb5_authdata_export_authdata(context,
+ user->ad_context,
+ AD_USAGE_TGS_REQ,
+ &in_creds.authdata);
+ if (code != 0) {
+ k5_mutex_unlock(&user->lock);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ k5_mutex_unlock(&user->lock);
+
+ code = krb5_get_credentials_for_user(context,
+ KRB5_GC_CANONICALIZE | KRB5_GC_NO_STORE,
+ impersonator_cred->ccache,
+ &in_creds,
+ NULL, &out_creds);
+ if (code != 0) {
+ krb5_free_authdata(context, in_creds.authdata);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = kg_compose_deleg_cred(minor_status,
+ impersonator_cred,
+ out_creds,
+ time_req,
+ output_cred,
+ time_rec,
+ context);
+
+ krb5_free_authdata(context, in_creds.authdata);
+ krb5_free_creds(context, out_creds);
+
+ return major_status;
+}
+
+/* The mechglue always passes null desired_mechs and actual_mechs. */
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_gss_cred_id_t imp_cred = (krb5_gss_cred_id_t)impersonator_cred_handle;
+ krb5_gss_cred_id_t cred;
+ krb5_context context;
+
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (desired_name == GSS_C_NO_NAME)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (output_cred_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (cred_usage != GSS_C_INITIATE) {
+ *minor_status = (OM_uint32)G_BAD_USAGE;
+ return GSS_S_FAILURE;
+ }
+
+ if (imp_cred->usage != GSS_C_INITIATE && imp_cred->usage != GSS_C_BOTH) {
+ *minor_status = 0;
+ return GSS_S_NO_CRED;
+ }
+
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+ if (time_rec != NULL)
+ *time_rec = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = kg_cred_resolve(minor_status, context,
+ impersonator_cred_handle, NULL);
+ if (GSS_ERROR(major_status)) {
+ krb5_free_context(context);
+ return major_status;
+ }
+
+ major_status = kg_impersonate_name(minor_status,
+ imp_cred,
+ (krb5_gss_name_t)desired_name,
+ time_req,
+ &cred,
+ time_rec,
+ context);
+
+ if (!GSS_ERROR(major_status))
+ *output_cred_handle = (gss_cred_id_t)cred;
+
+ k5_mutex_unlock(&imp_cred->lock);
+ krb5_free_context(context);
+
+ return major_status;
+
+}
+
+/*
+ * Set up cred to be an S4U2Proxy credential by copying in the impersonator's
+ * creds, setting a cache config variable with the impersonator principal name,
+ * and saving the impersonator principal name in the cred structure.
+ */
+static krb5_error_code
+make_proxy_cred(krb5_context context, krb5_gss_cred_id_t cred,
+ krb5_gss_cred_id_t impersonator_cred)
+{
+ krb5_error_code code;
+ krb5_data data;
+ char *str;
+
+ code = krb5_cc_copy_creds(context, impersonator_cred->ccache,
+ cred->ccache);
+ if (code)
+ return code;
+
+ code = krb5_unparse_name(context, impersonator_cred->name->princ, &str);
+ if (code)
+ return code;
+
+ data = string2data(str);
+ code = krb5_cc_set_config(context, cred->ccache, NULL,
+ KRB5_CC_CONF_PROXY_IMPERSONATOR, &data);
+ krb5_free_unparsed_name(context, str);
+ if (code)
+ return code;
+
+ return krb5_copy_principal(context, impersonator_cred->name->princ,
+ &cred->impersonator);
+}
+
+OM_uint32
+kg_compose_deleg_cred(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t impersonator_cred,
+ krb5_creds *subject_creds,
+ OM_uint32 time_req,
+ krb5_gss_cred_id_t *output_cred,
+ OM_uint32 *time_rec,
+ krb5_context context)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_gss_cred_id_t cred = NULL;
+
+ *output_cred = NULL;
+ k5_mutex_assert_locked(&impersonator_cred->lock);
+
+ if (!kg_is_initiator_cred(impersonator_cred) ||
+ impersonator_cred->name == NULL ||
+ impersonator_cred->impersonator != NULL) {
+ code = G_BAD_USAGE;
+ goto cleanup;
+ }
+
+ assert(impersonator_cred->name->princ != NULL);
+
+ assert(subject_creds != NULL);
+ assert(subject_creds->client != NULL);
+
+ cred = xmalloc(sizeof(*cred));
+ if (cred == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ memset(cred, 0, sizeof(*cred));
+
+ code = k5_mutex_init(&cred->lock);
+ if (code != 0)
+ goto cleanup;
+
+ cred->usage = GSS_C_INITIATE;
+
+ cred->expire = subject_creds->times.endtime;
+
+ code = kg_init_name(context, subject_creds->client, NULL, NULL, NULL, 0,
+ &cred->name);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_cc_new_unique(context, "MEMORY", NULL, &cred->ccache);
+ if (code != 0)
+ goto cleanup;
+ cred->destroy_ccache = 1;
+
+ code = krb5_cc_initialize(context, cred->ccache, subject_creds->client);
+ if (code != 0)
+ goto cleanup;
+
+ /*
+ * Only return a "proxy" credential for use with constrained
+ * delegation if the subject credentials are forwardable.
+ * Submitting non-forwardable credentials to the KDC for use
+ * with constrained delegation will only return an error.
+ */
+ if (subject_creds->ticket_flags & TKT_FLG_FORWARDABLE) {
+ code = make_proxy_cred(context, cred, impersonator_cred);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_cc_store_cred(context, cred->ccache, subject_creds);
+ if (code != 0)
+ goto cleanup;
+
+ if (time_rec != NULL) {
+ krb5_timestamp now;
+
+ code = krb5_timeofday(context, &now);
+ if (code != 0)
+ goto cleanup;
+
+ *time_rec = cred->expire - now;
+ }
+
+ major_status = GSS_S_COMPLETE;
+ *minor_status = 0;
+ *output_cred = cred;
+
+cleanup:
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ }
+
+ if (GSS_ERROR(major_status) && cred != NULL) {
+ k5_mutex_destroy(&cred->lock);
+ krb5_cc_destroy(context, cred->ccache);
+ kg_release_name(context, &cred->name);
+ xfree(cred);
+ }
+
+ return major_status;
+}
diff --git a/src/lib/gssapi/krb5/ser_sctx.c b/src/lib/gssapi/krb5/ser_sctx.c
new file mode 100644
index 000000000000..79c4c710e6d4
--- /dev/null
+++ b/src/lib/gssapi/krb5/ser_sctx.c
@@ -0,0 +1,798 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/ser_sctx.c - [De]serialization of security context */
+/*
+ * Copyright 1995, 2004, 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+/*
+ * This module contains routines to [de]serialize
+ * krb5_gss_enc_desc and krb5_gss_ctx_id_t.
+ * XXX This whole serialization abstraction is unnecessary in a
+ * non-messaging environment, which krb5 is. Someday, this should
+ * all get redone without the extra level of indirection. I've done
+ * some of this work here, since adding new serializers is an internal
+ * krb5 interface, and I won't use those. There is some more
+ * deobfuscation (no longer anonymizing pointers, mostly) which could
+ * still be done. --marc
+ */
+
+static krb5_error_code
+kg_oid_externalize(kcontext, arg, buffer, lenremain)
+ krb5_context kcontext;
+ krb5_pointer arg;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ gss_OID oid = (gss_OID) arg;
+ krb5_error_code err;
+
+ err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
+ if (err)
+ return err;
+ err = krb5_ser_pack_int32((krb5_int32) oid->length,
+ buffer, lenremain);
+ if (err)
+ return err;
+ err = krb5_ser_pack_bytes((krb5_octet *) oid->elements,
+ oid->length, buffer, lenremain);
+ if (err)
+ return err;
+ err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
+ return err;
+}
+
+static krb5_error_code
+kg_oid_internalize(kcontext, argp, buffer, lenremain)
+ krb5_context kcontext;
+ krb5_pointer *argp;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ gss_OID oid;
+ krb5_int32 ibuf;
+ krb5_octet *bp;
+ size_t remain;
+
+ bp = *buffer;
+ remain = *lenremain;
+
+ /* Read in and check our magic number */
+ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+ return (EINVAL);
+
+ if (ibuf != KV5M_GSS_OID)
+ return (EINVAL);
+
+ oid = (gss_OID) malloc(sizeof(gss_OID_desc));
+ if (oid == NULL)
+ return ENOMEM;
+ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
+ free(oid);
+ return EINVAL;
+ }
+ oid->length = ibuf;
+ oid->elements = malloc((size_t)ibuf);
+ if (oid->elements == 0) {
+ free(oid);
+ return ENOMEM;
+ }
+ if (krb5_ser_unpack_bytes((krb5_octet *) oid->elements,
+ oid->length, &bp, &remain)) {
+ free(oid->elements);
+ free(oid);
+ return EINVAL;
+ }
+
+ /* Read in and check our trailing magic number */
+ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
+ free(oid->elements);
+ free(oid);
+ return (EINVAL);
+ }
+
+ if (ibuf != KV5M_GSS_OID) {
+ free(oid->elements);
+ free(oid);
+ return (EINVAL);
+ }
+
+ *buffer = bp;
+ *lenremain = remain;
+ *argp = (krb5_pointer) oid;
+ return 0;
+}
+
+static krb5_error_code
+kg_oid_size(kcontext, arg, sizep)
+ krb5_context kcontext;
+ krb5_pointer arg;
+ size_t *sizep;
+{
+ krb5_error_code kret;
+ gss_OID oid;
+ size_t required;
+
+ kret = EINVAL;
+ if ((oid = (gss_OID) arg)) {
+ required = 2*sizeof(krb5_int32); /* For the header and trailer */
+ required += sizeof(krb5_int32);
+ required += oid->length;
+
+ kret = 0;
+
+ *sizep += required;
+ }
+
+ return(kret);
+}
+
+static krb5_error_code
+kg_seqstate_externalize(kcontext, arg, buffer, lenremain)
+ krb5_context kcontext;
+ g_seqnum_state arg;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ krb5_error_code err;
+ err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
+ if (err == 0)
+ err = g_seqstate_externalize(arg, buffer, lenremain);
+ if (err == 0)
+ err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
+ return err;
+}
+
+static krb5_error_code
+kg_seqstate_internalize(kcontext, argp, buffer, lenremain)
+ krb5_context kcontext;
+ g_seqnum_state *argp;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ krb5_int32 ibuf;
+ krb5_octet *bp;
+ size_t remain;
+ krb5_error_code err;
+
+ bp = *buffer;
+ remain = *lenremain;
+
+ /* Read in and check our magic number */
+ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+ return (EINVAL);
+
+ if (ibuf != KV5M_GSS_QUEUE)
+ return (EINVAL);
+
+ err = g_seqstate_internalize(argp, &bp, &remain);
+ if (err)
+ return err;
+
+ /* Read in and check our trailing magic number */
+ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
+ g_seqstate_free(*argp);
+ return (EINVAL);
+ }
+
+ if (ibuf != KV5M_GSS_QUEUE) {
+ g_seqstate_free(*argp);
+ return (EINVAL);
+ }
+
+ *buffer = bp;
+ *lenremain = remain;
+ return 0;
+}
+
+static krb5_error_code
+kg_seqstate_size(kcontext, arg, sizep)
+ krb5_context kcontext;
+ g_seqnum_state arg;
+ size_t *sizep;
+{
+ krb5_error_code kret;
+ size_t required;
+
+ kret = EINVAL;
+ if (arg) {
+ required = 2*sizeof(krb5_int32); /* For the header and trailer */
+ g_seqstate_size(arg, &required);
+
+ kret = 0;
+ *sizep += required;
+ }
+ return(kret);
+}
+
+/*
+ * Determine the size required for this krb5_gss_ctx_id_rec.
+ */
+krb5_error_code
+kg_ctx_size(kcontext, arg, sizep)
+ krb5_context kcontext;
+ krb5_pointer arg;
+ size_t *sizep;
+{
+ krb5_error_code kret;
+ krb5_gss_ctx_id_rec *ctx;
+ size_t required;
+
+ /*
+ * krb5_gss_ctx_id_rec requires:
+ * krb5_int32 for KG_CONTEXT
+ * krb5_int32 for initiate.
+ * krb5_int32 for established.
+ * krb5_int32 for have_acceptor_subkey.
+ * krb5_int32 for seed_init.
+ * krb5_int32 for gss_flags.
+ * sizeof(seed) for seed
+ * ... for here
+ * ... for there
+ * ... for subkey
+ * krb5_int32 for signalg.
+ * krb5_int32 for cksum_size.
+ * krb5_int32 for sealalg.
+ * ... for enc
+ * ... for seq
+ * krb5_int32 for authtime.
+ * krb5_int32 for starttime.
+ * krb5_int32 for endtime.
+ * krb5_int32 for renew_till.
+ * krb5_int32 for flags.
+ * int64_t for seq_send.
+ * int64_t for seq_recv.
+ * ... for seqstate
+ * ... for auth_context
+ * ... for mech_used
+ * krb5_int32 for proto
+ * krb5_int32 for cksumtype
+ * ... for acceptor_subkey
+ * krb5_int32 for acceptor_key_cksumtype
+ * krb5_int32 for cred_rcache
+ * krb5_int32 for number of elements in authdata array
+ * ... for authdata array
+ * krb5_int32 for trailer.
+ */
+ kret = EINVAL;
+ if ((ctx = (krb5_gss_ctx_id_rec *) arg)) {
+ required = 21*sizeof(krb5_int32);
+ required += 2*sizeof(int64_t);
+ required += sizeof(ctx->seed);
+
+ kret = 0;
+ if (!kret && ctx->here)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_PRINCIPAL,
+ (krb5_pointer) ctx->here->princ,
+ &required);
+
+ if (!kret && ctx->there)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_PRINCIPAL,
+ (krb5_pointer) ctx->there->princ,
+ &required);
+
+ if (!kret && ctx->subkey)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_KEYBLOCK,
+ (krb5_pointer) &ctx->subkey->keyblock,
+ &required);
+
+ if (!kret && ctx->enc)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_KEYBLOCK,
+ (krb5_pointer) &ctx->enc->keyblock,
+ &required);
+
+ if (!kret && ctx->seq)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_KEYBLOCK,
+ (krb5_pointer) &ctx->seq->keyblock,
+ &required);
+
+ if (!kret)
+ kret = kg_oid_size(kcontext,
+ (krb5_pointer) ctx->mech_used,
+ &required);
+
+ if (!kret && ctx->seqstate)
+ kret = kg_seqstate_size(kcontext, ctx->seqstate, &required);
+
+ if (!kret)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_CONTEXT,
+ (krb5_pointer) ctx->k5_context,
+ &required);
+ if (!kret)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_AUTH_CONTEXT,
+ (krb5_pointer) ctx->auth_context,
+ &required);
+ if (!kret && ctx->acceptor_subkey)
+ kret = krb5_size_opaque(kcontext,
+ KV5M_KEYBLOCK, (krb5_pointer)
+ &ctx->acceptor_subkey->keyblock,
+ &required);
+ if (!kret && ctx->authdata) {
+ krb5_int32 i;
+
+ for (i = 0; !kret && ctx->authdata[i]; i++) {
+ kret = krb5_size_opaque(kcontext,
+ KV5M_AUTHDATA,
+ (krb5_pointer)ctx->authdata[i],
+ &required);
+ }
+ }
+ if (!kret) {
+ krb5_gss_name_t initiator_name;
+
+ initiator_name = ctx->initiate ? ctx->here : ctx->there;
+
+ if (initiator_name && initiator_name->ad_context) {
+ kret = krb5_size_opaque(kcontext,
+ KV5M_AUTHDATA_CONTEXT,
+ initiator_name->ad_context,
+ &required);
+ }
+ }
+ *sizep += required;
+ }
+ return(kret);
+}
+
+/*
+ * Externalize this krb5_gss_ctx_id_ret.
+ */
+krb5_error_code
+kg_ctx_externalize(kcontext, arg, buffer, lenremain)
+ krb5_context kcontext;
+ krb5_pointer arg;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ krb5_error_code kret;
+ krb5_gss_ctx_id_rec *ctx;
+ size_t required;
+ krb5_octet *bp;
+ size_t remain;
+ krb5int_access kaccess;
+
+ kret = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+ if (kret)
+ return(kret);
+
+ required = 0;
+ bp = *buffer;
+ remain = *lenremain;
+ kret = EINVAL;
+ if ((ctx = (krb5_gss_ctx_id_rec *) arg)) {
+ kret = ENOMEM;
+ if (!kg_ctx_size(kcontext, arg, &required) &&
+ (required <= remain)) {
+ /* Our identifier */
+ (void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
+
+ /* Now static data */
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->initiate,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->established,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->have_acceptor_subkey,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->seed_init,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->gss_flags,
+ &bp, &remain);
+ (void) krb5_ser_pack_bytes((krb5_octet *) ctx->seed,
+ sizeof(ctx->seed),
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->signalg,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->cksum_size,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->sealalg,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.authtime,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.starttime,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.endtime,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_times.renew_till,
+ &bp, &remain);
+ (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_flags,
+ &bp, &remain);
+ (void) (*kaccess.ser_pack_int64)((int64_t) ctx->seq_send,
+ &bp, &remain);
+ (void) (*kaccess.ser_pack_int64)((int64_t) ctx->seq_recv,
+ &bp, &remain);
+
+ /* Now dynamic data */
+ kret = 0;
+
+ if (!kret && ctx->mech_used)
+ kret = kg_oid_externalize(kcontext, ctx->mech_used,
+ &bp, &remain);
+
+ if (!kret && ctx->here)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_PRINCIPAL,
+ (krb5_pointer) ctx->here->princ,
+ &bp, &remain);
+
+ if (!kret && ctx->there)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_PRINCIPAL,
+ (krb5_pointer) ctx->there->princ,
+ &bp, &remain);
+
+ if (!kret && ctx->subkey)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_KEYBLOCK, (krb5_pointer)
+ &ctx->subkey->keyblock,
+ &bp, &remain);
+
+ if (!kret && ctx->enc)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_KEYBLOCK, (krb5_pointer)
+ &ctx->enc->keyblock,
+ &bp, &remain);
+
+ if (!kret && ctx->seq)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_KEYBLOCK, (krb5_pointer)
+ &ctx->seq->keyblock,
+ &bp, &remain);
+
+ if (!kret && ctx->seqstate)
+ kret = kg_seqstate_externalize(kcontext,
+ ctx->seqstate, &bp, &remain);
+
+ if (!kret)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_CONTEXT,
+ (krb5_pointer) ctx->k5_context,
+ &bp, &remain);
+
+ if (!kret)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_AUTH_CONTEXT,
+ (krb5_pointer) ctx->auth_context,
+ &bp, &remain);
+
+ if (!kret)
+ kret = krb5_ser_pack_int32((krb5_int32) ctx->proto,
+ &bp, &remain);
+ if (!kret)
+ kret = krb5_ser_pack_int32((krb5_int32) ctx->cksumtype,
+ &bp, &remain);
+ if (!kret && ctx->acceptor_subkey)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_KEYBLOCK, (krb5_pointer)
+ &ctx->acceptor_subkey->keyblock,
+ &bp, &remain);
+ if (!kret)
+ kret = krb5_ser_pack_int32((krb5_int32) ctx->acceptor_subkey_cksumtype,
+ &bp, &remain);
+
+ if (!kret)
+ kret = krb5_ser_pack_int32((krb5_int32) ctx->cred_rcache,
+ &bp, &remain);
+ if (!kret) {
+ krb5_int32 i = 0;
+
+ if (ctx->authdata) {
+ for (; ctx->authdata[i]; i++)
+ ;
+ }
+ /* authdata count */
+ kret = krb5_ser_pack_int32(i, &bp, &remain);
+ if (!kret && ctx->authdata) {
+ /* authdata */
+ for (i = 0; !kret && ctx->authdata[i]; i++)
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_AUTHDATA,
+ ctx->authdata[i],
+ &bp,
+ &remain);
+ }
+ }
+ /* authdata context */
+ if (!kret) {
+ krb5_gss_name_t initiator_name;
+
+ initiator_name = ctx->initiate ? ctx->here : ctx->there;
+
+ if (initiator_name && initiator_name->ad_context) {
+ kret = krb5_externalize_opaque(kcontext,
+ KV5M_AUTHDATA_CONTEXT,
+ initiator_name->ad_context,
+ &bp,
+ &remain);
+ }
+ }
+ /* trailer */
+ if (!kret)
+ kret = krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
+ if (!kret) {
+ *buffer = bp;
+ *lenremain = remain;
+ }
+ }
+ }
+ return(kret);
+}
+
+/* Internalize a keyblock and convert it to a key. */
+static krb5_error_code
+intern_key(krb5_context ctx, krb5_key *key, krb5_octet **bp, size_t *sp)
+{
+ krb5_keyblock *keyblock;
+ krb5_error_code ret;
+
+ ret = krb5_internalize_opaque(ctx, KV5M_KEYBLOCK,
+ (krb5_pointer *) &keyblock, bp, sp);
+ if (ret != 0)
+ return ret;
+ ret = krb5_k_create_key(ctx, keyblock, key);
+ krb5_free_keyblock(ctx, keyblock);
+ return ret;
+}
+
+/*
+ * Internalize this krb5_gss_ctx_id_t.
+ */
+krb5_error_code
+kg_ctx_internalize(kcontext, argp, buffer, lenremain)
+ krb5_context kcontext;
+ krb5_pointer *argp;
+ krb5_octet **buffer;
+ size_t *lenremain;
+{
+ krb5_error_code kret;
+ krb5_gss_ctx_id_rec *ctx;
+ krb5_int32 ibuf;
+ krb5_octet *bp;
+ size_t remain;
+ krb5int_access kaccess;
+ krb5_principal princ;
+
+ kret = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+ if (kret)
+ return(kret);
+
+ bp = *buffer;
+ remain = *lenremain;
+ kret = EINVAL;
+ princ = NULL;
+ /* Read our magic number */
+ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+ ibuf = 0;
+ if (ibuf == KG_CONTEXT) {
+ kret = ENOMEM;
+
+ /* Get a context */
+ if ((remain >= (17*sizeof(krb5_int32)
+ + 2*sizeof(int64_t)
+ + sizeof(ctx->seed))) &&
+ (ctx = (krb5_gss_ctx_id_rec *)
+ xmalloc(sizeof(krb5_gss_ctx_id_rec)))) {
+ memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+
+ ctx->magic = ibuf;
+ ctx->k5_context = kcontext;
+
+ /* Get static data */
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->initiate = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->established = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->have_acceptor_subkey = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->seed_init = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->gss_flags = (int) ibuf;
+ (void) krb5_ser_unpack_bytes((krb5_octet *) ctx->seed,
+ sizeof(ctx->seed),
+ &bp, &remain);
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->signalg = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->cksum_size = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->sealalg = (int) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->krb_times.authtime = (krb5_timestamp) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->krb_times.starttime = (krb5_timestamp) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->krb_times.endtime = (krb5_timestamp) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->krb_times.renew_till = (krb5_timestamp) ibuf;
+ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->krb_flags = (krb5_flags) ibuf;
+ (void) (*kaccess.ser_unpack_int64)((int64_t *)&ctx->seq_send,
+ &bp, &remain);
+ kret = (*kaccess.ser_unpack_int64)((int64_t *)&ctx->seq_recv,
+ &bp, &remain);
+ if (kret) {
+ free(ctx);
+ return kret;
+ }
+
+ {
+ krb5_pointer tmp;
+ kret = kg_oid_internalize(kcontext, &tmp, &bp,
+ &remain);
+ if (kret == 0)
+ ctx->mech_used = tmp;
+ else if (kret == EINVAL)
+ kret = 0;
+ }
+ /* Now get substructure data */
+ kret = krb5_internalize_opaque(kcontext,
+ KV5M_PRINCIPAL,
+ (krb5_pointer *) &princ,
+ &bp, &remain);
+ if (kret == 0) {
+ kret = kg_init_name(kcontext, princ, NULL, NULL, NULL,
+ KG_INIT_NAME_NO_COPY, &ctx->here);
+ if (kret)
+ krb5_free_principal(kcontext, princ);
+ } else if (kret == EINVAL)
+ kret = 0;
+ if (!kret) {
+ kret = krb5_internalize_opaque(kcontext,
+ KV5M_PRINCIPAL,
+ (krb5_pointer *) &princ,
+ &bp, &remain);
+ if (kret == 0) {
+ kret = kg_init_name(kcontext, princ, NULL, NULL, NULL,
+ KG_INIT_NAME_NO_COPY, &ctx->there);
+ if (kret)
+ krb5_free_principal(kcontext, princ);
+ } else if (kret == EINVAL)
+ kret = 0;
+ }
+ if (!kret &&
+ (kret = intern_key(kcontext, &ctx->subkey, &bp, &remain))) {
+ if (kret == EINVAL)
+ kret = 0;
+ }
+ if (!kret &&
+ (kret = intern_key(kcontext, &ctx->enc, &bp, &remain))) {
+ if (kret == EINVAL)
+ kret = 0;
+ }
+ if (!kret &&
+ (kret = intern_key(kcontext, &ctx->seq, &bp, &remain))) {
+ if (kret == EINVAL)
+ kret = 0;
+ }
+
+ if (!kret) {
+ kret = kg_seqstate_internalize(kcontext, &ctx->seqstate,
+ &bp, &remain);
+ if (kret == EINVAL)
+ kret = 0;
+ }
+
+ if (!kret)
+ kret = krb5_internalize_opaque(kcontext,
+ KV5M_CONTEXT,
+ (krb5_pointer *) &ctx->k5_context,
+ &bp, &remain);
+
+ if (!kret)
+ kret = krb5_internalize_opaque(kcontext,
+ KV5M_AUTH_CONTEXT,
+ (krb5_pointer *) &ctx->auth_context,
+ &bp, &remain);
+
+ if (!kret)
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->proto = ibuf;
+ if (!kret)
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->cksumtype = ibuf;
+ if (!kret &&
+ (kret = intern_key(kcontext, &ctx->acceptor_subkey,
+ &bp, &remain))) {
+ if (kret == EINVAL)
+ kret = 0;
+ }
+ if (!kret)
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->acceptor_subkey_cksumtype = ibuf;
+ if (!kret)
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ ctx->cred_rcache = ibuf;
+ /* authdata */
+ if (!kret)
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ if (!kret) {
+ krb5_int32 nadata = ibuf, i;
+
+ if (nadata > 0) {
+ ctx->authdata = (krb5_authdata **)calloc((size_t)nadata + 1,
+ sizeof(krb5_authdata *));
+ if (ctx->authdata == NULL) {
+ kret = ENOMEM;
+ } else {
+ for (i = 0; !kret && i < nadata; i++)
+ kret = krb5_internalize_opaque(kcontext,
+ KV5M_AUTHDATA,
+ (krb5_pointer *)&ctx->authdata[i],
+ &bp,
+ &remain);
+ }
+ }
+ }
+ /* authdata context */
+ if (!kret) {
+ krb5_gss_name_t initiator_name;
+
+ initiator_name = ctx->initiate ? ctx->here : ctx->there;
+ if (initiator_name == NULL) {
+ kret = EINVAL;
+ } else {
+ kret = krb5_internalize_opaque(kcontext,
+ KV5M_AUTHDATA_CONTEXT,
+ (krb5_pointer *)&initiator_name->ad_context,
+ &bp,
+ &remain);
+ if (kret == EINVAL)
+ kret = 0;
+ }
+ }
+ /* Get trailer */
+ if (!kret)
+ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+ if (!kret && ibuf != KG_CONTEXT)
+ kret = EINVAL;
+
+ if (!kret) {
+ *buffer = bp;
+ *lenremain = remain;
+ *argp = (krb5_pointer) ctx;
+ } else {
+ if (ctx->seq)
+ krb5_k_free_key(kcontext, ctx->seq);
+ if (ctx->enc)
+ krb5_k_free_key(kcontext, ctx->enc);
+ if (ctx->subkey)
+ krb5_k_free_key(kcontext, ctx->subkey);
+ if (ctx->there)
+ kg_release_name(kcontext, &ctx->there);
+ if (ctx->here)
+ kg_release_name(kcontext, &ctx->here);
+ xfree(ctx);
+ }
+ }
+ }
+ return(kret);
+}
diff --git a/src/lib/gssapi/krb5/set_allowable_enctypes.c b/src/lib/gssapi/krb5/set_allowable_enctypes.c
new file mode 100644
index 000000000000..d9fd279ed234
--- /dev/null
+++ b/src/lib/gssapi/krb5/set_allowable_enctypes.c
@@ -0,0 +1,123 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/set_allowable_enctypes.c */
+/*
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * krb5_gss_set_allowable_enctypes()
+ */
+
+/*
+ * gss_krb5_set_allowable_enctypes
+ *
+ * This function may be called by a context initiator after calling
+ * gss_acquire_cred(), but before calling gss_init_sec_context(),
+ * to restrict the set of enctypes which will be negotiated during
+ * context establishment to those in the provided array.
+ *
+ * 'cred_handle' must be a valid credential handle obtained via
+ * gss_acquire_cred(). It may not be GSS_C_NO_CREDENTIAL.
+ * gss_acquire_cred() may be called with GSS_C_NO_CREDENTIAL
+ * to get a handle to the default credential.
+ *
+ * The purpose of this function is to limit the keys that may
+ * be exported via gss_krb5_export_lucid_sec_context(); thus it
+ * should limit the enctypes of all keys that will be needed
+ * after the security context has been established.
+ * (i.e. context establishment may use a session key with a
+ * stronger enctype than in the provided array, however a
+ * subkey must be established within the enctype limits
+ * established by this function.)
+ *
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "gssapi_krb5.h"
+
+OM_uint32
+gss_krb5int_set_allowable_enctypes(OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle,
+ const gss_OID desired_oid,
+ const gss_buffer_t value)
+{
+ unsigned int i;
+ krb5_enctype * new_ktypes;
+ OM_uint32 major_status;
+ krb5_gss_cred_id_t cred;
+ krb5_error_code kerr = 0;
+ struct krb5_gss_set_allowable_enctypes_req *req;
+
+ /* Assume a failure */
+ *minor_status = 0;
+ major_status = GSS_S_FAILURE;
+
+ assert(value->length == sizeof(*req));
+ req = (struct krb5_gss_set_allowable_enctypes_req *)value->value;
+
+ /* verify and valildate cred handle */
+ cred = (krb5_gss_cred_id_t) *cred_handle;
+
+ if (req->ktypes) {
+ for (i = 0; i < req->num_ktypes && req->ktypes[i]; i++) {
+ if (!krb5_c_valid_enctype(req->ktypes[i])) {
+ kerr = KRB5_PROG_ETYPE_NOSUPP;
+ goto error_out;
+ }
+ }
+ } else {
+ k5_mutex_lock(&cred->lock);
+ if (cred->req_enctypes)
+ free(cred->req_enctypes);
+ cred->req_enctypes = NULL;
+ k5_mutex_unlock(&cred->lock);
+ return GSS_S_COMPLETE;
+ }
+
+ /* Copy the requested ktypes into the cred structure */
+ if ((new_ktypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * (i + 1)))) {
+ memcpy(new_ktypes, req->ktypes, sizeof(krb5_enctype) * i);
+ new_ktypes[i] = 0; /* "null-terminate" the list */
+ }
+ else {
+ kerr = ENOMEM;
+ goto error_out;
+ }
+ k5_mutex_lock(&cred->lock);
+ if (cred->req_enctypes)
+ free(cred->req_enctypes);
+ cred->req_enctypes = new_ktypes;
+ k5_mutex_unlock(&cred->lock);
+
+ /* Success! */
+ return GSS_S_COMPLETE;
+
+error_out:
+ *minor_status = kerr;
+ return(major_status);
+}
diff --git a/src/lib/gssapi/krb5/set_ccache.c b/src/lib/gssapi/krb5/set_ccache.c
new file mode 100644
index 000000000000..8acf3ec90cde
--- /dev/null
+++ b/src/lib/gssapi/krb5/set_ccache.c
@@ -0,0 +1,101 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/set_ccache.c */
+/*
+ * Copyright 1999, 2003 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * Set ccache name used by gssapi, and optionally obtain old ccache
+ * name. Caller should not free returned name.
+ */
+
+#include <string.h>
+#include "gssapiP_krb5.h"
+
+OM_uint32
+gss_krb5int_ccache_name(OM_uint32 *minor_status,
+ const gss_OID desired_mech,
+ const gss_OID desired_object,
+ const gss_buffer_t value)
+{
+ char *old_name = NULL;
+ OM_uint32 err = 0;
+ OM_uint32 minor = 0;
+ char *gss_out_name;
+ struct krb5_gss_ccache_name_req *req;
+
+ err = gss_krb5int_initialize_library();
+ if (err) {
+ *minor_status = err;
+ return GSS_S_FAILURE;
+ }
+
+ assert(value->length == sizeof(*req));
+
+ if (value->length != sizeof(*req))
+ return GSS_S_FAILURE;
+
+ req = (struct krb5_gss_ccache_name_req *)value->value;
+
+ gss_out_name = k5_getspecific(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME);
+
+ if (req->out_name) {
+ const char *tmp_name = NULL;
+
+ if (!err) {
+ kg_get_ccache_name (&err, &tmp_name);
+ }
+ if (!err) {
+ old_name = gss_out_name;
+ gss_out_name = (char *)tmp_name;
+ }
+ }
+ /* If out_name was NULL, we keep the same gss_out_name value, and
+ don't free up any storage (leave old_name NULL). */
+
+ if (!err)
+ kg_set_ccache_name (&err, req->name);
+
+ minor = k5_setspecific(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME, gss_out_name);
+ if (minor) {
+ /* Um. Now what? */
+ if (err == 0) {
+ err = minor;
+ }
+ free(gss_out_name);
+ gss_out_name = NULL;
+ }
+
+ if (!err) {
+ if (req->out_name) {
+ *(req->out_name) = gss_out_name;
+ }
+ }
+
+ if (old_name != NULL) {
+ free (old_name);
+ }
+
+ *minor_status = err;
+ return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
diff --git a/src/lib/gssapi/krb5/store_cred.c b/src/lib/gssapi/krb5/store_cred.c
new file mode 100644
index 000000000000..654d96541726
--- /dev/null
+++ b/src/lib/gssapi/krb5/store_cred.c
@@ -0,0 +1,234 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/krb5/store_cred.c */
+/*
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+static int
+has_unexpired_creds(krb5_gss_cred_id_t kcred,
+ const gss_OID desired_mech,
+ int default_cred,
+ gss_const_key_value_set_t cred_store)
+{
+ OM_uint32 major_status, minor;
+ gss_name_t cred_name;
+ gss_OID_set_desc desired_mechs;
+ gss_cred_id_t tmp_cred = GSS_C_NO_CREDENTIAL;
+ OM_uint32 time_rec;
+
+ desired_mechs.count = 1;
+ desired_mechs.elements = (gss_OID)desired_mech;
+
+ if (default_cred)
+ cred_name = GSS_C_NO_NAME;
+ else
+ cred_name = (gss_name_t)kcred->name;
+
+ major_status = krb5_gss_acquire_cred_from(&minor, cred_name, 0,
+ &desired_mechs, GSS_C_INITIATE,
+ cred_store, &tmp_cred, NULL,
+ &time_rec);
+
+ krb5_gss_release_cred(&minor, &tmp_cred);
+
+ return (GSS_ERROR(major_status) || time_rec);
+}
+
+static OM_uint32
+copy_initiator_creds(OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ const gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_const_key_value_set_t cred_store)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_gss_cred_id_t kcred = NULL;
+ krb5_context context = NULL;
+ krb5_ccache ccache = NULL;
+ const char *ccache_name;
+
+ *minor_status = 0;
+
+ if (!default_cred && cred_store == GSS_C_NO_CRED_STORE) {
+ *minor_status = G_STORE_NON_DEFAULT_CRED_NOSUPP;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ major_status = krb5_gss_validate_cred_1(minor_status,
+ input_cred_handle,
+ context);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ kcred = (krb5_gss_cred_id_t)input_cred_handle;
+
+ if (kcred->ccache == NULL) {
+ *minor_status = KG_CCACHE_NOMATCH;
+ major_status = GSS_S_DEFECTIVE_CREDENTIAL;
+ goto cleanup;
+ }
+
+ if (!overwrite_cred &&
+ has_unexpired_creds(kcred, desired_mech, default_cred, cred_store)) {
+ major_status = GSS_S_DUPLICATE_ELEMENT;
+ goto cleanup;
+ }
+
+ major_status = kg_value_from_cred_store(cred_store,
+ KRB5_CS_CCACHE_URN, &ccache_name);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ if (ccache_name != NULL) {
+ code = krb5_cc_resolve(context, ccache_name, &ccache);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_CRED_UNAVAIL;
+ goto cleanup;
+ }
+ code = krb5_cc_initialize(context, ccache,
+ kcred->name->princ);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_CRED_UNAVAIL;
+ goto cleanup;
+ }
+ }
+
+ if (ccache == NULL) {
+ if (!default_cred) {
+ *minor_status = G_STORE_NON_DEFAULT_CRED_NOSUPP;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ code = krb5int_cc_default(context, &ccache);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ }
+
+ code = krb5_cc_copy_creds(context, kcred->ccache, ccache);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ *minor_status = 0;
+ major_status = GSS_S_COMPLETE;
+
+cleanup:
+ if (kcred != NULL)
+ k5_mutex_unlock(&kcred->lock);
+ if (ccache != NULL)
+ krb5_cc_close(context, ccache);
+ krb5_free_context(context);
+
+ return major_status;
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_store_cred(OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ gss_cred_usage_t cred_usage,
+ const gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_OID_set *elements_stored,
+ gss_cred_usage_t *cred_usage_stored)
+{
+ return krb5_gss_store_cred_into(minor_status, input_cred_handle,
+ cred_usage, desired_mech,
+ overwrite_cred, default_cred,
+ GSS_C_NO_CRED_STORE,
+ elements_stored, cred_usage_stored);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_store_cred_into(OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ gss_cred_usage_t cred_usage,
+ const gss_OID desired_mech,
+ OM_uint32 overwrite_cred,
+ OM_uint32 default_cred,
+ gss_const_key_value_set_t cred_store,
+ gss_OID_set *elements_stored,
+ gss_cred_usage_t *cred_usage_stored)
+{
+ OM_uint32 major_status;
+ gss_cred_usage_t actual_usage;
+ OM_uint32 lifetime;
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL)
+ return GSS_S_NO_CRED;
+
+ major_status = GSS_S_FAILURE;
+
+ if (cred_usage == GSS_C_ACCEPT) {
+ *minor_status = G_STORE_ACCEPTOR_CRED_NOSUPP;
+ return GSS_S_FAILURE;
+ } else if (cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
+ *minor_status = G_BAD_USAGE;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = krb5_gss_inquire_cred(minor_status, input_cred_handle,
+ NULL, &lifetime,
+ &actual_usage, elements_stored);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+ if (lifetime == 0)
+ return GSS_S_CREDENTIALS_EXPIRED;
+
+ if (actual_usage != GSS_C_INITIATE && actual_usage != GSS_C_BOTH) {
+ *minor_status = G_STORE_ACCEPTOR_CRED_NOSUPP;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = copy_initiator_creds(minor_status, input_cred_handle,
+ desired_mech, overwrite_cred,
+ default_cred, cred_store);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+ if (cred_usage_stored != NULL)
+ *cred_usage_stored = GSS_C_INITIATE;
+
+ return GSS_S_COMPLETE;
+}
diff --git a/src/lib/gssapi/krb5/util_cksum.c b/src/lib/gssapi/krb5/util_cksum.c
new file mode 100644
index 000000000000..cfd585ec7219
--- /dev/null
+++ b/src/lib/gssapi/krb5/util_cksum.c
@@ -0,0 +1,295 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+/* Checksumming the channel bindings always uses plain MD5. */
+krb5_error_code
+kg_checksum_channel_bindings(context, cb, cksum)
+ krb5_context context;
+ gss_channel_bindings_t cb;
+ krb5_checksum *cksum;
+{
+ size_t len;
+ char *buf = 0;
+ char *ptr;
+ size_t sumlen;
+ krb5_data plaind;
+ krb5_error_code code;
+ void *temp;
+
+ /* initialize the the cksum */
+ code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen);
+ if (code)
+ return(code);
+
+ cksum->checksum_type = CKSUMTYPE_RSA_MD5;
+ cksum->length = sumlen;
+
+ /* generate a buffer full of zeros if no cb specified */
+
+ if (cb == GSS_C_NO_CHANNEL_BINDINGS) {
+ if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) {
+ return(ENOMEM);
+ }
+ memset(cksum->contents, '\0', cksum->length);
+ return(0);
+ }
+
+ /* create the buffer to checksum into */
+
+ len = (sizeof(krb5_int32)*5+
+ cb->initiator_address.length+
+ cb->acceptor_address.length+
+ cb->application_data.length);
+
+ if ((buf = (char *) xmalloc(len)) == NULL)
+ return(ENOMEM);
+
+ /* helper macros. This code currently depends on a long being 32
+ bits, and htonl dtrt. */
+
+ ptr = buf;
+
+ TWRITE_INT(ptr, cb->initiator_addrtype, 0);
+ TWRITE_BUF(ptr, cb->initiator_address, 0);
+ TWRITE_INT(ptr, cb->acceptor_addrtype, 0);
+ TWRITE_BUF(ptr, cb->acceptor_address, 0);
+ TWRITE_BUF(ptr, cb->application_data, 0);
+
+ /* checksum the data */
+
+ plaind.length = len;
+ plaind.data = buf;
+
+ code = krb5_c_make_checksum(context, CKSUMTYPE_RSA_MD5, 0, 0,
+ &plaind, cksum);
+ if (code)
+ goto cleanup;
+
+ if ((temp = xmalloc(cksum->length)) == NULL) {
+ krb5_free_checksum_contents(context, cksum);
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ memcpy(temp, cksum->contents, cksum->length);
+ krb5_free_checksum_contents(context, cksum);
+ cksum->contents = (krb5_octet *)temp;
+
+ /* success */
+cleanup:
+ if (buf)
+ xfree(buf);
+ return code;
+}
+
+krb5_error_code
+kg_make_checksum_iov_v1(krb5_context context,
+ krb5_cksumtype type,
+ size_t cksum_len,
+ krb5_key seq,
+ krb5_key enc,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype,
+ krb5_checksum *checksum)
+{
+ krb5_error_code code;
+ gss_iov_buffer_desc *header;
+ krb5_crypto_iov *kiov;
+ int i = 0, j;
+ size_t conf_len = 0, token_header_len;
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ assert(header != NULL);
+
+ kiov = calloc(iov_count + 3, sizeof(krb5_crypto_iov));
+ if (kiov == NULL)
+ return ENOMEM;
+
+ /* Checksum over ( Header | Confounder | Data | Pad ) */
+ if (toktype == KG_TOK_WRAP_MSG)
+ conf_len = kg_confounder_size(context, enc->keyblock.enctype);
+
+ /* Checksum output */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
+ kiov[i].data.length = checksum->length;
+ kiov[i].data.data = xmalloc(checksum->length);
+ if (kiov[i].data.data == NULL) {
+ xfree(kiov);
+ return ENOMEM;
+ }
+ i++;
+
+ /* Header | SND_SEQ | SGN_CKSUM | Confounder */
+ token_header_len = 16 + cksum_len + conf_len;
+
+ /* Header (calculate from end because of variable length ASN.1 header) */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ kiov[i].data.length = 8;
+ kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - token_header_len;
+ i++;
+
+ /* Confounder */
+ if (toktype == KG_TOK_WRAP_MSG) {
+ kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
+ kiov[i].data.length = conf_len;
+ kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - conf_len;
+ i++;
+ }
+
+ for (j = 0; j < iov_count; j++) {
+ kiov[i].flags = kg_translate_flag_iov(iov[j].type);
+ kiov[i].data.length = iov[j].buffer.length;
+ kiov[i].data.data = (char *)iov[j].buffer.value;
+ i++;
+ }
+
+ code = krb5_k_make_checksum_iov(context, type, seq, sign_usage, kiov, i);
+ if (code == 0) {
+ checksum->length = kiov[0].data.length;
+ checksum->contents = (unsigned char *)kiov[0].data.data;
+ } else
+ free(kiov[0].data.data);
+
+ xfree(kiov);
+
+ return code;
+}
+
+static krb5_error_code
+checksum_iov_v3(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_key key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype,
+ krb5_boolean verify,
+ krb5_boolean *valid)
+{
+ krb5_error_code code;
+ gss_iov_buffer_desc *header;
+ gss_iov_buffer_desc *trailer;
+ krb5_crypto_iov *kiov;
+ size_t kiov_count;
+ int i = 0, j;
+ unsigned int k5_checksumlen;
+
+ if (verify)
+ *valid = FALSE;
+
+ code = krb5_c_crypto_length(context, key->keyblock.enctype, KRB5_CRYPTO_TYPE_CHECKSUM, &k5_checksumlen);
+ if (code != 0)
+ return code;
+
+ header = kg_locate_header_iov(iov, iov_count, toktype);
+ assert(header != NULL);
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ assert(rrc != 0 || trailer != NULL);
+
+ if (trailer == NULL) {
+ if (rrc != k5_checksumlen)
+ return KRB5_BAD_MSIZE;
+ if (header->buffer.length != 16 + k5_checksumlen)
+ return KRB5_BAD_MSIZE;
+ } else if (trailer->buffer.length != k5_checksumlen)
+ return KRB5_BAD_MSIZE;
+
+ kiov_count = 2 + iov_count;
+ kiov = (krb5_crypto_iov *)xmalloc(kiov_count * sizeof(krb5_crypto_iov));
+ if (kiov == NULL)
+ return ENOMEM;
+
+ /* Checksum over ( Data | Header ) */
+
+ /* Data */
+ for (j = 0; j < iov_count; j++) {
+ kiov[i].flags = kg_translate_flag_iov(iov[j].type);
+ kiov[i].data.length = iov[j].buffer.length;
+ kiov[i].data.data = (char *)iov[j].buffer.value;
+ i++;
+ }
+
+ /* Header */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ kiov[i].data.length = 16;
+ kiov[i].data.data = (char *)header->buffer.value;
+ i++;
+
+ /* Checksum */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
+ if (trailer == NULL) {
+ kiov[i].data.length = header->buffer.length - 16;
+ kiov[i].data.data = (char *)header->buffer.value + 16;
+ } else {
+ kiov[i].data.length = trailer->buffer.length;
+ kiov[i].data.data = (char *)trailer->buffer.value;
+ }
+ i++;
+
+ if (verify)
+ code = krb5_k_verify_checksum_iov(context, type, key, sign_usage, kiov, kiov_count, valid);
+ else
+ code = krb5_k_make_checksum_iov(context, type, key, sign_usage, kiov, kiov_count);
+
+ xfree(kiov);
+
+ return code;
+}
+
+krb5_error_code
+kg_make_checksum_iov_v3(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_key key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype)
+{
+ return checksum_iov_v3(context, type, rrc, key,
+ sign_usage, iov, iov_count, toktype, 0, NULL);
+}
+
+krb5_error_code
+kg_verify_checksum_iov_v3(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_key key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int toktype,
+ krb5_boolean *valid)
+{
+ return checksum_iov_v3(context, type, rrc, key,
+ sign_usage, iov, iov_count, toktype, 1, valid);
+}
diff --git a/src/lib/gssapi/krb5/util_crypt.c b/src/lib/gssapi/krb5/util_crypt.c
new file mode 100644
index 000000000000..0cebde12a85c
--- /dev/null
+++ b/src/lib/gssapi/krb5/util_crypt.c
@@ -0,0 +1,782 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2001, 2008 by the Massachusetts Institute of Technology.
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+static krb5_error_code
+kg_copy_keys(krb5_context context, krb5_gss_ctx_id_rec *ctx, krb5_key subkey)
+{
+ krb5_error_code code;
+
+ krb5_k_free_key(context, ctx->enc);
+ ctx->enc = NULL;
+ code = krb5_k_create_key(context, &subkey->keyblock, &ctx->enc);
+ if (code != 0)
+ return code;
+
+ krb5_k_free_key(context, ctx->seq);
+ ctx->seq = NULL;
+ code = krb5_k_create_key(context, &subkey->keyblock, &ctx->seq);
+ if (code != 0)
+ return code;
+
+ return 0;
+}
+
+static krb5_error_code
+kg_derive_des_enc_key(krb5_context context, krb5_key subkey, krb5_key *out)
+{
+ krb5_error_code code;
+ krb5_keyblock *keyblock;
+ unsigned int i;
+
+ *out = NULL;
+
+ code = krb5_k_key_keyblock(context, subkey, &keyblock);
+ if (code != 0)
+ return code;
+
+ for (i = 0; i < keyblock->length; i++)
+ keyblock->contents[i] ^= 0xF0;
+
+ code = krb5_k_create_key(context, keyblock, out);
+ krb5_free_keyblock(context, keyblock);
+ return code;
+}
+
+krb5_error_code
+kg_setup_keys(krb5_context context, krb5_gss_ctx_id_rec *ctx, krb5_key subkey,
+ krb5_cksumtype *cksumtype)
+{
+ krb5_error_code code;
+
+ assert(ctx != NULL);
+ assert(subkey != NULL);
+
+ *cksumtype = 0;
+ ctx->proto = 0;
+
+ if (ctx->enc == NULL) {
+ ctx->signalg = -1;
+ ctx->sealalg = -1;
+ }
+
+ code = krb5int_c_mandatory_cksumtype(context, subkey->keyblock.enctype,
+ cksumtype);
+ if (code != 0)
+ return code;
+
+ switch (subkey->keyblock.enctype) {
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES_CBC_MD4:
+ case ENCTYPE_DES_CBC_CRC:
+ krb5_k_free_key(context, ctx->seq);
+ code = krb5_k_create_key(context, &subkey->keyblock, &ctx->seq);
+ if (code != 0)
+ return code;
+
+ krb5_k_free_key(context, ctx->enc);
+ code = kg_derive_des_enc_key(context, subkey, &ctx->enc);
+ if (code != 0)
+ return code;
+
+ ctx->enc->keyblock.enctype = ENCTYPE_DES_CBC_RAW;
+ ctx->seq->keyblock.enctype = ENCTYPE_DES_CBC_RAW;
+ ctx->signalg = SGN_ALG_DES_MAC_MD5;
+ ctx->cksum_size = 8;
+ ctx->sealalg = SEAL_ALG_DES;
+
+ break;
+ case ENCTYPE_DES3_CBC_SHA1:
+ code = kg_copy_keys(context, ctx, subkey);
+ if (code != 0)
+ return code;
+
+ ctx->enc->keyblock.enctype = ENCTYPE_DES3_CBC_RAW;
+ ctx->seq->keyblock.enctype = ENCTYPE_DES3_CBC_RAW;
+ ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
+ ctx->cksum_size = 20;
+ ctx->sealalg = SEAL_ALG_DES3KD;
+ break;
+ case ENCTYPE_ARCFOUR_HMAC:
+ case ENCTYPE_ARCFOUR_HMAC_EXP:
+ /* RFC 4121 accidentally omits RC4-HMAC-EXP as a "not-newer" enctype,
+ * even though RFC 4757 treats it as one. */
+ code = kg_copy_keys(context, ctx, subkey);
+ if (code != 0)
+ return code;
+
+ ctx->signalg = SGN_ALG_HMAC_MD5;
+ ctx->cksum_size = 8;
+ ctx->sealalg = SEAL_ALG_MICROSOFT_RC4;
+ break;
+ default:
+ ctx->proto = 1;
+ break;
+ }
+
+ return 0;
+}
+
+int
+kg_confounder_size(krb5_context context, krb5_enctype enctype)
+{
+ krb5_error_code code;
+ size_t blocksize;
+ /* We special case rc4*/
+ if (enctype == ENCTYPE_ARCFOUR_HMAC || enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
+ return 8;
+ code = krb5_c_block_size(context, enctype, &blocksize);
+ if (code)
+ return(-1); /* XXX */
+
+ return(blocksize);
+}
+
+krb5_error_code
+kg_make_confounder(krb5_context context, krb5_enctype enctype,
+ unsigned char *buf)
+{
+ int confsize;
+ krb5_data lrandom;
+
+ confsize = kg_confounder_size(context, enctype);
+ if (confsize < 0)
+ return KRB5_BAD_MSIZE;
+
+ lrandom.length = confsize;
+ lrandom.data = (char *)buf;
+
+ return(krb5_c_random_make_octets(context, &lrandom));
+}
+
+/* Set *data_out to a krb5_data structure containing iv, or to NULL if iv is
+ * NULL. */
+static krb5_error_code
+iv_to_state(krb5_context context, krb5_key key, krb5_pointer iv,
+ krb5_data **data_out)
+{
+ krb5_error_code code;
+ krb5_data *data;
+ size_t blocksize;
+
+ *data_out = NULL;
+ if (iv == NULL)
+ return 0;
+
+ code = krb5_c_block_size(context, key->keyblock.enctype, &blocksize);
+ if (code)
+ return code;
+
+ data = k5alloc(sizeof(*data), &code);
+ if (data == NULL)
+ return code;
+ code = alloc_data(data, blocksize);
+ if (code) {
+ free(data);
+ return code;
+ }
+ memcpy(data->data, iv, blocksize);
+ *data_out = data;
+ return 0;
+}
+
+krb5_error_code
+kg_encrypt(krb5_context context, krb5_key key, int usage, krb5_pointer iv,
+ krb5_const_pointer in, krb5_pointer out, unsigned int length)
+{
+ krb5_error_code code;
+ krb5_data *state, inputd;
+ krb5_enc_data outputd;
+
+ code = iv_to_state(context, key, iv, &state);
+ if (code)
+ return code;
+
+ inputd.length = length;
+ inputd.data = (char *)in;
+
+ outputd.ciphertext.length = length;
+ outputd.ciphertext.data = out;
+
+ code = krb5_k_encrypt(context, key, usage, state, &inputd, &outputd);
+ krb5_free_data(context, state);
+ return code;
+}
+
+krb5_error_code
+kg_encrypt_inplace(krb5_context context, krb5_key key, int usage,
+ krb5_pointer iv, krb5_pointer ptr, unsigned int length)
+{
+ krb5_error_code code;
+ krb5_crypto_iov iov;
+ krb5_data *state;
+
+ code = iv_to_state(context, key, iv, &state);
+ if (code)
+ return code;
+
+ iov.flags = KRB5_CRYPTO_TYPE_DATA;
+ iov.data = make_data((void *)ptr, length);
+ code = krb5_k_encrypt_iov(context, key, usage, state, &iov, 1);
+ krb5_free_data(context, state);
+ return code;
+}
+
+/* length is the length of the cleartext. */
+
+krb5_error_code
+kg_decrypt(krb5_context context, krb5_key key, int usage, krb5_pointer iv,
+ krb5_const_pointer in, krb5_pointer out, unsigned int length)
+{
+ krb5_error_code code;
+ krb5_data *state, outputd;
+ krb5_enc_data inputd;
+
+ code = iv_to_state(context, key, iv, &state);
+ if (code)
+ return code;
+
+ inputd.enctype = ENCTYPE_UNKNOWN;
+ inputd.ciphertext.length = length;
+ inputd.ciphertext.data = (char *)in;
+
+ outputd.length = length;
+ outputd.data = out;
+
+ code = krb5_k_decrypt(context, key, usage, state, &inputd, &outputd);
+ krb5_free_data(context, state);
+ return code;
+}
+
+krb5_error_code
+kg_arcfour_docrypt(const krb5_keyblock *keyblock, int usage,
+ const unsigned char *kd_data, size_t kd_data_len,
+ const unsigned char *input_buf, size_t input_len,
+ unsigned char *output_buf)
+{
+ krb5_data kd = make_data((char *) kd_data, kd_data_len);
+ krb5_crypto_iov kiov;
+
+ memcpy(output_buf, input_buf, input_len);
+ kiov.flags = KRB5_CRYPTO_TYPE_DATA;
+ kiov.data = make_data(output_buf, input_len);
+ return krb5int_arcfour_gsscrypt(keyblock, usage, &kd, &kiov, 1);
+}
+
+/* AEAD */
+static krb5_error_code
+kg_translate_iov_v1(krb5_context context, krb5_enctype enctype,
+ gss_iov_buffer_desc *iov, int iov_count,
+ krb5_crypto_iov **pkiov, size_t *pkiov_count)
+{
+ gss_iov_buffer_desc *header;
+ gss_iov_buffer_desc *trailer;
+ int i = 0, j;
+ size_t kiov_count;
+ krb5_crypto_iov *kiov;
+ size_t conf_len;
+
+ *pkiov = NULL;
+ *pkiov_count = 0;
+
+ conf_len = kg_confounder_size(context, enctype);
+
+ header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+ assert(header != NULL);
+
+ if (header->buffer.length < conf_len)
+ return KRB5_BAD_MSIZE;
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ assert(trailer == NULL || trailer->buffer.length == 0);
+
+ kiov_count = 3 + iov_count;
+ kiov = (krb5_crypto_iov *)malloc(kiov_count * sizeof(krb5_crypto_iov));
+ if (kiov == NULL)
+ return ENOMEM;
+
+ /* For pre-CFX (raw enctypes) there is no krb5 header */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER;
+ kiov[i].data.length = 0;
+ kiov[i].data.data = NULL;
+ i++;
+
+ /* For pre-CFX, the confounder is at the end of the GSS header */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
+ kiov[i].data.length = conf_len;
+ kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - conf_len;
+ i++;
+
+ for (j = 0; j < iov_count; j++) {
+ kiov[i].flags = kg_translate_flag_iov(iov[j].type);
+ if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY)
+ continue;
+
+ kiov[i].data.length = iov[j].buffer.length;
+ kiov[i].data.data = (char *)iov[j].buffer.value;
+ i++;
+ }
+
+ kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
+ kiov[i].data.length = 0;
+ kiov[i].data.data = NULL;
+ i++;
+
+ *pkiov = kiov;
+ *pkiov_count = i;
+
+ return 0;
+}
+
+/*
+ * DCE_STYLE indicates actual RRC is EC + RRC
+ * EC is extra rotate count for DCE_STYLE, pad length otherwise
+ * RRC is rotate count.
+ */
+static krb5_error_code
+kg_translate_iov_v3(krb5_context context, int dce_style, size_t ec, size_t rrc,
+ krb5_enctype enctype, gss_iov_buffer_desc *iov,
+ int iov_count, krb5_crypto_iov **pkiov,
+ size_t *pkiov_count)
+{
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t trailer;
+ int i = 0, j;
+ size_t kiov_count;
+ krb5_crypto_iov *kiov;
+ unsigned int k5_headerlen = 0, k5_trailerlen = 0;
+ size_t gss_headerlen, gss_trailerlen;
+ krb5_error_code code;
+
+ *pkiov = NULL;
+ *pkiov_count = 0;
+
+ header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+ assert(header != NULL);
+
+ trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+ assert(trailer == NULL || rrc == 0);
+
+ code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_HEADER,
+ &k5_headerlen);
+ if (code != 0)
+ return code;
+
+ code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_TRAILER,
+ &k5_trailerlen);
+ if (code != 0)
+ return code;
+
+ /* Check header and trailer sizes */
+ gss_headerlen = 16 /* GSS-Header */ + k5_headerlen; /* Kerb-Header */
+ gss_trailerlen = ec + 16 /* E(GSS-Header) */ + k5_trailerlen; /* Kerb-Trailer */
+
+ /* If we're caller without a trailer, we must rotate by trailer length */
+ if (trailer == NULL) {
+ size_t actual_rrc = rrc;
+
+ if (dce_style)
+ actual_rrc += ec; /* compensate for Windows bug */
+
+ if (actual_rrc != gss_trailerlen)
+ return KRB5_BAD_MSIZE;
+
+ gss_headerlen += gss_trailerlen;
+ gss_trailerlen = 0;
+ } else {
+ if (trailer->buffer.length != gss_trailerlen)
+ return KRB5_BAD_MSIZE;
+ }
+
+ if (header->buffer.length != gss_headerlen)
+ return KRB5_BAD_MSIZE;
+
+ kiov_count = 3 + iov_count;
+ kiov = (krb5_crypto_iov *)malloc(kiov_count * sizeof(krb5_crypto_iov));
+ if (kiov == NULL)
+ return ENOMEM;
+
+ /*
+ * The krb5 header is located at the end of the GSS header.
+ */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER;
+ kiov[i].data.length = k5_headerlen;
+ kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - k5_headerlen;
+ i++;
+
+ for (j = 0; j < iov_count; j++) {
+ kiov[i].flags = kg_translate_flag_iov(iov[j].type);
+ if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY)
+ continue;
+
+ kiov[i].data.length = iov[j].buffer.length;
+ kiov[i].data.data = (char *)iov[j].buffer.value;
+ i++;
+ }
+
+ /*
+ * The EC and encrypted GSS header are placed in the trailer, which may
+ * be rotated directly after the plaintext header if no trailer buffer
+ * is provided.
+ */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
+ kiov[i].data.length = ec + 16; /* E(Header) */
+ if (trailer == NULL)
+ kiov[i].data.data = (char *)header->buffer.value + 16;
+ else
+ kiov[i].data.data = (char *)trailer->buffer.value;
+ i++;
+
+ /*
+ * The krb5 trailer is placed after the encrypted copy of the
+ * krb5 header (which may be in the GSS header or trailer).
+ */
+ kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
+ kiov[i].data.length = k5_trailerlen;
+ kiov[i].data.data = kiov[i - 1].data.data + ec + 16; /* E(Header) */
+ i++;
+
+ *pkiov = kiov;
+ *pkiov_count = i;
+
+ return 0;
+}
+
+/* PROTO is 1 if CFX, 0 if pre-CFX */
+static krb5_error_code
+kg_translate_iov(krb5_context context, int proto, int dce_style, size_t ec,
+ size_t rrc, krb5_enctype enctype, gss_iov_buffer_desc *iov,
+ int iov_count, krb5_crypto_iov **pkiov, size_t *pkiov_count)
+{
+ return proto ?
+ kg_translate_iov_v3(context, dce_style, ec, rrc, enctype,
+ iov, iov_count, pkiov, pkiov_count) :
+ kg_translate_iov_v1(context, enctype, iov, iov_count,
+ pkiov, pkiov_count);
+}
+
+krb5_error_code
+kg_encrypt_iov(krb5_context context, int proto, int dce_style, size_t ec,
+ size_t rrc, krb5_key key, int usage, krb5_pointer iv,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ krb5_error_code code;
+ krb5_data *state;
+ size_t kiov_len;
+ krb5_crypto_iov *kiov;
+
+ code = iv_to_state(context, key, iv, &state);
+ if (code)
+ return code;
+
+ code = kg_translate_iov(context, proto, dce_style, ec, rrc,
+ key->keyblock.enctype, iov, iov_count,
+ &kiov, &kiov_len);
+ if (code == 0) {
+ code = krb5_k_encrypt_iov(context, key, usage, state, kiov, kiov_len);
+ free(kiov);
+ }
+
+ krb5_free_data(context, state);
+ return code;
+}
+
+/* length is the length of the cleartext. */
+
+krb5_error_code
+kg_decrypt_iov(krb5_context context, int proto, int dce_style, size_t ec,
+ size_t rrc, krb5_key key, int usage, krb5_pointer iv,
+ gss_iov_buffer_desc *iov, int iov_count)
+{
+ krb5_error_code code;
+ krb5_data *state;
+ size_t kiov_len;
+ krb5_crypto_iov *kiov;
+
+ code = iv_to_state(context, key, iv, &state);
+ if (code)
+ return code;
+
+ code = kg_translate_iov(context, proto, dce_style, ec, rrc,
+ key->keyblock.enctype, iov, iov_count,
+ &kiov, &kiov_len);
+ if (code == 0) {
+ code = krb5_k_decrypt_iov(context, key, usage, state, kiov, kiov_len);
+ free(kiov);
+ }
+
+ krb5_free_data(context, state);
+ return code;
+}
+
+krb5_error_code
+kg_arcfour_docrypt_iov(krb5_context context, const krb5_keyblock *keyblock,
+ int usage, const unsigned char *kd_data,
+ size_t kd_data_len, gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ krb5_error_code code;
+ krb5_data kd = make_data((char *) kd_data, kd_data_len);
+ krb5_crypto_iov *kiov = NULL;
+ size_t kiov_len = 0;
+
+ code = kg_translate_iov(context, 0 /* proto */, 0 /* dce_style */,
+ 0 /* ec */, 0 /* rrc */, keyblock->enctype,
+ iov, iov_count, &kiov, &kiov_len);
+ if (code)
+ return code;
+ code = krb5int_arcfour_gsscrypt(keyblock, usage, &kd, kiov, kiov_len);
+ free(kiov);
+ return code;
+}
+
+krb5_cryptotype
+kg_translate_flag_iov(OM_uint32 type)
+{
+ krb5_cryptotype ktype;
+
+ switch (GSS_IOV_BUFFER_TYPE(type)) {
+ case GSS_IOV_BUFFER_TYPE_DATA:
+ case GSS_IOV_BUFFER_TYPE_PADDING:
+ ktype = KRB5_CRYPTO_TYPE_DATA;
+ break;
+ case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
+ ktype = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ break;
+ default:
+ ktype = KRB5_CRYPTO_TYPE_EMPTY;
+ break;
+ }
+
+ return ktype;
+}
+
+gss_iov_buffer_t
+kg_locate_iov(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
+{
+ int i;
+ gss_iov_buffer_t p = GSS_C_NO_IOV_BUFFER;
+
+ if (iov == GSS_C_NO_IOV_BUFFER)
+ return GSS_C_NO_IOV_BUFFER;
+
+ for (i = iov_count - 1; i >= 0; i--) {
+ if (GSS_IOV_BUFFER_TYPE(iov[i].type) == type) {
+ if (p == GSS_C_NO_IOV_BUFFER)
+ p = &iov[i];
+ else
+ return GSS_C_NO_IOV_BUFFER;
+ }
+ }
+
+ return p;
+}
+
+/* Return the IOV where the GSSAPI token header should be placed (and possibly
+ * the checksum as well, depending on the token type). */
+gss_iov_buffer_t
+kg_locate_header_iov(gss_iov_buffer_desc *iov, int iov_count, int toktype)
+{
+ if (toktype == KG_TOK_MIC_MSG)
+ return kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_MIC_TOKEN);
+ else
+ return kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+}
+
+void
+kg_iov_msglen(gss_iov_buffer_desc *iov, int iov_count, size_t *data_length_p,
+ size_t *assoc_data_length_p)
+{
+ int i;
+ size_t data_length = 0, assoc_data_length = 0;
+
+ assert(iov != GSS_C_NO_IOV_BUFFER);
+
+ *data_length_p = *assoc_data_length_p = 0;
+
+ for (i = 0; i < iov_count; i++) {
+ OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[i].type);
+
+ if (type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
+ assoc_data_length += iov[i].buffer.length;
+
+ if (type == GSS_IOV_BUFFER_TYPE_DATA ||
+ type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
+ data_length += iov[i].buffer.length;
+ }
+
+ *data_length_p = data_length;
+ *assoc_data_length_p = assoc_data_length;
+}
+
+void
+kg_release_iov(gss_iov_buffer_desc *iov, int iov_count)
+{
+ int i;
+
+ assert(iov != GSS_C_NO_IOV_BUFFER);
+
+ for (i = 0; i < iov_count; i++) {
+ if (iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
+ gssalloc_free(iov[i].buffer.value);
+ iov[i].buffer.length = 0;
+ iov[i].buffer.value = NULL;
+ iov[i].type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
+ }
+ }
+}
+
+OM_uint32
+kg_fixup_padding_iov(OM_uint32 *minor_status, gss_iov_buffer_desc *iov,
+ int iov_count)
+{
+ gss_iov_buffer_t padding = NULL;
+ gss_iov_buffer_t data = NULL;
+ size_t padlength, relative_padlength;
+ unsigned char *p;
+
+ data = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_DATA);
+ padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+
+ if (data == NULL) {
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+ }
+
+ if (padding == NULL || padding->buffer.length == 0) {
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ p = (unsigned char *)padding->buffer.value;
+ padlength = p[padding->buffer.length - 1];
+
+ if (data->buffer.length + padding->buffer.length < padlength ||
+ padlength == 0) {
+ *minor_status = (OM_uint32)KRB5_BAD_MSIZE;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ /*
+ * kg_unseal_stream_iov() will place one byte of padding in the
+ * padding buffer; its true value is unknown until after decryption.
+ *
+ * relative_padlength contains the number of bytes to compensate the
+ * padding and data buffers by; it will be zero if the caller manages
+ * the padding length.
+ *
+ * If the caller manages the padding length, then relative_padlength
+ * wil be zero.
+ *
+ * eg. if the buffers are structured as follows:
+ *
+ * +---DATA---+-PAD-+
+ * | ABCDE444 | 4 |
+ * +----------+-----+
+ *
+ * after compensation they would look like:
+ *
+ * +-DATA--+-PAD--+
+ * | ABCDE | NULL |
+ * +-------+------+
+ */
+ relative_padlength = padlength - padding->buffer.length;
+
+ assert(data->buffer.length >= relative_padlength);
+
+ data->buffer.length -= relative_padlength;
+
+ kg_release_iov(padding, 1);
+ padding->buffer.length = 0;
+ padding->buffer.value = NULL;
+
+ return GSS_S_COMPLETE;
+}
+
+krb5_boolean
+kg_integ_only_iov(gss_iov_buffer_desc *iov, int iov_count)
+{
+ int i;
+ krb5_boolean has_conf_data = FALSE;
+
+ assert(iov != GSS_C_NO_IOV_BUFFER);
+
+ for (i = 0; i < iov_count; i++) {
+ if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA) {
+ has_conf_data = TRUE;
+ break;
+ }
+ }
+
+ return (has_conf_data == FALSE);
+}
+
+krb5_error_code
+kg_allocate_iov(gss_iov_buffer_t iov, size_t size)
+{
+ assert(iov != GSS_C_NO_IOV_BUFFER);
+ assert(iov->type & GSS_IOV_BUFFER_FLAG_ALLOCATE);
+
+ iov->buffer.length = size;
+ iov->buffer.value = gssalloc_malloc(size);
+ if (iov->buffer.value == NULL) {
+ iov->buffer.length = 0;
+ return ENOMEM;
+ }
+
+ iov->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
+
+ return 0;
+}
diff --git a/src/lib/gssapi/krb5/util_seed.c b/src/lib/gssapi/krb5/util_seed.c
new file mode 100644
index 000000000000..6e1c9ac8aecb
--- /dev/null
+++ b/src/lib/gssapi/krb5/util_seed.c
@@ -0,0 +1,61 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+static const unsigned char zeros[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
+
+krb5_error_code
+kg_make_seed(context, key, seed)
+ krb5_context context;
+ krb5_key key;
+ unsigned char *seed;
+{
+ krb5_error_code code;
+ krb5_key rkey = NULL;
+ krb5_keyblock *tmpkey, *kb;
+ unsigned int i;
+
+ code = krb5_k_key_keyblock(context, key, &tmpkey);
+ if (code)
+ return(code);
+
+ /* reverse the key bytes, as per spec */
+ kb = &key->keyblock;
+ for (i=0; i<tmpkey->length; i++)
+ tmpkey->contents[i] = kb->contents[kb->length - 1 - i];
+
+ code = krb5_k_create_key(context, tmpkey, &rkey);
+ if (code)
+ goto cleanup;
+
+ code = kg_encrypt(context, rkey, KG_USAGE_SEAL, NULL, zeros, seed, 16);
+
+cleanup:
+ krb5_free_keyblock(context, tmpkey);
+ krb5_k_free_key(context, rkey);
+ return(code);
+}
diff --git a/src/lib/gssapi/krb5/util_seqnum.c b/src/lib/gssapi/krb5/util_seqnum.c
new file mode 100644
index 000000000000..bef631da9d1a
--- /dev/null
+++ b/src/lib/gssapi/krb5/util_seqnum.c
@@ -0,0 +1,102 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2001, 2009 by the Massachusetts Institute of Technology.
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+#include "k5-int.h"
+
+/*
+ * $Id$
+ */
+
+krb5_error_code
+kg_make_seq_num(context, key, direction, seqnum, cksum, buf)
+ krb5_context context;
+ krb5_key key;
+ int direction;
+ krb5_ui_4 seqnum;
+ unsigned char *cksum;
+ unsigned char *buf;
+{
+ unsigned char plain[8];
+
+ plain[4] = direction;
+ plain[5] = direction;
+ plain[6] = direction;
+ plain[7] = direction;
+ if (key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC ||
+ key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
+ /* Yes, Microsoft used big-endian sequence number.*/
+ store_32_be(seqnum, plain);
+ return kg_arcfour_docrypt (&key->keyblock, 0,
+ cksum, 8,
+ &plain[0], 8,
+ buf);
+
+ }
+
+ store_32_le(seqnum, plain);
+ return(kg_encrypt(context, key, KG_USAGE_SEQ, cksum, plain, buf, 8));
+}
+
+krb5_error_code kg_get_seq_num(context, key, cksum, buf, direction, seqnum)
+ krb5_context context;
+ krb5_key key;
+ unsigned char *cksum;
+ unsigned char *buf;
+ int *direction;
+ krb5_ui_4 *seqnum;
+{
+ krb5_error_code code;
+ unsigned char plain[8];
+
+ if (key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC ||
+ key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
+ code = kg_arcfour_docrypt (&key->keyblock, 0,
+ cksum, 8,
+ buf, 8,
+ plain);
+ } else {
+ code = kg_decrypt(context, key, KG_USAGE_SEQ, cksum, buf, plain, 8);
+ }
+ if (code)
+ return(code);
+
+ if ((plain[4] != plain[5]) ||
+ (plain[4] != plain[6]) ||
+ (plain[4] != plain[7]))
+ return((krb5_error_code) KG_BAD_SEQ);
+
+ *direction = plain[4];
+ if (key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC ||
+ key->keyblock.enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
+ *seqnum = (plain[3]|(plain[2]<<8) | (plain[1]<<16)| (plain[0]<<24));
+ } else {
+ *seqnum = ((plain[0]) |
+ (plain[1]<<8) |
+ (plain[2]<<16) |
+ (plain[3]<<24));
+ }
+
+ return(0);
+}
diff --git a/src/lib/gssapi/krb5/val_cred.c b/src/lib/gssapi/krb5/val_cred.c
new file mode 100644
index 000000000000..cb1cb9393acf
--- /dev/null
+++ b/src/lib/gssapi/krb5/val_cred.c
@@ -0,0 +1,83 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1997, 2007 by Massachusetts Institute of Technology
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "gssapiP_krb5.h"
+
+/* Check to see whether or not a GSSAPI krb5 credential is valid. If
+ * it is not, return an error. */
+
+OM_uint32
+krb5_gss_validate_cred_1(OM_uint32 *minor_status, gss_cred_id_t cred_handle,
+ krb5_context context)
+{
+ krb5_gss_cred_id_t cred;
+ krb5_error_code code;
+ krb5_principal princ;
+
+ cred = (krb5_gss_cred_id_t) cred_handle;
+ k5_mutex_lock(&cred->lock);
+
+ if (cred->ccache && cred->expire != 0) {
+ if ((code = krb5_cc_get_principal(context, cred->ccache, &princ))) {
+ k5_mutex_unlock(&cred->lock);
+ *minor_status = code;
+ return(GSS_S_DEFECTIVE_CREDENTIAL);
+ }
+ if (!krb5_principal_compare(context, princ, cred->name->princ)) {
+ k5_mutex_unlock(&cred->lock);
+ *minor_status = KG_CCACHE_NOMATCH;
+ return(GSS_S_DEFECTIVE_CREDENTIAL);
+ }
+ (void)krb5_free_principal(context, princ);
+ }
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+krb5_gss_validate_cred(minor_status, cred_handle)
+ OM_uint32 *minor_status;
+ gss_cred_id_t cred_handle;
+{
+ krb5_context context;
+ krb5_error_code code;
+ OM_uint32 maj;
+
+ code = krb5_gss_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ maj = krb5_gss_validate_cred_1(minor_status, cred_handle, context);
+ if (maj == 0) {
+ krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t) cred_handle;
+ k5_mutex_assert_locked(&cred->lock);
+ k5_mutex_unlock(&cred->lock);
+ }
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return maj;
+}
diff --git a/src/lib/gssapi/krb5/wrap_size_limit.c b/src/lib/gssapi/krb5/wrap_size_limit.c
new file mode 100644
index 000000000000..7959f424ec96
--- /dev/null
+++ b/src/lib/gssapi/krb5/wrap_size_limit.c
@@ -0,0 +1,178 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2000 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/* V2 interface */
+OM_uint32 KRB5_CALLCONV
+krb5_gss_wrap_size_limit(minor_status, context_handle, conf_req_flag,
+ qop_req, req_output_size, max_input_size)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t context_handle;
+ int conf_req_flag;
+ gss_qop_t qop_req;
+ OM_uint32 req_output_size;
+ OM_uint32 *max_input_size;
+{
+ krb5_gss_ctx_id_rec *ctx;
+ OM_uint32 data_size, conflen;
+ OM_uint32 ohlen;
+ int overhead;
+
+ /* only default qop is allowed */
+ if (qop_req != GSS_C_QOP_DEFAULT) {
+ *minor_status = (OM_uint32) G_UNKNOWN_QOP;
+ return GSS_S_BAD_QOP;
+ }
+
+ ctx = (krb5_gss_ctx_id_rec *) context_handle;
+ if (ctx->terminated || !ctx->established) {
+ *minor_status = KG_CTX_INCOMPLETE;
+ return(GSS_S_NO_CONTEXT);
+ }
+
+ if (ctx->proto == 1) {
+ /* No pseudo-ASN.1 wrapper overhead, so no sequence length and
+ OID. */
+ OM_uint32 sz = req_output_size;
+
+ /* Token header: 16 octets. */
+ if (conf_req_flag) {
+ krb5_key key;
+ krb5_enctype enctype;
+
+ key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey
+ : ctx->subkey;
+ enctype = key->keyblock.enctype;
+
+ while (sz > 0 && krb5_encrypt_size(sz, enctype) + 16 > req_output_size)
+ sz--;
+ /* Allow for encrypted copy of header. */
+ if (sz > 16)
+ sz -= 16;
+ else
+ sz = 0;
+#ifdef CFX_EXERCISE
+ /* Allow for EC padding. In the MIT implementation, only
+ added while testing. */
+ if (sz > 65535)
+ sz -= 65535;
+ else
+ sz = 0;
+#endif
+ } else {
+ krb5_cksumtype cksumtype;
+ krb5_error_code err;
+ size_t cksumsize;
+
+ cksumtype = ctx->have_acceptor_subkey ? ctx->acceptor_subkey_cksumtype
+ : ctx->cksumtype;
+
+ err = krb5_c_checksum_length(ctx->k5_context, cksumtype, &cksumsize);
+ if (err) {
+ *minor_status = err;
+ return GSS_S_FAILURE;
+ }
+
+ /* Allow for token header and checksum. */
+ if (sz < 16 + cksumsize)
+ sz = 0;
+ else
+ sz -= (16 + cksumsize);
+ }
+
+ *max_input_size = sz;
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+ }
+
+ /* Calculate the token size and subtract that from the output size */
+ overhead = 7 + ctx->mech_used->length;
+ data_size = req_output_size;
+ conflen = kg_confounder_size(ctx->k5_context, ctx->enc->keyblock.enctype);
+ data_size = (conflen + data_size + 8) & (~(OM_uint32)7);
+ ohlen = g_token_size(ctx->mech_used,
+ (unsigned int) (data_size + ctx->cksum_size + 14))
+ - req_output_size;
+
+ if (ohlen+overhead < req_output_size)
+ /*
+ * Cannot have trailer length that will cause us to pad over our
+ * length.
+ */
+ *max_input_size = (req_output_size - ohlen - overhead) & (~(OM_uint32)7);
+ else
+ *max_input_size = 0;
+
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}