Merge from branches/mechglue. Initial integration of Sun-donated
authorTom Yu <tlyu@mit.edu>
Wed, 14 Jun 2006 22:27:54 +0000 (22:27 +0000)
committerTom Yu <tlyu@mit.edu>
Wed, 14 Jun 2006 22:27:54 +0000 (22:27 +0000)
mechglue and SPNEGO implementations.  Additional changes outside of
src/lib/gssapi:

* src/configure.in: Add lib/gssapi/mechglue and lib/gssapi/spnego
to list of directories to output Makefile in.

* src/lib/rpc/unit-test/rpc_test.0/expire.exp (expired): Update
regexp for mechglue.

* src/tests/dejagnu/krb-standalone/v4gssftp.exp (v4ftp_test):
Update "Miscellaneous failure" regexp for mechglue.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@18131 dc483132-0cff-0310-8789-dd5450dbe970

68 files changed:
README
src/configure.in
src/include/krb5/locate.h [new file with mode: 0644]
src/lib/gssapi/LICENSE [new file with mode: 0644]
src/lib/gssapi/Makefile.in
src/lib/gssapi/generic/Makefile.in
src/lib/gssapi/generic/gssapi.hin
src/lib/gssapi/generic/gssapiP_generic.h
src/lib/gssapi/generic/gssapi_err_generic.et
src/lib/gssapi/generic/oid_ops.c [deleted file]
src/lib/gssapi/generic/util_oid.c [deleted file]
src/lib/gssapi/gss_libinit.c
src/lib/gssapi/krb5/Makefile.in
src/lib/gssapi/krb5/accept_sec_context.c
src/lib/gssapi/krb5/copy_ccache.c
src/lib/gssapi/krb5/get_tkt_flags.c
src/lib/gssapi/krb5/gssapiP_krb5.h
src/lib/gssapi/krb5/gssapi_krb5.c
src/lib/gssapi/krb5/gssapi_krb5.hin
src/lib/gssapi/krb5/indicate_mechs.c
src/lib/gssapi/krb5/init_sec_context.c
src/lib/gssapi/krb5/krb5_gss_glue.c
src/lib/gssapi/krb5/lucid_context.c
src/lib/gssapi/krb5/rel_oid.c
src/lib/gssapi/krb5/set_allowable_enctypes.c
src/lib/gssapi/mechglue/Makefile.in
src/lib/gssapi/mechglue/g_accept_sec_context.c
src/lib/gssapi/mechglue/g_acquire_cred.c
src/lib/gssapi/mechglue/g_canon_name.c [new file with mode: 0644]
src/lib/gssapi/mechglue/g_compare_name.c
src/lib/gssapi/mechglue/g_context_time.c
src/lib/gssapi/mechglue/g_delete_sec_context.c
src/lib/gssapi/mechglue/g_dsp_name.c
src/lib/gssapi/mechglue/g_dsp_status.c
src/lib/gssapi/mechglue/g_dup_name.c [new file with mode: 0644]
src/lib/gssapi/mechglue/g_exp_sec_context.c
src/lib/gssapi/mechglue/g_export_name.c [new file with mode: 0644]
src/lib/gssapi/mechglue/g_glue.c
src/lib/gssapi/mechglue/g_imp_name.c
src/lib/gssapi/mechglue/g_imp_sec_context.c
src/lib/gssapi/mechglue/g_indicate_mechs.c
src/lib/gssapi/mechglue/g_init_sec_context.c
src/lib/gssapi/mechglue/g_initialize.c
src/lib/gssapi/mechglue/g_inq_context.c
src/lib/gssapi/mechglue/g_inq_cred.c
src/lib/gssapi/mechglue/g_inq_names.c
src/lib/gssapi/mechglue/g_mechname.c
src/lib/gssapi/mechglue/g_oid_ops.c
src/lib/gssapi/mechglue/g_process_context.c
src/lib/gssapi/mechglue/g_rel_cred.c
src/lib/gssapi/mechglue/g_rel_name.c
src/lib/gssapi/mechglue/g_rel_oid_set.c
src/lib/gssapi/mechglue/g_seal.c
src/lib/gssapi/mechglue/g_sign.c
src/lib/gssapi/mechglue/g_store_cred.c [new file with mode: 0644]
src/lib/gssapi/mechglue/g_unseal.c
src/lib/gssapi/mechglue/g_userok.c [new file with mode: 0644]
src/lib/gssapi/mechglue/g_utils.c [new file with mode: 0644]
src/lib/gssapi/mechglue/g_verify.c
src/lib/gssapi/mechglue/gssd_pname_to_uid.c
src/lib/gssapi/mechglue/mglueP.h
src/lib/gssapi/mechglue/oid_ops.c
src/lib/gssapi/spnego/Makefile.in [new file with mode: 0644]
src/lib/gssapi/spnego/gssapiP_spnego.h [new file with mode: 0644]
src/lib/gssapi/spnego/spnego_mech.c [new file with mode: 0644]
src/lib/rpc/svc_auth_gssapi.c
src/lib/rpc/unit-test/rpc_test.0/expire.exp
src/tests/dejagnu/krb-standalone/v4gssftp.exp

diff --git a/README b/README
index 300df13d9a188a43811dd4d214d9cb8f7a85fe08..243af7d7e092f3ac6ffaf7f4c3dd27a64660d191 100644 (file)
--- a/README
+++ b/README
@@ -222,9 +222,76 @@ src/lib/crypto/aes has the following copyright:
  in respect of any properties, including, but not limited to, correctness 
  and fitness for purpose.
 
+--- The implementations of GSSAPI mechglue in GSSAPI-SPNEGO in
+    src/lib/gssapi, including the following files:
+
+lib/gssapi/generic/gssapi_err_generic.et
+lib/gssapi/mechglue/g_accept_sec_context.c
+lib/gssapi/mechglue/g_acquire_cred.c
+lib/gssapi/mechglue/g_canon_name.c
+lib/gssapi/mechglue/g_compare_name.c
+lib/gssapi/mechglue/g_context_time.c
+lib/gssapi/mechglue/g_delete_sec_context.c
+lib/gssapi/mechglue/g_dsp_name.c
+lib/gssapi/mechglue/g_dsp_status.c
+lib/gssapi/mechglue/g_dup_name.c
+lib/gssapi/mechglue/g_exp_sec_context.c
+lib/gssapi/mechglue/g_export_name.c
+lib/gssapi/mechglue/g_glue.c
+lib/gssapi/mechglue/g_imp_name.c
+lib/gssapi/mechglue/g_imp_sec_context.c
+lib/gssapi/mechglue/g_init_sec_context.c
+lib/gssapi/mechglue/g_initialize.c
+lib/gssapi/mechglue/g_inquire_context.c
+lib/gssapi/mechglue/g_inquire_cred.c
+lib/gssapi/mechglue/g_inquire_names.c
+lib/gssapi/mechglue/g_process_context.c
+lib/gssapi/mechglue/g_rel_buffer.c
+lib/gssapi/mechglue/g_rel_cred.c
+lib/gssapi/mechglue/g_rel_name.c
+lib/gssapi/mechglue/g_rel_oid_set.c
+lib/gssapi/mechglue/g_seal.c
+lib/gssapi/mechglue/g_sign.c
+lib/gssapi/mechglue/g_store_cred.c
+lib/gssapi/mechglue/g_unseal.c
+lib/gssapi/mechglue/g_userok.c
+lib/gssapi/mechglue/g_utils.c
+lib/gssapi/mechglue/g_verify.c
+lib/gssapi/mechglue/gssd_pname_to_uid.c
+lib/gssapi/mechglue/mglueP.h
+lib/gssapi/mechglue/oid_ops.c
+lib/gssapi/spnego/gssapiP_spnego.h
+lib/gssapi/spnego/spnego_mech.c
+
+are subject to the following license:
+
+Copyright (c) 2004 Sun Microsystems, 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.
+
 Acknowledgements
 ----------------
 
+Thanks to Sun Microsystems for donating their implementations of
+mechglue and SPNEGO.
+
 Thanks to the members of the Kerberos V5 development team at MIT, both
 past and present: Danilo Almeida, Jeffrey Altman, Richard Basch, Jay
 Berkenbilt, Mitch Berger, Andrew Boardman, Joe Calzaretta, John Carr,
index 68adb76bfdcab84ea5023dc7e1b174ec819c7caa..7c6cc95eb7bbb84e318b03dac9c94d5112e26dc6 100644 (file)
@@ -912,6 +912,7 @@ V5_AC_OUTPUT_MAKEFILE(.
        lib/krb5/keytab lib/krb5/krb lib/krb5/rcache lib/krb5/os
 
        lib/gssapi lib/gssapi/generic lib/gssapi/krb5
+       lib/gssapi/mechglue lib/gssapi/spnego
 
        lib/rpc lib/rpc/unit-test
 
diff --git a/src/include/krb5/locate.h b/src/include/krb5/locate.h
new file mode 100644 (file)
index 0000000..552369c
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef K5_PLUGIN_H_INCLUDED
+#define K5_PLUGIN_H_INCLUDED
+#include <krb5/krb5.h>
+
+enum locate_service_type {
+    locate_service_kdc = 1,
+    locate_service_master_kdc,
+    locate_service_kadmin,
+    locate_service_krb524,
+    locate_service_kpasswd
+};
+
+struct krb5plugin_service_locate_ftable {
+    int vmajor, vminor;
+    /* Per-context setup and teardown.  Returned void* blob is
+       private to the plugin.  */
+    krb5_error_code (*init)(krb5_context, void **);
+    void (*fini)(void *);
+    /* Callback function returns non-zero if the plugin function
+       should quit and return; this may be because of an error, or may
+       indicate we've already contacted the service, whatever.  The
+       lookup function should only return an error if it detects a
+       problem, not if the callback function tells it to quit.  */
+    krb5_error_code (*lookup)(void *,
+                             enum locate_service_type svc, const char *realm,
+                             int socktype, int family,
+                             int (*cbfunc)(void *,int,struct sockaddr *),
+                             void *cbdata);
+};
+#endif
diff --git a/src/lib/gssapi/LICENSE b/src/lib/gssapi/LICENSE
new file mode 100644 (file)
index 0000000..612f8ad
--- /dev/null
@@ -0,0 +1,91 @@
+[ NOTE: MIT has only incorporated the mechglue and spnego change, and
+not the incremental propagation changes.  The filenames are different
+between the Sun and MIT sources.  The actual MIT filenames appear in
+the top-level README file.  Original text of Sun's LICENSE file
+follows. ]
+
+Subject to the license set forth below, Sun Microsystems, Inc. donates
+the attached files to MIT for the purpose of including these
+modifications and additions in future versions of the Kerberos system.
+
+Many of the files attached are subject to licenses issued by other
+entities, including OpenVision, MIT, and FundsXpress.  See the
+individual files, and/or related Readme files, for these licenses.
+
+In addition Sun requires that the license set forth below be
+incorporated into any future version of the Kerberos system which
+contains portions of the files attached.  The following files must be
+listed, in the top level Readme file, as being provided subject to such
+license:
+
+cmd/krb5/iprop/iprop.x
+cmd/krb5/iprop/iprop_hdr.h
+cmd/krb5/kadmin/server/ipropd_svc.c
+cmd/krb5/kproplog/kproplog.c
+cmd/krb5/slave/kpropd_rpc.c
+lib/gss_mechs/mech_krb5/et/kdb5_err.c
+lib/gss_mechs/mech_spnego/mech/gssapiP_spnego.h
+lib/gss_mechs/mech_spnego/mech/spnego_mech.c
+lib/krb5/kadm5/kadm_host_srv_names.c
+lib/krb5/kdb/kdb_convert.c
+lib/krb5/kdb/kdb_hdr.h
+lib/krb5/kdb/kdb_log.c
+lib/krb5/kdb/kdb_log.h
+lib/libgss/g_accept_sec_context.c
+lib/libgss/g_acquire_cred.c
+lib/libgss/g_canon_name.c
+lib/libgss/g_compare_name.c
+lib/libgss/g_context_time.c
+lib/libgss/g_delete_sec_context.c
+lib/libgss/g_dsp_name.c
+lib/libgss/g_dsp_status.c
+lib/libgss/g_dup_name.c
+lib/libgss/g_exp_sec_context.c
+lib/libgss/g_export_name.c
+lib/libgss/g_glue.c
+lib/libgss/g_imp_name.c
+lib/libgss/g_imp_sec_context.c
+lib/libgss/g_init_sec_context.c
+lib/libgss/g_initialize.c
+lib/libgss/g_inquire_context.c
+lib/libgss/g_inquire_cred.c
+lib/libgss/g_inquire_names.c
+lib/libgss/g_process_context.c
+lib/libgss/g_rel_buffer.c
+lib/libgss/g_rel_cred.c
+lib/libgss/g_rel_name.c
+lib/libgss/g_rel_oid_set.c
+lib/libgss/g_seal.c
+lib/libgss/g_sign.c
+lib/libgss/g_store_cred.c
+lib/libgss/g_unseal.c
+lib/libgss/g_userok.c
+lib/libgss/g_utils.c
+lib/libgss/g_verify.c
+lib/libgss/gssd_pname_to_uid.c
+uts/common/gssapi/include/gssapi_err_generic.h
+uts/common/gssapi/include/mechglueP.h
+
+Sun's License is as follows:
+
+Copyright (c) 2004 Sun Microsystems, 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.
+
index daf0818ddc6b1b47da2c530731e123fd61fcea22..d9c9e770759168788594260113d01ac9e7f30233 100644 (file)
@@ -2,7 +2,7 @@ thisconfigdir=../..
 myfulldir=lib/gssapi
 mydir=lib/gssapi
 BUILDTOP=$(REL)..$(S)..
-LOCAL_SUBDIRS= generic krb5
+LOCAL_SUBDIRS= generic mechglue krb5 spnego
 DEFS=
 
 ##DOSLIBNAME=$(OUTPRE)gssapi.lib
@@ -14,7 +14,7 @@ DEFS=
 
 ##DOS##DLL_EXP_TYPE=GSS
 
-LOCALINCLUDES = -Igeneric -I$(srcdir)/generic -Ikrb5 -I$(srcdir)/krb5
+LOCALINCLUDES = -Igeneric -I$(srcdir)/generic -Ikrb5 -I$(srcdir)/krb5 -I$(srcdir)/mechglue
 STLIBOBJS=\
        gss_libinit.o
 
@@ -29,11 +29,11 @@ LIBMAJOR=2
 LIBMINOR=2
 LIBINITFUNC=gssint_lib_init
 LIBFINIFUNC=gssint_lib_fini
-STOBJLISTS=OBJS.ST generic/OBJS.ST krb5/OBJS.ST
-SUBDIROBJLISTS=generic/OBJS.ST krb5/OBJS.ST
+STOBJLISTS=OBJS.ST generic/OBJS.ST mechglue/OBJS.ST krb5/OBJS.ST spnego/OBJS.ST
+SUBDIROBJLISTS=generic/OBJS.ST mechglue/OBJS.ST krb5/OBJS.ST
 SHLIB_EXPDEPS=\
        $(KRB5_DEPLIB) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB) $(COM_ERR_DEPLIB)
-SHLIB_EXPLIBS=-lkrb5 -lk5crypto -lcom_err $(SUPPORT_LIB) $(LIBS)
+SHLIB_EXPLIBS=-lkrb5 -lk5crypto -lcom_err $(SUPPORT_LIB) $(DL_LIB) $(LIBS)
 SHLIB_DIRS=-L$(TOPLIBD)
 SHLIB_RDIRS=$(KRB5_LIBDIR)
 RELDIR=gssapi
index 9dfa68e6fd243f53adfde3e7faa6d0fad3ec9a75..38b55e1b464704542f8ad3aa637d1d34b2c2fe7a 100644 (file)
@@ -67,11 +67,9 @@ SRCS = \
        $(srcdir)/disp_com_err_status.c \
        $(srcdir)/disp_major_status.c \
        $(srcdir)/gssapi_generic.c \
-       $(srcdir)/oid_ops.c \
        $(srcdir)/rel_buffer.c \
        $(srcdir)/rel_oid_set.c \
        $(srcdir)/util_buffer.c \
-       $(srcdir)/util_oid.c \
        $(srcdir)/util_ordering.c \
        $(srcdir)/util_set.c \
        $(srcdir)/util_token.c \
@@ -82,11 +80,9 @@ OBJS = \
        $(OUTPRE)disp_com_err_status.$(OBJEXT) \
        $(OUTPRE)disp_major_status.$(OBJEXT) \
        $(OUTPRE)gssapi_generic.$(OBJEXT) \
-       $(OUTPRE)oid_ops.$(OBJEXT) \
        $(OUTPRE)rel_buffer.$(OBJEXT) \
        $(OUTPRE)rel_oid_set.$(OBJEXT) \
        $(OUTPRE)util_buffer.$(OBJEXT) \
-       $(OUTPRE)util_oid.$(OBJEXT) \
        $(OUTPRE)util_ordering.$(OBJEXT) \
        $(OUTPRE)util_set.$(OBJEXT) \
        $(OUTPRE)util_token.$(OBJEXT) \
@@ -97,11 +93,9 @@ STLIBOBJS = \
        disp_com_err_status.o \
        disp_major_status.o \
        gssapi_generic.o \
-       oid_ops.o \
        rel_buffer.o \
        rel_oid_set.o \
        util_buffer.o \
-       util_oid.o \
        util_ordering.o \
        util_set.o \
        util_token.o \
index 37b79e807f14d1936afae297bc21c87436d9b431..28b5b1123700b27ed6047b78bc39f7e1eba37aa6 100644 (file)
@@ -691,6 +691,13 @@ OM_uint32 KRB5_CALLCONV gss_inquire_names_for_mech
            gss_OID_set *               /* name_types */
           );
 
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_inquire_mechs_for_name(
+    OM_uint32 *,               /* minor_status */
+    const gss_name_t,          /* input_name */
+    gss_OID_set *              /* mech_types */
+);
+
 /*
  * The following routines are obsolete variants of gss_get_mic, gss_wrap,
  * gss_verify_mic and gss_unwrap.  They should be provided by GSSAPI V2
index ca19b18910ff049162934b09ae293f135c6973c4..2752f1dfa1ad8294141e74ea5140037e04e96e8d 100644 (file)
@@ -48,9 +48,9 @@ typedef UINT64_TYPE gssint_uint64;
 
 /** helper macros **/
 
-#define g_OID_equal(o1,o2) \
-   (((o1)->length == (o2)->length) && \
-    (memcmp((o1)->elements,(o2)->elements,(unsigned int) (o1)->length) == 0))
+#define        g_OID_equal(o1, o2) \
+       (((o1)->length == (o2)->length) && \
+       (memcmp((o1)->elements, (o2)->elements, (o1)->length) == 0))
 
 /* this code knows that an int on the wire is 32 bits.  The type of
    num should be at least this big, or the extra shifts may do weird
@@ -122,7 +122,6 @@ typedef UINT64_TYPE gssint_uint64;
 #define        g_delete_ctx_id         gssint_g_delete_ctx_id
 #define        g_delete_lucidctx_id    gssint_g_delete_lucidctx_id
 #define        g_make_string_buffer    gssint_g_make_string_buffer
-#define        g_copy_OID_set          gssint_g_copy_OID_set
 #define        g_token_size            gssint_g_token_size
 #define        g_make_token_header     gssint_g_make_token_header
 #define        g_verify_token_header   gssint_g_verify_token_header
@@ -168,8 +167,6 @@ int g_delete_lucidctx_id (g_set *vdb, void *lctx);
 
 int g_make_string_buffer (const char *str, gss_buffer_t buffer);
 
-int g_copy_OID_set (const gss_OID_set_desc * const in, gss_OID_set *out);
-
 unsigned int g_token_size (const gss_OID_desc * mech, unsigned int body_size);
 
 void g_make_token_header (const gss_OID_desc * mech, unsigned int body_size,
index 99ba45fe3814c163a889ab38f69acef9286facbd..3e976e3dbf5022d9e609d9f47a3fdcd4061c6ccb 100644 (file)
@@ -43,4 +43,7 @@ error_code G_BAD_DIRECTION, "Packet was replayed in wrong direction"
 error_code G_TOK_TRUNC, "Token is missing data"
 error_code G_REFLECT, "Token was reflected"
 error_code G_WRONG_TOKID, "Received token ID does not match expected token ID"
+error_code G_CRED_USAGE_MISMATCH, "The given credential's usage does not match the requested usage"
+error_code G_STORE_ACCEPTOR_CRED_NOSUPP, "Storing of acceptor credentials is not supported by the mechanism"
+error_code G_STORE_NON_DEFAULT_CRED_NOSUPP, "Storing of non-default credentials is not supported by the mechanism"
 end
diff --git a/src/lib/gssapi/generic/oid_ops.c b/src/lib/gssapi/generic/oid_ops.c
deleted file mode 100644 (file)
index 1234f2e..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * lib/gssapi/generic/oid_ops.c
- *
- * 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.
- *
- */
-
-/*
- * oid_ops.c - GSS-API V2 interfaces to manipulate OIDs
- */
-
-#include "gssapiP_generic.h"
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-
-OM_uint32
-generic_gss_release_oid(minor_status, oid)
-    OM_uint32  *minor_status;
-    gss_OID    *oid;
-{
-    *minor_status = 0;
-
-    if (*oid == GSS_C_NO_OID)
-       return(GSS_S_COMPLETE);
-
-    /*
-     * 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 ((*oid != gss_nt_user_name) &&
-       (*oid != gss_nt_machine_uid_name) &&
-       (*oid != gss_nt_string_uid_name) &&
-       (*oid != gss_nt_service_name) &&
-       (*oid != gss_nt_exported_name) &&
-       (*oid != gss_nt_service_name_v2)) {
-       free((*oid)->elements);
-       free(*oid);
-    }
-    *oid = GSS_C_NO_OID;
-    return(GSS_S_COMPLETE);
-}
-
-OM_uint32
-generic_gss_copy_oid(minor_status, oid, new_oid)
-       OM_uint32       *minor_status;
-       const gss_OID_desc * const oid;
-       gss_OID         *new_oid;
-{
-       gss_OID         p;
-
-       p = (gss_OID) malloc(sizeof(gss_OID_desc));
-       if (!p) {
-               *minor_status = ENOMEM;
-               return GSS_S_FAILURE;
-       }
-       p->length = oid->length;
-       p->elements = malloc(p->length);
-       if (!p->elements) {
-               free(p);
-               *minor_status = ENOMEM;
-               return GSS_S_FAILURE;
-       }
-       memcpy(p->elements, oid->elements, p->length);
-       *new_oid = p;
-       return(GSS_S_COMPLETE);
-}
-
-
-OM_uint32
-generic_gss_create_empty_oid_set(minor_status, oid_set)
-    OM_uint32  *minor_status;
-    gss_OID_set        *oid_set;
-{
-    if ((*oid_set = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)))) {
-       memset(*oid_set, 0, sizeof(gss_OID_set_desc));
-       *minor_status = 0;
-       return(GSS_S_COMPLETE);
-    }
-    else {
-       *minor_status = ENOMEM;
-       return(GSS_S_FAILURE);
-    }
-}
-
-OM_uint32
-generic_gss_add_oid_set_member(minor_status, member_oid, oid_set)
-    OM_uint32  *minor_status;
-    const gss_OID_desc * const member_oid;
-    gss_OID_set        *oid_set;
-{
-    gss_OID    elist;
-    gss_OID    lastel;
-
-    elist = (*oid_set)->elements;
-    /* Get an enlarged copy of the array */
-    if (((*oid_set)->elements = (gss_OID) malloc(((*oid_set)->count+1) *
-                                                 sizeof(gss_OID_desc)))) {
-       /* Copy in the old junk */
-       if (elist)
-           memcpy((*oid_set)->elements,
-                  elist,
-                  ((*oid_set)->count * sizeof(gss_OID_desc)));
-
-       /* Duplicate the input element */
-       lastel = &(*oid_set)->elements[(*oid_set)->count];
-       if ((lastel->elements =
-            (void *) malloc((size_t) member_oid->length))) {
-           /* Success - copy elements */
-           memcpy(lastel->elements, member_oid->elements,
-                  (size_t) member_oid->length);
-           /* Set length */
-           lastel->length = member_oid->length;
-
-           /* Update count */
-           (*oid_set)->count++;
-           if (elist)
-               free(elist);
-           *minor_status = 0;
-           return(GSS_S_COMPLETE);
-       }
-       else
-           free((*oid_set)->elements);
-    }
-    /* Failure - restore old contents of list */
-    (*oid_set)->elements = elist;
-    *minor_status = ENOMEM;
-    return(GSS_S_FAILURE);
-}
-
-OM_uint32
-generic_gss_test_oid_set_member(minor_status, member, set, present)
-    OM_uint32  *minor_status;
-    const gss_OID_desc * const member;
-    gss_OID_set        set;
-    int                *present;
-{
-    size_t     i;
-    int                result;
-
-    result = 0;
-    for (i=0; i<set->count; i++) {
-       if ((set->elements[i].length == member->length) &&
-           !memcmp(set->elements[i].elements,
-                   member->elements,
-                   (size_t) member->length)) {
-           result = 1;
-           break;
-       }
-    }
-    *present = result;
-    *minor_status = 0;
-    return(GSS_S_COMPLETE);
-}
-
-/*
- * OID<->string routines.  These are uuuuugly.
- */
-OM_uint32
-generic_gss_oid_to_str(minor_status, oid, oid_str)
-    OM_uint32          *minor_status;
-    const gss_OID_desc * const oid;
-    gss_buffer_t       oid_str;
-{
-    char               numstr[128];
-    unsigned long      number;
-    int                        numshift;
-    size_t             string_length;
-    size_t             i;
-    unsigned char      *cp;
-    char               *bp;
-
-    /* Decoded according to krb5/gssapi_krb5.c */
-
-    /* First determine the size of the string */
-    string_length = 0;
-    number = 0;
-    numshift = 0;
-    cp = (unsigned char *) oid->elements;
-    number = (unsigned long) cp[0];
-    sprintf(numstr, "%ld ", number/40);
-    string_length += strlen(numstr);
-    sprintf(numstr, "%ld ", number%40);
-    string_length += strlen(numstr);
-    for (i=1; i<oid->length; i++) {
-       if ( (size_t) (numshift+7) < (sizeof(unsigned long)*8)) {
-           number = (number << 7) | (cp[i] & 0x7f);
-           numshift += 7;
-       }
-       else {
-           *minor_status = EINVAL;
-           return(GSS_S_FAILURE);
-       }
-       if ((cp[i] & 0x80) == 0) {
-           sprintf(numstr, "%ld ", number);
-           string_length += strlen(numstr);
-           number = 0;
-           numshift = 0;
-       }
-    }
-    /*
-     * If we get here, we've calculated the length of "n n n ... n ".  Add 4
-     * here for "{ " and "}\0".
-     */
-    string_length += 4;
-    if ((bp = (char *) malloc(string_length))) {
-       strcpy(bp, "{ ");
-       number = (unsigned long) cp[0];
-       sprintf(numstr, "%ld ", number/40);
-       strcat(bp, numstr);
-       sprintf(numstr, "%ld ", number%40);
-       strcat(bp, numstr);
-       number = 0;
-       cp = (unsigned char *) oid->elements;
-       for (i=1; i<oid->length; i++) {
-           number = (number << 7) | (cp[i] & 0x7f);
-           if ((cp[i] & 0x80) == 0) {
-               sprintf(numstr, "%ld ", number);
-               strcat(bp, numstr);
-               number = 0;
-           }
-       }
-       strcat(bp, "}");
-       oid_str->length = strlen(bp)+1;
-       oid_str->value = (void *) bp;
-       *minor_status = 0;
-       return(GSS_S_COMPLETE);
-    }
-    *minor_status = ENOMEM;
-    return(GSS_S_FAILURE);
-}
-
-OM_uint32
-generic_gss_str_to_oid(minor_status, oid_str, oid)
-    OM_uint32          *minor_status;
-    gss_buffer_t       oid_str;
-    gss_OID            *oid;
-{
-    char       *cp, *bp, *startp;
-    int                brace;
-    long       numbuf;
-    long       onumbuf;
-    OM_uint32  nbytes;
-    int                idx;
-    unsigned char *op;
-
-    brace = 0;
-    bp = (char *) oid_str->value;
-    cp = bp;
-    /* Skip over leading space */
-    while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
-       bp++;
-    if (*bp == '{') {
-       brace = 1;
-       bp++;
-    }
-    while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
-       bp++;
-    startp = bp;
-    nbytes = 0;
-
-    /*
-     * The first two numbers are chewed up by the first octet.
-     */
-    if (sscanf(bp, "%ld", &numbuf) != 1) {
-       *minor_status = EINVAL;
-       return(GSS_S_FAILURE);
-    }
-    while ((bp < &cp[oid_str->length]) && isdigit((int) *bp))
-       bp++;
-    while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
-       bp++;
-    if (sscanf(bp, "%ld", &numbuf) != 1) {
-       *minor_status = EINVAL;
-       return(GSS_S_FAILURE);
-    }
-    while ((bp < &cp[oid_str->length]) && isdigit((int) *bp))
-       bp++;
-    while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
-       bp++;
-    nbytes++;
-    while (isdigit((int) *bp)) {
-       if (sscanf(bp, "%ld", &numbuf) != 1) {
-           *minor_status = EINVAL;
-           return(GSS_S_FAILURE);
-       }
-       while (numbuf) {
-           nbytes++;
-           numbuf >>= 7;
-       }
-       while ((bp < &cp[oid_str->length]) && isdigit((int) *bp))
-           bp++;
-       while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
-           bp++;
-    }
-    if (brace && (*bp != '}')) {
-       *minor_status = EINVAL;
-       return(GSS_S_FAILURE);
-    }
-
-    /*
-     * Phew!  We've come this far, so the syntax is good.
-     */
-    if ((*oid = (gss_OID) malloc(sizeof(gss_OID_desc)))) {
-       if (((*oid)->elements = (void *) malloc((size_t) nbytes))) {
-           (*oid)->length = nbytes;
-           op = (unsigned char *) (*oid)->elements;
-           bp = startp;
-           sscanf(bp, "%ld", &numbuf);
-           while (isdigit((int) *bp))
-               bp++;
-           while (isspace((int) *bp))
-               bp++;
-           onumbuf = 40*numbuf;
-           sscanf(bp, "%ld", &numbuf);
-           onumbuf += numbuf;
-           *op = (unsigned char) onumbuf;
-           op++;
-           while (isdigit((int) *bp))
-               bp++;
-           while (isspace((int) *bp))
-               bp++;
-           while (isdigit((int) *bp)) {
-               sscanf(bp, "%ld", &numbuf);
-               nbytes = 0;
-               /* Have to fill in the bytes msb-first */
-               onumbuf = numbuf;
-               while (numbuf) {
-                   nbytes++;
-                   numbuf >>= 7;
-               }
-               numbuf = onumbuf;
-               op += nbytes;
-               idx = -1;
-               while (numbuf) {
-                   op[idx] = (unsigned char) numbuf & 0x7f;
-                   if (idx != -1)
-                       op[idx] |= 0x80;
-                   idx--;
-                   numbuf >>= 7;
-               }
-               while (isdigit((int) *bp))
-                   bp++;
-               while (isspace((int) *bp))
-                   bp++;
-           }
-           *minor_status = 0;
-           return(GSS_S_COMPLETE);
-       }
-       else {
-           free(*oid);
-           *oid = GSS_C_NO_OID;
-       }
-    }
-    *minor_status = ENOMEM;
-    return(GSS_S_FAILURE);
-}
-
diff --git a/src/lib/gssapi/generic/util_oid.c b/src/lib/gssapi/generic/util_oid.c
deleted file mode 100644 (file)
index 60b1e15..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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_generic.h"
-#include "string.h"
-
-/*
- * $Id$
- */
-
-int
-g_copy_OID_set(in, out)
-     const gss_OID_set_desc * const in;
-     gss_OID_set *out;
-{
-   gss_OID_set copy;
-   gss_OID     new_oid;
-   size_t      i;
-   size_t      len;
-
-   *out = NULL;
-
-   if ((copy =
-       (gss_OID_set_desc *) xmalloc(sizeof(gss_OID_set_desc))) == NULL)
-      return(0);
-
-   copy->count = in->count;
-   len = sizeof(gss_OID_desc) * copy->count;
-
-   if ((copy->elements = 
-       (gss_OID_desc *) xmalloc( len )) == NULL) {
-      xfree(copy);
-      return(0);
-   }
-
-   memset( copy->elements, 0, len );
-   
-   for (i=0; i<in->count; i++) {
-      len = in->elements[i].length;
-      new_oid = &(copy->elements[i]);
-      new_oid->elements = xmalloc( len );
-      if ( new_oid->elements == NULL ) {
-         while( i>0 ) {
-            i--;
-            new_oid = &(copy->elements[i]);
-            if ( new_oid->elements!=NULL )
-               xfree( new_oid->elements );
-         }
-         xfree( copy->elements );
-         xfree( copy );
-         return( 0 );
-      }
-      memcpy( new_oid->elements, in->elements[i].elements, len );
-      new_oid->length = len;
-   }
-
-   *out = copy;
-   return(1);
-}
index f16359497a5291222ad3989607290392aadbb245..16031e26efc8b6548abfeb9873e09664bfeb5e47 100644 (file)
@@ -7,6 +7,8 @@
 #include "gss_libinit.h"
 #include "k5-platform.h"
 
+#include "mglueP.h"
+
 /*
  * Initialize the GSSAPI library.
  */
@@ -26,6 +28,9 @@ int gssint_lib_init(void)
     add_error_table(&et_k5g_error_table);
     add_error_table(&et_ggss_error_table);
 #endif
+    err = gssint_mechglue_init();
+    if (err)
+       return err;
     err = k5_mutex_finish_init(&gssint_krb5_keytab_lock);
     if (err)
        return err;
@@ -61,6 +66,7 @@ void gssint_lib_fini(void)
     k5_mutex_destroy(&kg_vdb.mutex);
     k5_mutex_destroy(&kg_kdc_flag_mutex);
     k5_mutex_destroy(&gssint_krb5_keytab_lock);
+    gssint_mechglue_fini();
 }
 
 OM_uint32 gssint_initialize_library (void)
index 7d9e8826ff43bcede5646aae36e029be579067cd..7cd9848e7759d3e92dcd18240535398af7af9259 100644 (file)
@@ -2,7 +2,7 @@ thisconfigdir=../../..
 myfulldir=lib/gssapi/krb5
 mydir=lib/gssapi/krb5
 BUILDTOP=$(REL)..$(S)..$(S)..
-LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic
+LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic -I../mechglue -I$(srcdir)/../mechglue
 DEFS=
 
 ##DOS##BUILDTOP = ..\..\..
index ecda750f593ea7f51048933fce0c77405f6d4e4e..f461e8d501c3a37e72fe390a6dabb596668a07b9 100644 (file)
@@ -347,6 +347,12 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
                                      &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_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), 
index b0cc96fd8f498f4a2d88d9f55bf2e14d3c1e01bc..195be0f84299ded14ce72aaef82fbb85f2a419a1 100644 (file)
@@ -1,7 +1,7 @@
 #include "gssapiP_krb5.h"
 
 OM_uint32 KRB5_CALLCONV 
-gss_krb5_copy_ccache(minor_status, cred_handle, out_ccache)
+gss_krb5int_copy_ccache(minor_status, cred_handle, out_ccache)
      OM_uint32 *minor_status;
      gss_cred_id_t cred_handle;
      krb5_ccache out_ccache;
index 74f1532ae38f2480624d85b8b0e360d4fd1cc332..19841a086d6710c9adfb6ae97136f1246b82bec8 100644 (file)
@@ -27,7 +27,7 @@
  */
 
 OM_uint32 KRB5_CALLCONV 
-gss_krb5_get_tkt_flags(minor_status, context_handle, ticket_flags)
+gss_krb5int_get_tkt_flags(minor_status, context_handle, ticket_flags)
      OM_uint32 *minor_status;
      gss_ctx_id_t context_handle;
      krb5_flags *ticket_flags;
index 3539ac7a91c28c8bc4ebf07554501e62e8f604c3..b23bda406925d27bfa028cb8bd43b60f86051fc7 100644 (file)
 
 /** 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"
+
+
 #define CKSUMTYPE_KG_CB                0x8003
 
 #define KG_TOK_CTX_AP_REQ      0x0100
@@ -575,7 +586,7 @@ OM_uint32 krb5_gss_import_sec_context
 
 krb5_error_code krb5_gss_ser_init(krb5_context);
 
-OM_uint32 krb5_gss_release_oid
+OM_uint32 krb5_gss_internal_release_oid
 (OM_uint32 *,          /* minor_status */
            gss_OID *                   /* oid */
           );
@@ -631,6 +642,33 @@ OM_uint32 gss_krb5int_unseal_token_v3(krb5_context *contextptr,
                                      int *conf_state, int *qop_state, 
                                      int toktype);
 
+/*
+ * These take unglued krb5-mech-specific contexts.
+ */
+
+OM_uint32 KRB5_CALLCONV gss_krb5int_get_tkt_flags 
+       (OM_uint32 *minor_status,
+                  gss_ctx_id_t context_handle,
+                  krb5_flags *ticket_flags);
+
+OM_uint32 KRB5_CALLCONV gss_krb5int_copy_ccache
+       (OM_uint32 *minor_status,
+                  gss_cred_id_t cred_handle,
+                  krb5_ccache out_ccache);
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5int_set_allowable_enctypes(OM_uint32 *minor_status, 
+                                  gss_cred_id_t cred,
+                                  OM_uint32 num_ktypes,
+                                  krb5_enctype *ktypes);
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5int_export_lucid_sec_context(OM_uint32 *minor_status,
+                                    gss_ctx_id_t *context_handle,
+                                    OM_uint32 version,
+                                    void **kctx);
+
+
 extern k5_mutex_t kg_kdc_flag_mutex;
 krb5_error_code krb5_gss_init_context (krb5_context *ctxp);
 
index 94f11ef0321c5095f9274cb7e3061ff7c4eb9e46..f1c27e487e51dc462e68de3154aaca66b8733032 100644 (file)
 
 const gss_OID_desc krb5_gss_oid_array[] = {
    /* this is the official, rfc-specified OID */
-   {9, "\052\206\110\206\367\022\001\002\002"},
-   /* this is the unofficial, wrong OID */
-   {5, "\053\005\001\005\002"},
+   {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},
    /* this is the v2 assigned OID */
    {9, "\052\206\110\206\367\022\001\002\003"},
    /* these two are name type OID's */
@@ -108,14 +110,15 @@ const gss_OID_desc krb5_gss_oid_array[] = {
 
 const gss_OID_desc * const gss_mech_krb5              = krb5_gss_oid_array+0;
 const gss_OID_desc * const gss_mech_krb5_old          = krb5_gss_oid_array+1;
-const gss_OID_desc * const gss_nt_krb5_name           = krb5_gss_oid_array+3;
-const gss_OID_desc * const gss_nt_krb5_principal      = krb5_gss_oid_array+4;
-const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME = krb5_gss_oid_array+3;
+const gss_OID_desc * const gss_mech_krb5_wrong        = krb5_gss_oid_array+2;
+const gss_OID_desc * const gss_nt_krb5_name           = krb5_gss_oid_array+4;
+const gss_OID_desc * const gss_nt_krb5_principal      = krb5_gss_oid_array+5;
+const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME = krb5_gss_oid_array+4;
 
 static const gss_OID_set_desc oidsets[] = {
    {1, (gss_OID) krb5_gss_oid_array+0},
    {1, (gss_OID) krb5_gss_oid_array+1},
-   {2, (gss_OID) krb5_gss_oid_array+0},
+   {3, (gss_OID) krb5_gss_oid_array+0},
    {1, (gss_OID) krb5_gss_oid_array+2},
    {3, (gss_OID) krb5_gss_oid_array+0},
 };
index 20002478ece302c27d62b3099d98082af1ea7c08..647d14e3953b28c7287ccb74b74c64515da536d5 100644 (file)
@@ -72,6 +72,7 @@ GSS_DLLIMP extern const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME;
 
 GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5;
 GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5_old;
+GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5_wrong;
 GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5;
 GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5_old;
 GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5_both;
index 48baf1a0e58660f97774f7185320ef00ada9e882..9f2a2a1aa00d74de568af717d5b7ac31efdb5a52 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include "gssapiP_krb5.h"
+#include "mglueP.h"
 
 OM_uint32
 krb5_gss_indicate_mechs(minor_status, mech_set)
@@ -33,7 +34,7 @@ krb5_gss_indicate_mechs(minor_status, mech_set)
 {
    *minor_status = 0;
 
-   if (! g_copy_OID_set(gss_mech_set_krb5_both, mech_set)) {
+   if (! gssint_copy_oid_set(minor_status, gss_mech_set_krb5_both, mech_set)) {
          *mech_set     = GSS_C_NO_OID_SET;
          *minor_status = ENOMEM;
          return(GSS_S_FAILURE);
index 2ce795bb83ba42b478642002e07a76af151be3b9..6d27fd33cb64bfa59c20007f04bc78d37739c3bf 100644 (file)
@@ -918,6 +918,9 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
    } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) {
        if (!cred->prerfc_mech)
           err = 1;
+   } else if (g_OID_equal(mech_type, gss_mech_krb5_wrong)) {
+       if (!cred->rfc_mech)
+          err = 1;
    } else {
        err = 1;
    }
index 583881d8e443cc5f1377d80f771b02715a127bdc..758cfbcb0f28459520fb9a3841f9e24d06a6b275 100644 (file)
  */
 
 #include "gssapiP_krb5.h"
+#include "mglueP.h"
 
-OM_uint32 KRB5_CALLCONV
-gss_accept_sec_context(minor_status, context_handle, verifier_cred_handle,
+/** mechglue wrappers **/
+
+static OM_uint32 k5glue_acquire_cred
+(void *, 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 */
+           );
+
+static OM_uint32 k5glue_release_cred
+(void *, OM_uint32*,       /* minor_status */
+            gss_cred_id_t*    /* cred_handle */
+           );
+
+static OM_uint32 k5glue_init_sec_context
+(void *, 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 */
+           );
+
+static OM_uint32 k5glue_accept_sec_context
+(void *, 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 */
+           );
+
+static OM_uint32 k5glue_process_context_token
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            gss_buffer_t      /* token_buffer */
+           );
+
+static OM_uint32 k5glue_delete_sec_context
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t*,    /* context_handle */
+            gss_buffer_t      /* output_token */
+           );
+
+static OM_uint32 k5glue_context_time
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            OM_uint32*        /* time_rec */
+           );
+
+static OM_uint32 k5glue_sign
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            int,              /* qop_req */
+            gss_buffer_t,     /* message_buffer */
+            gss_buffer_t      /* message_token */
+           );
+
+static OM_uint32 k5glue_verify
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            gss_buffer_t,     /* message_buffer */
+            gss_buffer_t,     /* token_buffer */
+            int*              /* qop_state */
+           );
+
+static OM_uint32 k5glue_seal
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            int,              /* conf_req_flag */
+            int,              /* qop_req */
+            gss_buffer_t,     /* input_message_buffer */
+            int*,             /* conf_state */
+            gss_buffer_t      /* output_message_buffer */
+           );
+
+static OM_uint32 k5glue_unseal
+(void *, 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 */
+            int*              /* qop_state */
+           );
+
+static OM_uint32 k5glue_display_status
+(void *, OM_uint32*,       /* minor_status */
+            OM_uint32,        /* status_value */
+            int,              /* status_type */
+            gss_OID,          /* mech_type */
+            OM_uint32*,       /* message_context */
+            gss_buffer_t      /* status_string */
+           );
+
+static OM_uint32 k5glue_indicate_mechs
+(void *, OM_uint32*,       /* minor_status */
+            gss_OID_set*      /* mech_set */
+           );
+
+static OM_uint32 k5glue_compare_name
+(void *, OM_uint32*,       /* minor_status */
+            gss_name_t,       /* name1 */
+            gss_name_t,       /* name2 */
+            int*              /* name_equal */
+           );
+
+static OM_uint32 k5glue_display_name
+(void *, OM_uint32*,      /* minor_status */
+            gss_name_t,      /* input_name */
+            gss_buffer_t,    /* output_name_buffer */
+            gss_OID*         /* output_name_type */
+           );
+
+static OM_uint32 k5glue_import_name
+(void *, OM_uint32*,       /* minor_status */
+            gss_buffer_t,     /* input_name_buffer */
+            gss_OID,          /* input_name_type */
+            gss_name_t*       /* output_name */
+           );
+
+static OM_uint32 k5glue_release_name
+(void *, OM_uint32*,       /* minor_status */
+            gss_name_t*       /* input_name */
+           );
+
+static OM_uint32 k5glue_inquire_cred
+(void *, 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 */
+           );
+
+static OM_uint32 k5glue_inquire_context
+(void *, 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 */
+          );
+
+#if 0
+/* New V2 entry points */
+static OM_uint32 k5glue_get_mic
+(void *, 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 */
+          );
+
+static OM_uint32 k5glue_verify_mic
+(void *, 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 */
+          );
+
+static OM_uint32 k5glue_wrap
+(void *, 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 */
+          );
+
+static OM_uint32 k5glue_unwrap
+(void *, 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 */
+          );
+#endif
+
+static OM_uint32 k5glue_wrap_size_limit
+(void *, 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 */
+          );
+
+#if 0
+static OM_uint32 k5glue_import_name_object
+(void *, OM_uint32 *,          /* minor_status */
+           void *,                     /* input_name */
+           gss_OID,                    /* input_name_type */
+           gss_name_t *                /* output_name */
+          );
+
+static OM_uint32 k5glue_export_name_object
+(void *, OM_uint32 *,          /* minor_status */
+           gss_name_t,                 /* input_name */
+           gss_OID,                    /* desired_name_type */
+           void * *                    /* output_name */
+          );
+#endif
+
+static OM_uint32 k5glue_add_cred
+(void *, OM_uint32 *,          /* minor_status */
+           gss_cred_id_t,              /* input_cred_handle */
+           gss_name_t,                 /* desired_name */
+           gss_OID,                    /* desired_mech */
+           gss_cred_usage_t,           /* cred_usage */
+           OM_uint32,                  /* initiator_time_req */
+           OM_uint32,                  /* acceptor_time_req */
+           gss_cred_id_t *,            /* output_cred_handle */
+           gss_OID_set *,              /* actual_mechs */
+           OM_uint32 *,                /* initiator_time_rec */
+           OM_uint32 *                 /* acceptor_time_rec */
+          );
+
+static OM_uint32 k5glue_inquire_cred_by_mech
+(void *, 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 */
+          );
+
+static OM_uint32 k5glue_export_sec_context
+(void *, OM_uint32 *,          /* minor_status */
+           gss_ctx_id_t *,             /* context_handle */
+           gss_buffer_t                /* interprocess_token */
+           );
+
+static OM_uint32 k5glue_import_sec_context
+(void *, OM_uint32 *,          /* minor_status */
+           gss_buffer_t,               /* interprocess_token */
+           gss_ctx_id_t *              /* context_handle */
+           );
+
+krb5_error_code k5glue_ser_init(krb5_context);
+
+static OM_uint32 k5glue_internal_release_oid
+(void *, OM_uint32 *,          /* minor_status */
+           gss_OID *                   /* oid */
+          );
+
+static OM_uint32 k5glue_inquire_names_for_mech
+(void *, OM_uint32 *,          /* minor_status */
+           gss_OID,                    /* mechanism */
+           gss_OID_set *               /* name_types */
+          );
+
+#if 0
+static OM_uint32 k5glue_canonicalize_name
+(void *, OM_uint32  *,         /* minor_status */
+           const gss_name_t,           /* input_name */
+           const gss_OID,              /* mech_type */
+           gss_name_t *                /* output_name */
+        );
+#endif
+
+static OM_uint32 k5glue_export_name
+(void *, OM_uint32  *,         /* minor_status */
+           const gss_name_t,           /* input_name */
+           gss_buffer_t                /* exported_name */
+        );
+
+#if 0
+static OM_uint32 k5glue_duplicate_name
+(void *, OM_uint32  *,         /* minor_status */
+           const gss_name_t,           /* input_name */
+           gss_name_t *                /* dest_name */
+        );
+#endif
+
+#if 0
+static OM_uint32 k5glue_validate_cred
+(void *, OM_uint32 *,          /* minor_status */
+           gss_cred_id_t               /* cred */
+         );
+#endif
+
+/*
+ * The krb5 mechanism provides two mech OIDs; use this initializer to
+ * ensure that both dispatch tables contain identical function
+ * pointers.
+ */
+#define KRB5_GSS_CONFIG_INIT                           \
+    NULL,                                              \
+    k5glue_acquire_cred,                               \
+    k5glue_release_cred,                               \
+    k5glue_init_sec_context,                           \
+    k5glue_accept_sec_context,                         \
+    k5glue_process_context_token,                      \
+    k5glue_delete_sec_context,                         \
+    k5glue_context_time,                               \
+    k5glue_sign,                                       \
+    k5glue_verify,                                     \
+    k5glue_seal,                                       \
+    k5glue_unseal,                                     \
+    k5glue_display_status,                             \
+    k5glue_indicate_mechs,                             \
+    k5glue_compare_name,                               \
+    k5glue_display_name,                               \
+    k5glue_import_name,                                        \
+    k5glue_release_name,                               \
+    k5glue_inquire_cred,                               \
+    k5glue_add_cred,                                   \
+    k5glue_export_sec_context,                         \
+    k5glue_import_sec_context,                         \
+    k5glue_inquire_cred_by_mech,                       \
+    k5glue_inquire_names_for_mech,                     \
+    k5glue_inquire_context,                            \
+    k5glue_internal_release_oid,                       \
+    k5glue_wrap_size_limit,                            \
+    NULL,                      /* pname_to_uid */      \
+    NULL,                      /* userok */            \
+    k5glue_export_name,                                        \
+    NULL                       /* store_cred */
+
+static struct gss_config krb5_mechanism = {
+    100, "kerberos_v5",
+    { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
+    KRB5_GSS_CONFIG_INIT
+};
+
+static struct gss_config krb5_mechanism_old = {
+    200, "kerberos_v5 (pre-RFC OID)",
+    { GSS_MECH_KRB5_OLD_OID_LENGTH, GSS_MECH_KRB5_OLD_OID },
+    KRB5_GSS_CONFIG_INIT
+};
+
+static struct gss_config krb5_mechanism_wrong = {
+    300, "kerberos_v5 (wrong OID)",
+    { GSS_MECH_KRB5_WRONG_OID_LENGTH, GSS_MECH_KRB5_WRONG_OID },
+    KRB5_GSS_CONFIG_INIT
+};
+
+static gss_mechanism krb5_mech_configs[] = {
+    &krb5_mechanism, &krb5_mechanism_old, &krb5_mechanism_wrong, NULL
+};
+
+#ifdef MS_BUG_TEST
+static gss_mechanism krb5_mech_configs_hack[] = {
+    &krb5_mechanism, &krb5_mechanism_old, NULL
+}
+#endif
+
+#if 1
+#define gssint_get_mech_configs krb5_gss_get_mech_configs
+#endif
+
+gss_mechanism *
+gssint_get_mech_configs(void)
+{
+#ifdef MS_BUG_TEST
+    char *envstr = getenv("MS_FORCE_NO_MSOID");
+
+    if (envstr != NULL && strcmp(envstr, "1") == 0) {
+       return krb5_mech_configs_hack;
+    }
+#endif
+    return krb5_mech_configs;
+}
+
+static OM_uint32
+k5glue_accept_sec_context(ctx, 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)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_ctx_id_t *context_handle;
      gss_cred_id_t verifier_cred_handle;
@@ -55,9 +446,10 @@ gss_accept_sec_context(minor_status, context_handle, verifier_cred_handle,
                                      delegated_cred_handle));
 }
 
-OM_uint32 KRB5_CALLCONV
-gss_acquire_cred(minor_status, desired_name, time_req, desired_mechs,
+static OM_uint32
+k5glue_acquire_cred(ctx, minor_status, desired_name, time_req, desired_mechs,
                 cred_usage, output_cred_handle, actual_mechs, time_rec)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_name_t desired_name;
      OM_uint32 time_req;
@@ -78,11 +470,12 @@ gss_acquire_cred(minor_status, desired_name, time_req, desired_mechs,
 }
 
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_add_cred(minor_status, input_cred_handle, desired_name, desired_mech,
+static OM_uint32
+k5glue_add_cred(ctx, minor_status, input_cred_handle, desired_name, desired_mech,
             cred_usage, initiator_time_req, acceptor_time_req,
             output_cred_handle, actual_mechs, initiator_time_rec,
             acceptor_time_rec)
+    void *ctx;
     OM_uint32           *minor_status;
     gss_cred_id_t      input_cred_handle;
     gss_name_t         desired_name;
@@ -102,18 +495,22 @@ gss_add_cred(minor_status, input_cred_handle, desired_name, desired_mech,
                             acceptor_time_rec));
 }
 
+#if 0
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_add_oid_set_member(minor_status, member_oid, oid_set)
+static OM_uint32
+k5glue_add_oid_set_member(ctx, minor_status, member_oid, oid_set)
+    void *ctx;
     OM_uint32   *minor_status;
     gss_OID    member_oid;
     gss_OID_set         *oid_set;
 {
     return(generic_gss_add_oid_set_member(minor_status, member_oid, oid_set));
 }
+#endif
 
-OM_uint32 KRB5_CALLCONV
-gss_compare_name(minor_status, name1, name2, name_equal)
+static OM_uint32
+k5glue_compare_name(ctx, minor_status, name1, name2, name_equal)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_name_t name1;
      gss_name_t name2;
@@ -123,8 +520,9 @@ gss_compare_name(minor_status, name1, name2, name_equal)
                                name2, name_equal));
 }
 
-OM_uint32 KRB5_CALLCONV
-gss_context_time(minor_status, context_handle, time_rec)
+static OM_uint32
+k5glue_context_time(ctx, minor_status, context_handle, time_rec)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_ctx_id_t context_handle;
      OM_uint32 *time_rec;
@@ -133,17 +531,21 @@ gss_context_time(minor_status, context_handle, time_rec)
                                time_rec));
 }
 
+#if 0
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_create_empty_oid_set(minor_status, oid_set)
+static OM_uint32
+k5glue_create_empty_oid_set(ctx, minor_status, oid_set)
+    void *ctx;
     OM_uint32   *minor_status;
     gss_OID_set         *oid_set;
 {
     return(generic_gss_create_empty_oid_set(minor_status, oid_set));
 }
+#endif
 
-OM_uint32 KRB5_CALLCONV
-gss_delete_sec_context(minor_status, context_handle, output_token)
+static OM_uint32
+k5glue_delete_sec_context(ctx, minor_status, context_handle, output_token)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_ctx_id_t *context_handle;
      gss_buffer_t output_token;
@@ -152,8 +554,9 @@ gss_delete_sec_context(minor_status, context_handle, output_token)
                                      context_handle, output_token));
 }
 
-OM_uint32 KRB5_CALLCONV
-gss_display_name(minor_status, input_name, output_name_buffer, output_name_type)
+static OM_uint32
+k5glue_display_name(ctx, minor_status, input_name, output_name_buffer, output_name_type)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_name_t input_name;
      gss_buffer_t output_name_buffer;
@@ -163,9 +566,10 @@ gss_display_name(minor_status, input_name, output_name_buffer, output_name_type)
                                output_name_buffer, output_name_type));
 }
 
-OM_uint32 KRB5_CALLCONV
-gss_display_status(minor_status, status_value, status_type,
+static OM_uint32
+k5glue_display_status(ctx, minor_status, status_value, status_type,
                   mech_type, message_context, status_string)
+    void *ctx;
      OM_uint32 *minor_status;
      OM_uint32 status_value;
      int status_type;
@@ -179,8 +583,9 @@ gss_display_status(minor_status, status_value, status_type,
 }
 
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_export_sec_context(minor_status, context_handle, interprocess_token)
+static OM_uint32
+k5glue_export_sec_context(ctx, minor_status, context_handle, interprocess_token)
+    void *ctx;
      OM_uint32          *minor_status;
      gss_ctx_id_t       *context_handle;
      gss_buffer_t      interprocess_token;
@@ -190,10 +595,12 @@ gss_export_sec_context(minor_status, context_handle, interprocess_token)
                                      interprocess_token));
 }
 
+#if 0
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_get_mic(minor_status, context_handle, qop_req,
+static OM_uint32
+k5glue_get_mic(ctx, minor_status, context_handle, qop_req,
            message_buffer, message_token)
+    void *ctx;
      OM_uint32          *minor_status;
      gss_ctx_id_t      context_handle;
      gss_qop_t         qop_req;
@@ -203,27 +610,32 @@ gss_get_mic(minor_status, context_handle, qop_req,
     return(krb5_gss_get_mic(minor_status, context_handle,
                            qop_req, message_buffer, message_token));
 }
+#endif
 
-OM_uint32 KRB5_CALLCONV
-gss_import_name(minor_status, input_name_buffer, input_name_type, output_name)
+static OM_uint32
+k5glue_import_name(ctx, minor_status, input_name_buffer, input_name_type, output_name)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_buffer_t input_name_buffer;
      gss_OID input_name_type;
      gss_name_t *output_name;
 {
+#if 0
     OM_uint32 err;
     err = gssint_initialize_library();
     if (err) {
        *minor_status = err;
        return GSS_S_FAILURE;
     }
+#endif
     return(krb5_gss_import_name(minor_status, input_name_buffer,
                                input_name_type, output_name));
 }
 
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_import_sec_context(minor_status, interprocess_token, context_handle)
+static OM_uint32
+k5glue_import_sec_context(ctx, minor_status, interprocess_token, context_handle)
+    void *ctx;
      OM_uint32          *minor_status;
      gss_buffer_t      interprocess_token;
      gss_ctx_id_t       *context_handle;
@@ -233,19 +645,21 @@ gss_import_sec_context(minor_status, interprocess_token, context_handle)
                                      context_handle));
 }
 
-OM_uint32 KRB5_CALLCONV
-gss_indicate_mechs(minor_status, mech_set)
+static OM_uint32
+k5glue_indicate_mechs(ctx, minor_status, mech_set)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_OID_set *mech_set;
 {
    return(krb5_gss_indicate_mechs(minor_status, mech_set));
 }
 
-OM_uint32 KRB5_CALLCONV
-gss_init_sec_context(minor_status, claimant_cred_handle, context_handle,
+static OM_uint32
+k5glue_init_sec_context(ctx, 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)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_cred_id_t claimant_cred_handle;
      gss_ctx_id_t *context_handle;
@@ -268,10 +682,11 @@ gss_init_sec_context(minor_status, claimant_cred_handle, context_handle,
                                    time_rec));
 }
 
-OM_uint32 KRB5_CALLCONV
-gss_inquire_context(minor_status, context_handle, initiator_name, acceptor_name,
+static OM_uint32
+k5glue_inquire_context(ctx, minor_status, context_handle, initiator_name, acceptor_name,
                    lifetime_rec, mech_type, ret_flags,
                    locally_initiated, open)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_ctx_id_t context_handle;
      gss_name_t *initiator_name;
@@ -288,9 +703,10 @@ gss_inquire_context(minor_status, context_handle, initiator_name, acceptor_name,
                                   open));
 }
 
-OM_uint32 KRB5_CALLCONV
-gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret,
+static OM_uint32
+k5glue_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret,
                 cred_usage, mechanisms)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_cred_id_t cred_handle;
      gss_name_t *name;
@@ -303,9 +719,10 @@ gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret,
 }
 
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name,
+static OM_uint32
+k5glue_inquire_cred_by_mech(ctx, minor_status, cred_handle, mech_type, name,
                         initiator_lifetime, acceptor_lifetime, cred_usage)
+    void *ctx;
      OM_uint32          *minor_status;
      gss_cred_id_t     cred_handle;
      gss_OID           mech_type;
@@ -320,8 +737,9 @@ gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name,
 }
 
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_inquire_names_for_mech(minor_status, mechanism, name_types)
+static OM_uint32
+k5glue_inquire_names_for_mech(ctx, minor_status, mechanism, name_types)
+    void *ctx;
     OM_uint32   *minor_status;
     gss_OID    mechanism;
     gss_OID_set         *name_types;
@@ -331,18 +749,22 @@ gss_inquire_names_for_mech(minor_status, mechanism, name_types)
                                           name_types));
 }
 
+#if 0
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_oid_to_str(minor_status, oid, oid_str)
+static OM_uint32
+k5glue_oid_to_str(ctx, minor_status, oid, oid_str)
+    void *ctx;
     OM_uint32           *minor_status;
     gss_OID            oid;
     gss_buffer_t       oid_str;
 {
     return(generic_gss_oid_to_str(minor_status, oid, oid_str));
 }
+#endif
 
-OM_uint32 KRB5_CALLCONV
-gss_process_context_token(minor_status, context_handle, token_buffer)
+static OM_uint32
+k5glue_process_context_token(ctx, minor_status, context_handle, token_buffer)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_ctx_id_t context_handle;
      gss_buffer_t token_buffer;
@@ -351,52 +773,62 @@ gss_process_context_token(minor_status, context_handle, token_buffer)
                                         context_handle, token_buffer));
 }
 
-OM_uint32 KRB5_CALLCONV
-gss_release_cred(minor_status, cred_handle)
+static OM_uint32
+k5glue_release_cred(ctx, minor_status, cred_handle)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_cred_id_t *cred_handle;
 {
    return(krb5_gss_release_cred(minor_status, cred_handle));
 }
 
-OM_uint32 KRB5_CALLCONV
-gss_release_name(minor_status, input_name)
+static OM_uint32
+k5glue_release_name(ctx, minor_status, input_name)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_name_t *input_name;
 {
    return(krb5_gss_release_name(minor_status, input_name));
 }
 
-OM_uint32 KRB5_CALLCONV
-gss_release_buffer(minor_status, buffer)
+#if 0
+static OM_uint32
+k5glue_release_buffer(ctx, minor_status, buffer)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_buffer_t buffer;
 {
    return(generic_gss_release_buffer(minor_status,
                                     buffer));
 }
+#endif
 
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_release_oid(minor_status, oid)
+static OM_uint32
+k5glue_internal_release_oid(ctx, minor_status, oid)
+    void *ctx;
      OM_uint32  *minor_status;
      gss_OID    *oid;
 {
-    return(krb5_gss_release_oid(minor_status, oid));
+    return(krb5_gss_internal_release_oid(minor_status, oid));
 }
 
-OM_uint32 KRB5_CALLCONV
-gss_release_oid_set(minor_status, set)
+#if 0
+static OM_uint32
+k5glue_release_oid_set(ctx, minor_status, set)
+    void *ctx;
      OM_uint32 * minor_status;
      gss_OID_set *set;
 {
    return(generic_gss_release_oid_set(minor_status, set));
 }
+#endif
 
 /* V1 only */
-OM_uint32 KRB5_CALLCONV
-gss_seal(minor_status, context_handle, conf_req_flag, qop_req,
+static OM_uint32
+k5glue_seal(ctx, minor_status, context_handle, conf_req_flag, qop_req,
         input_message_buffer, conf_state, output_message_buffer)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_ctx_id_t context_handle;
      int conf_req_flag;
@@ -410,10 +842,11 @@ gss_seal(minor_status, context_handle, conf_req_flag, qop_req,
                        conf_state, output_message_buffer));
 }
 
-OM_uint32 KRB5_CALLCONV
-gss_sign(minor_status, context_handle,
+static OM_uint32
+k5glue_sign(ctx, minor_status, context_handle,
              qop_req, message_buffer, 
              message_token)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_ctx_id_t context_handle;
      int qop_req;
@@ -424,10 +857,12 @@ gss_sign(minor_status, context_handle,
                        qop_req, message_buffer, message_token));
 }
 
+#if 0
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_verify_mic(minor_status, context_handle,
+static OM_uint32
+k5glue_verify_mic(ctx, minor_status, context_handle,
               message_buffer, token_buffer, qop_state)
+    void *ctx;
      OM_uint32          *minor_status;
      gss_ctx_id_t      context_handle;
      gss_buffer_t      message_buffer;
@@ -439,9 +874,10 @@ gss_verify_mic(minor_status, context_handle,
 }
 
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_wrap(minor_status, context_handle, conf_req_flag, qop_req,
+static OM_uint32
+k5glue_wrap(ctx, minor_status, context_handle, conf_req_flag, qop_req,
         input_message_buffer, conf_state, output_message_buffer)
+    void *ctx;
     OM_uint32           *minor_status;
     gss_ctx_id_t       context_handle;
     int                        conf_req_flag;
@@ -456,8 +892,9 @@ gss_wrap(minor_status, context_handle, conf_req_flag, qop_req,
 }
 
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_str_to_oid(minor_status, oid_str, oid)
+static OM_uint32
+k5glue_str_to_oid(ctx, minor_status, oid_str, oid)
+    void *ctx;
     OM_uint32           *minor_status;
     gss_buffer_t       oid_str;
     gss_OID             *oid;
@@ -466,8 +903,9 @@ gss_str_to_oid(minor_status, oid_str, oid)
 }
 
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_test_oid_set_member(minor_status, member, set, present)
+static OM_uint32
+k5glue_test_oid_set_member(ctx, minor_status, member, set, present)
+    void *ctx;
     OM_uint32   *minor_status;
     gss_OID    member;
     gss_OID_set        set;
@@ -476,11 +914,13 @@ gss_test_oid_set_member(minor_status, member, set, present)
     return(generic_gss_test_oid_set_member(minor_status, member, set,
                                           present));
 }
+#endif
 
 /* V1 only */
-OM_uint32 KRB5_CALLCONV
-gss_unseal(minor_status, context_handle, input_message_buffer,
+static OM_uint32
+k5glue_unseal(ctx, minor_status, context_handle, input_message_buffer,
           output_message_buffer, conf_state, qop_state)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_ctx_id_t context_handle;
      gss_buffer_t input_message_buffer;
@@ -493,10 +933,12 @@ gss_unseal(minor_status, context_handle, input_message_buffer,
                          conf_state, qop_state));
 }
 
+#if 0
 /* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_unwrap(minor_status, context_handle, input_message_buffer, 
+static OM_uint32
+k5glue_unwrap(ctx, minor_status, context_handle, input_message_buffer, 
           output_message_buffer, conf_state, qop_state)
+    void *ctx;
     OM_uint32           *minor_status;
     gss_ctx_id_t       context_handle;
     gss_buffer_t       input_message_buffer;
@@ -507,11 +949,13 @@ gss_unwrap(minor_status, context_handle, input_message_buffer,
     return(krb5_gss_unwrap(minor_status, context_handle, input_message_buffer,
                           output_message_buffer, conf_state, qop_state));
 }
+#endif
 
 /* V1 only */
-OM_uint32 KRB5_CALLCONV
-gss_verify(minor_status, context_handle, message_buffer,
+static OM_uint32
+k5glue_verify(ctx, minor_status, context_handle, message_buffer,
           token_buffer, qop_state)
+    void *ctx;
      OM_uint32 *minor_status;
      gss_ctx_id_t context_handle;
      gss_buffer_t message_buffer;
@@ -526,9 +970,10 @@ gss_verify(minor_status, context_handle, message_buffer,
 }
 
 /* V2 interface */
-OM_uint32 KRB5_CALLCONV
-gss_wrap_size_limit(minor_status, context_handle, conf_req_flag,
+static OM_uint32
+k5glue_wrap_size_limit(ctx, minor_status, context_handle, conf_req_flag,
                    qop_req, req_output_size, max_input_size)
+    void *ctx;
     OM_uint32           *minor_status;
     gss_ctx_id_t       context_handle;
     int                        conf_req_flag;
@@ -541,9 +986,11 @@ gss_wrap_size_limit(minor_status, context_handle, conf_req_flag,
                                   req_output_size, max_input_size));
 }
 
+#if 0
 /* V2 interface */
-OM_uint32 KRB5_CALLCONV
-gss_canonicalize_name(minor_status, input_name, mech_type, output_name)
+static OM_uint32
+k5glue_canonicalize_name(ctx, minor_status, input_name, mech_type, output_name)
+    void *ctx;
        OM_uint32  *minor_status;
        const gss_name_t input_name;
        const gss_OID mech_type;
@@ -552,11 +999,12 @@ gss_canonicalize_name(minor_status, input_name, mech_type, output_name)
        return krb5_gss_canonicalize_name(minor_status, input_name,
                                          mech_type, output_name);
 }
-
+#endif
 
 /* V2 interface */
-OM_uint32 KRB5_CALLCONV
-gss_export_name(minor_status, input_name, exported_name)
+static OM_uint32
+k5glue_export_name(ctx, minor_status, input_name, exported_name)
+    void *ctx;
        OM_uint32  *minor_status;
        const gss_name_t input_name;
        gss_buffer_t exported_name;
@@ -564,15 +1012,96 @@ gss_export_name(minor_status, input_name, exported_name)
        return krb5_gss_export_name(minor_status, input_name, exported_name);
 }
 
+#if 0
 /* V2 interface */
-OM_uint32 KRB5_CALLCONV
-gss_duplicate_name(minor_status, input_name, dest_name)
+static OM_uint32
+k5glue_duplicate_name(ctx, minor_status, input_name, dest_name)
+    void *ctx;
        OM_uint32  *minor_status;
        const gss_name_t input_name;
        gss_name_t *dest_name;
 {
        return krb5_gss_duplicate_name(minor_status, input_name, dest_name);
 }
+#endif
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_get_tkt_flags(
+    OM_uint32 *minor_status,
+    gss_ctx_id_t context_handle,
+    krb5_flags *ticket_flags)
+{
+    gss_union_ctx_id_t uctx;
+
+    uctx = (gss_union_ctx_id_t)context_handle;
+    if (!g_OID_equal(uctx->mech_type, &krb5_mechanism.mech_type) &&
+       !g_OID_equal(uctx->mech_type, &krb5_mechanism_old.mech_type))
+       return GSS_S_BAD_MECH;
+    return gss_krb5int_get_tkt_flags(minor_status, uctx->internal_ctx_id,
+                                    ticket_flags);
+}
+
+OM_uint32 KRB5_CALLCONV 
+gss_krb5_copy_ccache(
+    OM_uint32 *minor_status,
+    gss_cred_id_t cred_handle,
+    krb5_ccache out_ccache)
+{
+    gss_union_cred_t ucred;
+    gss_cred_id_t mcred;
+
+    ucred = (gss_union_cred_t)cred_handle;
+
+    mcred = gssint_get_mechanism_cred(ucred, &krb5_mechanism.mech_type);
+    if (mcred != GSS_C_NO_CREDENTIAL)
+       return gss_krb5int_copy_ccache(minor_status, mcred, out_ccache);
+
+    mcred = gssint_get_mechanism_cred(ucred, &krb5_mechanism_old.mech_type);
+    if (mcred != GSS_C_NO_CREDENTIAL)
+       return gss_krb5int_copy_ccache(minor_status, mcred, out_ccache);
+
+    return GSS_S_DEFECTIVE_CREDENTIAL;
+}
+
+/* XXX need to delete mechglue ctx too */
+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)
+{
+    gss_union_ctx_id_t uctx;
+
+    uctx = (gss_union_ctx_id_t)*context_handle;
+    if (!g_OID_equal(uctx->mech_type, &krb5_mechanism.mech_type) &&
+       !g_OID_equal(uctx->mech_type, &krb5_mechanism_old.mech_type))
+       return GSS_S_BAD_MECH;
+    return gss_krb5int_export_lucid_sec_context(minor_status,
+                                               &uctx->internal_ctx_id,
+                                               version, kctx);
+}
 
+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)
+{
+    gss_union_cred_t ucred;
+    gss_cred_id_t mcred;
+
+    ucred = (gss_union_cred_t)cred;
+    mcred = gssint_get_mechanism_cred(ucred, &krb5_mechanism.mech_type);
+    if (mcred != GSS_C_NO_CREDENTIAL)
+       return gss_krb5int_set_allowable_enctypes(minor_status, mcred,
+                                                 num_ktypes, ktypes);
 
+    mcred = gssint_get_mechanism_cred(ucred, &krb5_mechanism_old.mech_type);
+    if (mcred != GSS_C_NO_CREDENTIAL)
+       return gss_krb5int_set_allowable_enctypes(minor_status, mcred,
+                                                 num_ktypes, ktypes);
 
+    return GSS_S_DEFECTIVE_CREDENTIAL;
+}
index ac81fff60391fdb7fd1ce55d6c05e2a6707c1d4c..a1679a93d5600f42ae8935b83dc6d46607ec29ac 100644 (file)
@@ -60,7 +60,7 @@ make_external_lucid_ctx_v1(
  */
 
 OM_uint32 KRB5_CALLCONV
-gss_krb5_export_lucid_sec_context(
+gss_krb5int_export_lucid_sec_context(
     OM_uint32          *minor_status,
     gss_ctx_id_t       *context_handle,
     OM_uint32          version,
index 01921c02f7af7f8b9917b544e5cc32d5dd8a8de2..dcb1fe97af1cd1a49d2865b1fc0683391b0cd6b4 100644 (file)
  */
 #include "gssapiP_krb5.h"
 
-static OM_uint32 krb5_gss_internal_release_oid (OM_uint32 *, /* minor_status */
-                                               gss_OID * /* oid */
+OM_uint32 krb5_gss_internal_release_oid (OM_uint32 *, /* minor_status */
+                                        gss_OID * /* oid */
     );
 
+#if 0
 OM_uint32
 krb5_gss_release_oid(minor_status, oid)
     OM_uint32  *minor_status;
@@ -58,8 +59,9 @@ krb5_gss_release_oid(minor_status, oid)
        return(GSS_S_COMPLETE);
     }
 }
+#endif
 
-static OM_uint32
+OM_uint32
 krb5_gss_internal_release_oid(minor_status, oid)
     OM_uint32  *minor_status;
     gss_OID    *oid;
@@ -71,6 +73,7 @@ krb5_gss_internal_release_oid(minor_status, oid)
    
     if ((*oid != gss_mech_krb5) &&
        (*oid != gss_mech_krb5_old) &&
+       (*oid != gss_mech_krb5_wrong) &&
        (*oid != gss_nt_krb5_name) &&
        (*oid != gss_nt_krb5_principal)) {
        /* We don't know about this OID */
index 2bc2090fa004c097b5aa6b95b4a632786ba923d9..f573d7dfcc54c1353b15e3a34163a6b8a7cc63b4 100644 (file)
 #include "gssapi_krb5.h"
 
 OM_uint32 KRB5_CALLCONV
-gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, 
-                                gss_cred_id_t cred_handle,
-                               OM_uint32 num_ktypes,
-                               krb5_enctype *ktypes)
+gss_krb5int_set_allowable_enctypes(OM_uint32 *minor_status, 
+                                  gss_cred_id_t cred_handle,
+                                  OM_uint32 num_ktypes,
+                                  krb5_enctype *ktypes)
 {
     int i;
     krb5_enctype * new_ktypes;
index afb6ef35f246d03f51f37a2ee1393c196a3b91cf..d757de428291ffb1bab0fe89a008d19442a9f2d6 100644 (file)
@@ -1,8 +1,8 @@
-thisconfigdir=..
+thisconfigdir=../../..
 myfulldir=lib/gssapi/mechglue
-mydir=.
+mydir=mechglue
 BUILDTOP=$(REL)..$(S)..$(S)..
-LOCALINCLUDES = -I. -I$(srcdir)
+LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic
 DEFS=
 
 ##DOSBUILDTOP = ..\..\..
@@ -10,111 +10,86 @@ DEFS=
 
 ##DOS##DLL_EXP_TYPE=GSS
 
-LIBDONE=DONE
-LIB_SUBDIRS=.
-DEPLIBS=
-SHLIB_LDFLAGS= $(LDFLAGS) @SHLIB_RPATH_DIRS@ \
-       $(LD_UNRESOLVED_PREFIX)krb5_gss_initialize
-
-
-SHLIB_LIBDIRS= @SHLIB_LIBDIRS@
-
-SRCS   = $(srcdir)/g_acquire_cred.c \
-         $(srcdir)/g_rel_cred.c \
-         $(srcdir)/g_init_sec_context.c \
-         $(srcdir)/g_accept_sec_context.c \
-         $(srcdir)/g_process_context.c \
-         $(srcdir)/g_delete_sec_context.c \
-         $(srcdir)/g_imp_sec_context.c \
-         $(srcdir)/g_exp_sec_context.c \
-         $(srcdir)/g_context_time.c \
-         $(srcdir)/g_sign.c \
-         $(srcdir)/g_verify.c \
-         $(srcdir)/g_seal.c \
-         $(srcdir)/g_unseal.c \
-         $(srcdir)/g_dsp_status.c \
-         $(srcdir)/g_indicate_mechs.c \
-         $(srcdir)/g_compare_name.c \
-         $(srcdir)/g_dsp_name.c \
-         $(srcdir)/g_imp_name.c \
-         $(srcdir)/g_rel_name.c \
-         $(srcdir)/g_rel_buffer.c \
-         $(srcdir)/g_rel_oid_set.c \
-         $(srcdir)/g_oid_ops.c \
-         $(srcdir)/g_inq_cred.c \
-         $(srcdir)/g_inq_context.c \
-         $(srcdir)/g_inq_names.c \
-         $(srcdir)/g_initialize.c \
-         $(srcdir)/g_glue.c \
-         $(srcdir)/gssd_pname_to_uid.c \
-         $(srcdir)/gen_oids.c \
-         $(srcdir)/oid_ops.c \
-         $(srcdir)/g_mechname.c 
-
-OBJS   = $(OUTPRE)g_acquire_cred.$(OBJEXT) \
-         $(OUTPRE)g_rel_cred.$(OBJEXT) \
-         $(OUTPRE)g_init_sec_context.$(OBJEXT) \
-         $(OUTPRE)g_accept_sec_context.$(OBJEXT) \
-         $(OUTPRE)g_process_context.$(OBJEXT) \
-         $(OUTPRE)g_delete_sec_context.$(OBJEXT) \
-         $(OUTPRE)g_imp_sec_context.$(OBJEXT) \
-         $(OUTPRE)g_exp_sec_context.$(OBJEXT) \
-         $(OUTPRE)g_context_time.$(OBJEXT) \
-         $(OUTPRE)g_sign.$(OBJEXT) \
-         $(OUTPRE)g_verify.$(OBJEXT) \
-         $(OUTPRE)g_seal.$(OBJEXT) \
-         $(OUTPRE)g_unseal.$(OBJEXT) \
-         $(OUTPRE)g_dsp_status.$(OBJEXT) \
-         $(OUTPRE)g_indicate_mechs.$(OBJEXT) \
-         $(OUTPRE)g_compare_name.$(OBJEXT) \
-         $(OUTPRE)g_dsp_name.$(OBJEXT) \
-         $(OUTPRE)g_imp_name.$(OBJEXT) \
-         $(OUTPRE)g_rel_name.$(OBJEXT) \
-         $(OUTPRE)g_rel_buffer.$(OBJEXT) \
-         $(OUTPRE)g_rel_oid_set.$(OBJEXT) \
-         $(OUTPRE)g_oid_ops.$(OBJEXT) \
-         $(OUTPRE)g_inq_cred.$(OBJEXT) \
-         $(OUTPRE)g_inq_context.$(OBJEXT) \
-         $(OUTPRE)g_inq_names.$(OBJEXT) \
-         $(OUTPRE)g_initialize.$(OBJEXT) \
-         $(OUTPRE)g_glue.$(OBJEXT) \
-         $(OUTPRE)gssd_pname_to_uid.$(OBJEXT) \
-         $(OUTPRE)gen_oids.$(OBJEXT) \
-         $(OUTPRE)oid_ops.$(OBJEXT) \
-         $(OUTPRE)g_mechname.$(OBJEXT)
+SRCS = \
+       $(srcdir)/g_accept_sec_context.c \
+       $(srcdir)/g_acquire_cred.c \
+       $(srcdir)/g_canon_name.c \
+       $(srcdir)/g_compare_name.c \
+       $(srcdir)/g_context_time.c \
+       $(srcdir)/g_delete_sec_context.c \
+       $(srcdir)/g_dsp_name.c \
+       $(srcdir)/g_dsp_status.c \
+       $(srcdir)/g_dup_name.c \
+       $(srcdir)/g_exp_sec_context.c \
+       $(srcdir)/g_export_name.c \
+       $(srcdir)/g_glue.c \
+       $(srcdir)/g_imp_name.c \
+       $(srcdir)/g_imp_sec_context.c \
+       $(srcdir)/g_init_sec_context.c \
+       $(srcdir)/g_initialize.c \
+       $(srcdir)/g_inq_context.c \
+       $(srcdir)/g_inq_cred.c \
+       $(srcdir)/g_inq_names.c \
+       $(srcdir)/g_mechname.c \
+       $(srcdir)/g_oid_ops.c \
+       $(srcdir)/g_process_context.c \
+       $(srcdir)/g_rel_buffer.c \
+       $(srcdir)/g_rel_cred.c \
+       $(srcdir)/g_rel_name.c \
+       $(srcdir)/g_rel_oid_set.c \
+       $(srcdir)/g_seal.c \
+       $(srcdir)/g_sign.c \
+       $(srcdir)/g_store_cred.c \
+       $(srcdir)/g_unseal.c \
+       $(srcdir)/g_userok.c \
+       $(srcdir)/g_utils.c \
+       $(srcdir)/g_verify.c \
+       $(srcdir)/gssd_pname_to_uid.c \
+       $(srcdir)/oid_ops.c
+
+STLIBOBJS = \
+       g_accept_sec_context.o \
+       g_acquire_cred.o \
+       g_canon_name.o \
+       g_compare_name.o \
+       g_context_time.o \
+       g_delete_sec_context.o \
+       g_dsp_name.o \
+       g_dsp_status.o \
+       g_dup_name.o \
+       g_exp_sec_context.o \
+       g_export_name.o \
+       g_glue.o \
+       g_imp_name.o \
+       g_imp_sec_context.o \
+       g_init_sec_context.o \
+       g_initialize.o \
+       g_inq_context.o \
+       g_inq_cred.o \
+       g_inq_names.o \
+       g_mechname.o \
+       g_oid_ops.o \
+       g_process_context.o \
+       g_rel_buffer.o \
+       g_rel_cred.o \
+       g_rel_name.o \
+       g_rel_oid_set.o \
+       g_seal.o \
+       g_sign.o \
+       g_store_cred.o \
+       g_unseal.o \
+       g_userok.o \
+       g_utils.o \
+       g_verify.o \
+       gssd_pname_to_uid.o \
+       oid_ops.o
 
 EHDRDIR= $(BUILDTOP)$(S)include$(S)gssapi
 EXPORTED_HEADERS = mechglue.h
 
-all:: all-$(WHAT) 
-
-all-unix:: shared includes $(OBJS)
-
-all-windows:: includes $(OBJS)
-       if not exist $(EHDRDIR)\nul mkdir $(EHDRDIR)
-       copy mechglue.h $(EHDRDIR)
-
-shared:
-       mkdir shared
+all-unix:: all-libobjs
 
-libgssapi.$(STEXT): $(OBJS)
-       $(RM) $@
-       $(ARADD) $@ $(OBJS)
-       $(RANLIB) $@
-
-
-#libgssapi.$(LIBEXT): $(OBJS)
-#      $(ARCHIVE) $@ $(OBJS)
-#      $(RANLIB) $@
-
-clean:: clean-$(WHAT)
-
-clean-unix::
-       $(RM) shared/*
-
-clean-windows::
-       $(RM) $(EHDRDIR)\gssapi.h $(EHDRDIR)\gssapi_generic.h
-       if exist $(EHDRDIR)\nul rmdir $(EHDRDIR)
+clean-unix:: clean-libobjs
 
 # Krb5InstallHeaders($(EXPORTED_HEADERS), $(KRB5_INCDIR)/krb5)
 install::
@@ -124,3 +99,5 @@ install::
        done
 
 includes::
+
+# @libobj_frag@
index 8cc752fe7415060494a3f16404e63b3ec8e5d279..e0be150937ab73145358573bf584cb4cc9ba3fb7 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_accept_sec_context.c 1.19     95/08/07 SMI" */
+/* #pragma ident       "@(#)g_accept_sec_context.c     1.19    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -44,7 +44,7 @@ gss_accept_sec_context (minor_status,
                         output_token,
                         ret_flags,
                         time_rec,
-                        delegated_cred_handle)
+                        d_cred)
 
 OM_uint32 *            minor_status;
 gss_ctx_id_t *         context_handle;
@@ -56,23 +56,39 @@ gss_OID *           mech_type;
 gss_buffer_t           output_token;
 OM_uint32 *            ret_flags;
 OM_uint32 *            time_rec;
-gss_cred_id_t *                delegated_cred_handle;
+gss_cred_id_t *                d_cred;
 
 {
     OM_uint32          status, temp_status, temp_minor_status;
     gss_union_ctx_id_t union_ctx_id;
     gss_union_cred_t   union_cred;
     gss_cred_id_t      input_cred_handle = GSS_C_NO_CREDENTIAL;
-    gss_name_t         internal_name;
+    gss_cred_id_t      tmp_d_cred = GSS_C_NO_CREDENTIAL;
+    gss_name_t         internal_name = GSS_C_NO_NAME;
+    gss_name_t         tmp_src_name = GSS_C_NO_NAME;
     gss_OID_desc       token_mech_type_desc;
     gss_OID            token_mech_type = &token_mech_type_desc;
     gss_mechanism      mech;
     
-    gss_initialize();
+    /* check parameters first */
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+    if (context_handle == NULL || output_token == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    /* clear optional fields */
+    output_token->value = NULL;
+    output_token->length = 0;
+    if (src_name)
+       *src_name = NULL;
 
-    if (context_handle == NULL)
-       return GSS_S_NO_CONTEXT;
+    if (mech_type)
+       *mech_type = NULL;
 
+    if (d_cred)
+       *d_cred = NULL;
     /*
      * if context_handle is GSS_C_NO_CONTEXT, allocate a union context
      * descriptor to hold the mech type information as well as the
@@ -82,42 +98,33 @@ gss_cred_id_t *             delegated_cred_handle;
     
     if(*context_handle == GSS_C_NO_CONTEXT) {
        
+       if (GSS_EMPTY_BUFFER(input_token_buffer))
+           return (GSS_S_CALL_INACCESSIBLE_READ);
+
        /* Get the token mech type */
-       status = __gss_get_mech_type(token_mech_type, input_token_buffer);
+       status = gssint_get_mech_type(token_mech_type, input_token_buffer);
        if (status)
            return status;
 
        status = GSS_S_FAILURE;
        union_ctx_id = (gss_union_ctx_id_t)
            malloc(sizeof(gss_union_ctx_id_desc));
-       if (!union_ctx_id) {
-           *minor_status = ENOMEM;
-           goto error_out;
-       }
+       if (!union_ctx_id)
+           return (GSS_S_FAILURE);
 
-       union_ctx_id->mech_type = (gss_OID) malloc(sizeof(gss_OID_desc));
-       if (!union_ctx_id->mech_type) {
-           *minor_status = ENOMEM;
-           goto error_out;
+       union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT;
+       status = generic_gss_copy_oid(&temp_minor_status,
+                                     token_mech_type,
+                                     &union_ctx_id->mech_type);
+       if (status != GSS_S_COMPLETE) {
+           free(union_ctx_id);
+           return (status);
        }
-       
-       union_ctx_id->mech_type->elements = (void *)
-           malloc(token_mech_type->length);
-       if (!union_ctx_id->mech_type->elements) {
-           *minor_status = ENOMEM;
-           goto error_out;
-       }
-
-       union_ctx_id->mech_type->length = token_mech_type->length;
-       memcpy(union_ctx_id->mech_type->elements,
-              token_mech_type->elements,
-              token_mech_type->length);
 
-       /* copy the supplied context handle */
-
-       union_ctx_id->internal_ctx_id = *context_handle;
+       /* set the new context handle to caller's data */
+       *context_handle = (gss_ctx_id_t)union_ctx_id;
     } else {
-       union_ctx_id = *context_handle;
+       union_ctx_id = (gss_union_ctx_id_t)*context_handle;
        token_mech_type = union_ctx_id->mech_type;
     }
     
@@ -127,14 +134,14 @@ gss_cred_id_t *           delegated_cred_handle;
      * use the default credential.
      */
     union_cred = (gss_union_cred_t) verifier_cred_handle;
-    input_cred_handle = __gss_get_mechanism_cred(union_cred, token_mech_type);
+    input_cred_handle = gssint_get_mechanism_cred(union_cred, token_mech_type);
     
     /*
      * now select the approprate underlying mechanism routine and
      * call it.
      */
     
-    mech = __gss_get_mechanism (token_mech_type);
+    mech = gssint_get_mechanism (token_mech_type);
     if (mech && mech->gss_accept_sec_context) {
 
            status = mech->gss_accept_sec_context(
@@ -149,7 +156,7 @@ gss_cred_id_t *             delegated_cred_handle;
                                                  output_token,
                                                  ret_flags,
                                                  time_rec,
-                                                 delegated_cred_handle);
+                                       d_cred ? &tmp_d_cred : NULL);
 
            /* If there's more work to do, keep going... */
            if (status == GSS_S_CONTINUE_NEEDED)
@@ -166,36 +173,140 @@ gss_cred_id_t *          delegated_cred_handle;
             * then call gss_import_name() to create
             * the union name struct cast to src_name
             */
-           if (src_name != NULL && status == GSS_S_COMPLETE) {
-               temp_status = __gss_convert_name_to_union_name(
-                      &temp_minor_status, mech, internal_name, src_name);
+           if (internal_name != NULL) {
+               temp_status = gssint_convert_name_to_union_name(
+                      &temp_minor_status, mech,
+                      internal_name, &tmp_src_name);
                if (temp_status != GSS_S_COMPLETE) {
-                   if (minor_status)
-                       *minor_status = temp_minor_status;
-                   gss_release_buffer(&temp_minor_status, output_token);
-                   __gss_release_internal_name(&temp_minor_status,
-                                         &mech->mech_type, &internal_name);
+                   *minor_status = temp_minor_status;
+                   if (output_token->length)
+                       (void) gss_release_buffer(&temp_minor_status,
+                                                 output_token);
+                   if (internal_name != GSS_C_NO_NAME)
+                       mech->gss_release_name(
+                           mech->context,
+                           &temp_minor_status,
+                           &internal_name);
                    return (temp_status);
                }
+               if (src_name != NULL) {
+                   *src_name = tmp_src_name;
+               }
+           } else if (src_name != NULL) {
+               *src_name = GSS_C_NO_NAME;
+           }
+
+           /* Ensure we're returning correct creds format */
+           if ((ret_flags && GSS_C_DELEG_FLAG) &&
+               tmp_d_cred != GSS_C_NO_CREDENTIAL) {
+               gss_union_cred_t d_u_cred = NULL;
+
+               d_u_cred = malloc(sizeof (gss_union_cred_desc));
+               if (d_u_cred == NULL) {
+                   status = GSS_S_FAILURE;
+                   goto error_out;
+               }
+               (void) memset(d_u_cred, 0,
+                             sizeof (gss_union_cred_desc));
+
+               d_u_cred->count = 1;
+
+               status = generic_gss_copy_oid(&temp_minor_status,
+                                             token_mech_type,
+                                             &d_u_cred->mechs_array);
+
+               if (status != GSS_S_COMPLETE) {
+                   free(d_u_cred);
+                   goto error_out;
+               }
+
+               d_u_cred->cred_array = malloc(sizeof (gss_cred_id_t));
+               if (d_u_cred->cred_array != NULL) {
+                   d_u_cred->cred_array[0] = tmp_d_cred;
+               } else {
+                   free(d_u_cred);
+                   status = GSS_S_FAILURE;
+                   goto error_out;
+               }
+
+               if (status != GSS_S_COMPLETE) {
+                   free(d_u_cred->cred_array);
+                   free(d_u_cred);
+                   goto error_out;
+               }
+
+               internal_name = GSS_C_NO_NAME;
+
+               d_u_cred->auxinfo.creation_time = time(0);
+               d_u_cred->auxinfo.time_rec = 0;
+
+               if (mech->gss_inquire_cred) {
+                   status = mech->gss_inquire_cred(mech->context,
+                                                   minor_status,
+                                                   tmp_d_cred,
+                                                   &internal_name,
+                                                   &d_u_cred->auxinfo.time_rec,
+                                                   &d_u_cred->auxinfo.cred_usage,
+                                                   NULL);
+               }
+
+               if (internal_name != NULL) {
+                   temp_status = gssint_convert_name_to_union_name(
+                       &temp_minor_status, mech,
+                       internal_name, &tmp_src_name);
+                   if (temp_status != GSS_S_COMPLETE) {
+                       *minor_status = temp_minor_status;
+                       if (output_token->length)
+                           (void) gss_release_buffer(
+                               &temp_minor_status,
+                               output_token);
+                       free(d_u_cred->cred_array);
+                       free(d_u_cred);
+                       return (temp_status);
+                   }
+               }
+
+               if (tmp_src_name != NULL) {
+                   status = gss_display_name(
+                       &temp_minor_status,
+                       tmp_src_name,
+                       &d_u_cred->auxinfo.name,
+                       &d_u_cred->auxinfo.name_type);
+               }
+
+               *d_cred = (gss_cred_id_t)d_u_cred;
            }
 
-       if(*context_handle == GSS_C_NO_CONTEXT)
-           *context_handle = (gss_ctx_id_t *) union_ctx_id;
+           if (src_name == NULL && tmp_src_name != NULL)
+               (void) gss_release_name(&temp_minor_status,
+                                       &tmp_src_name);
+           return      (status);
+    } else {
 
-       return(status);
+       status = GSS_S_BAD_MECH;
     }
     
-    return(GSS_S_BAD_MECH);
-    
 error_out:
     if (union_ctx_id) {
        if (union_ctx_id->mech_type) {
            if (union_ctx_id->mech_type->elements)
                free(union_ctx_id->mech_type->elements);
            free(union_ctx_id->mech_type);
+           *context_handle = GSS_C_NO_CONTEXT;
        }
        free(union_ctx_id);
     }
+
+    if (output_token->length)
+       (void) gss_release_buffer(&temp_minor_status, output_token);
+
+    if (src_name)
+       *src_name = GSS_C_NO_NAME;
+
+    if (tmp_src_name != GSS_C_NO_NAME)
+       (void) gss_release_buffer(&temp_minor_status,
+                                 (gss_buffer_t)tmp_src_name);
+
     return (status);
 }
 
index 8ecf55f31dbacb6944a2e42b34dc09aee898885c..ca30607911b911e5328527c5d684a6a91f89eb15 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_acquire_cred.c 1.19     95/08/07 SMI" */
+/* #pragma ident       "@(#)g_acquire_cred.c   1.22    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
 #include <errno.h>
 #include <time.h>
 
-#define g_OID_equal(o1,o2) \
-   (((o1)->length == (o2)->length) && \
-    (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0))
-
 static gss_OID_set
-create_actual_mechs(creds)
-    gss_union_cred_t   creds;
+create_actual_mechs(mechs_array, count)
+    const gss_OID      mechs_array;
+    int count;
 {
     gss_OID_set        actual_mechs;
     int                        i;
+    OM_uint32          minor;
 
     actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc));
     if (!actual_mechs)
        return NULL;
 
     actual_mechs->elements = (gss_OID)
-           malloc(sizeof(gss_OID_desc) * creds->count);
+       malloc(sizeof (gss_OID_desc) * count);
     if (!actual_mechs->elements) {
        free(actual_mechs);
        return NULL;
     }
     
-    actual_mechs->count = creds->count;
+    actual_mechs->count = 0;
 
-    for (i=0; i < creds->count; i++) {
-       actual_mechs->elements[i].length = creds->mechs_array[i].length;
+    for (i = 0; i < count; i++) {
        actual_mechs->elements[i].elements = (void *)
-           malloc(creds->mechs_array[i].length);
-       memcpy(actual_mechs->elements[i].elements,
-              creds->mechs_array[i].elements, creds->mechs_array[i].length);
+           malloc(mechs_array[i].length);
+       if (actual_mechs->elements[i].elements == NULL) {
+           (void) gss_release_oid_set(&minor, &actual_mechs);
+           return (NULL);
+       }
+       g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
+       actual_mechs->count++;
     }
 
     return actual_mechs;
@@ -91,291 +92,118 @@ gss_OID_set *             actual_mechs;
 OM_uint32 *            time_rec;
 
 {
-    OM_uint32          status, temp_minor_status, temp_time_rec = ~0;
-    unsigned int       i, j, creds_acquired = 0;
-    int                        k;
-    gss_union_name_t   union_name;
-    gss_name_t         internal_name;
-    gss_union_cred_t   creds;
-    gss_OID_set_desc   default_OID_set;
-    gss_OID_desc       default_OID;
-    gss_OID            specific_mech_type = 0;
-    gss_mechanism      mech;
-    
-    /*
-     * This struct is used to keep track of which mech_types are
-     * actually available and to store the credentials returned
-     * from them by each mechanism specific gss_acquire_cred() call.
-     * The results are used to construct the final union_cred
-     * structure returned by the glue layer gss_acquire_cred() call
-     * and the actual_mechs gss_OID_set returned.
-     */
-    
-    struct creds_returned {
-       unsigned char   available;
-       gss_cred_id_t   cred;
-    } *creds_returned;
+    OM_uint32 major = GSS_S_FAILURE;
+    OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
+    gss_OID_set_desc default_OID_set;
+    gss_OID_set mechs;
+    gss_OID_desc default_OID;
+    gss_mechanism mech;
+    int i;
+    gss_union_cred_t creds;
+
+    /* start by checking parameters */
+    if (!minor_status)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
     
-    gss_initialize();
+    if (!output_cred_handle)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
 
-    /* Set this to NULL for now */
+    *output_cred_handle = GSS_C_NO_CREDENTIAL;
 
+    /* Set output parameters to NULL for now */
     if (actual_mechs)
        *actual_mechs = GSS_C_NULL_OID_SET;
 
-    if (minor_status)
-       *minor_status = 0;
-    
-    /* No need to continue if we don't have a place to store the creds */
-    if (output_cred_handle == NULL)
-       return GSS_S_COMPLETE;
-
-    /* get desired_name cast as a union_name type */
-    
-    union_name = (gss_union_name_t) desired_name;
+    if (time_rec)
+       *time_rec = 0;
 
-    if (union_name)
-           specific_mech_type = union_name->mech_type;
-    
     /*
      * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
-     * appropriate default.
+     * appropriate default.  We use the first mechanism in the
+     * mechansim list as the default. This set is created with
+     * statics thus needs not be freed
      */
     if(desired_mechs == GSS_C_NULL_OID_SET) {
-       /*
-        * If union_name->mech_type is NULL then we get the default
-        * mechanism; otherwise, we get the mechanism for the
-        * mechanism-specific name.
-        */
-       mech = __gss_get_mechanism(specific_mech_type);
+       mech = gssint_get_mechanism(NULL);
        if (mech == NULL)
            return (GSS_S_BAD_MECH);
-
-       desired_mechs = &default_OID_set;
-       default_OID_set.count = 1 ;
+       
+       mechs = &default_OID_set;
+       default_OID_set.count = 1;
        default_OID_set.elements = &default_OID;
        default_OID.length = mech->mech_type.length;
        default_OID.elements = mech->mech_type.elements;
-    }
-    
-    /*
-     * Now allocate the creds returned array. There is one element
-     * for each member of the desired_mechs argument. 
-     */
-    
-    creds_returned = (struct creds_returned *)
-       malloc(sizeof(struct creds_returned) * desired_mechs->count);
-    
-    /*
-     * For each requested mechanism in desired_mechs, determine if it
-     * is supported. If so, mark the corresponding element in
-     * creds_returned->available as 1 and call the mechanism
-     * specific gss_acquire_cred(), placing the returned cred in
-     * creds_returned->cred. If not, mark creds_returned->available as
-     * 0.
-     */
-    status = GSS_S_BAD_MECH;
-    for (j=0; j < desired_mechs->count; j++) {
-       creds_returned[j].available = 0;
-
-       mech = __gss_get_mechanism (&desired_mechs->elements[j]);
-       if (!mech || !mech->gss_acquire_cred)
-           continue;
-       /*
-        * If this is a mechanism-specific name, then only use the
-        * mechanism of the name.
-        */
-       if (specific_mech_type && !g_OID_equal(specific_mech_type,
-                                              &mech->mech_type))
-           continue;
-       /*
-        * If this is not a mechanism-specific name, then we need to
-        * do an import the external name in union_name first.
-        */
-       if (union_name == 0)
-           internal_name = (gss_name_t) 0;
-       else if (!union_name->mech_type) {
-           if (__gss_import_internal_name(&temp_minor_status,
-                                          &mech->mech_type,
-                                          union_name, &internal_name)) {
-               continue;
+    } else
+       mechs = desired_mechs;
+
+    if (mechs->count == 0)
+       return (GSS_S_BAD_MECH);
+
+    /* allocate the output credential structure */
+    creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
+    if (creds == NULL)
+       return (GSS_S_FAILURE);
+
+    /* initialize to 0s */
+    (void) memset(creds, 0, sizeof (gss_union_cred_desc));
+
+    /* for each requested mech attempt to obtain a credential */
+    for (i = 0; i < mechs->count; i++) {
+       major = gss_add_cred(minor_status, (gss_cred_id_t)creds,
+                            desired_name,
+                            &mechs->elements[i],
+                            cred_usage, time_req, time_req, NULL,
+                            NULL, &initTimeOut, &acceptTimeOut);
+       if (major == GSS_S_COMPLETE) {
+           /* update the credential's time */
+           if (cred_usage == GSS_C_ACCEPT) {
+               if (outTime > acceptTimeOut)
+                   outTime = acceptTimeOut;
+           } else if (cred_usage == GSS_C_INITIATE) {
+               if (outTime > initTimeOut)
+                   outTime = initTimeOut;
+           } else {
+               /*
+                * time_rec is the lesser of the
+                * init/accept times
+                */
+               if (initTimeOut > acceptTimeOut)
+                   outTime = (outTime > acceptTimeOut) ?
+                       acceptTimeOut : outTime;
+               else
+                   outTime = (outTime > initTimeOut) ?
+                       initTimeOut : outTime;
            }
-       } else
-           internal_name = union_name->mech_name;
-
-       status = mech->gss_acquire_cred(mech->context, minor_status,
-                                       internal_name, time_req,
-                                       desired_mechs, cred_usage,
-                                       &creds_returned[j].cred,
-                                       NULL, &temp_time_rec);
-
-       /* Release the internal name, if allocated above */
-       if (union_name && !union_name->mech_type) {
-           (void) __gss_release_internal_name(&temp_minor_status,
-                                              &mech->mech_type,
-                                              &internal_name);
        }
+    } /* for */
 
-       if (status != GSS_S_COMPLETE)
-           continue;
-
-       /* 
-        * Add this into the creds_returned structure, if we got
-        * a good credential for this mechanism.
-        */
-       if (time_rec) {
-           *time_rec = *time_rec > temp_time_rec ? temp_time_rec : *time_rec;
-           temp_time_rec = *time_rec;
-       }
-
-       creds_returned[j].available = 1;
-       creds_acquired++;
-
-       /*
-        * If union_name is set, then we're done.  Continue, and
-        * declare success.  Otherwise, if do an inquire credentials
-        * from the first mechanism that succeeds and use that as the
-        * union name.
-        */
-       if (union_name)
-           continue;
-
-       status = mech->gss_inquire_cred(mech->context, &temp_minor_status,
-                                       creds_returned[j].cred,
-                                       &internal_name, 0, 0, 0);
-       if (status) {
-           /* Should never happen */
-           creds_returned[j].available = 0;
-           creds_acquired--;
-           if (mech->gss_release_cred)
-               mech->gss_release_cred(mech->context, minor_status,
-                                      &creds_returned[j].cred);
-           continue;
-       }
-
-       status = __gss_convert_name_to_union_name(&temp_minor_status, mech,
-                                                 internal_name,
-                                                 (gss_name_t *) &union_name);
+    /* ensure that we have at least one credential element */
+    if (creds->count < 1) {
+       free(creds);
+       return (major);
     }
-    
-    /*
-     * Now allocate the creds struct, which will be cast as a gss_cred_id_t
-     * and returned in the output_cred_handle argument. If there were
-     * no credentials found, return an error. Also, allocate the
-     * actual_mechs data.
-     */
-    if (creds_acquired == 0) {
-       free (creds_returned);
-       return (status);
-    }
-    
-    creds = (gss_union_cred_t) malloc(sizeof(gss_union_cred_desc));
-    
-    creds->count = creds_acquired;
-    
-    creds->mechs_array = (gss_OID)
-       malloc(sizeof(gss_OID_desc) * creds_acquired);
-    
-    creds->cred_array = (gss_cred_id_t *)
-       malloc(sizeof(gss_cred_id_t) * creds_acquired);
-    
-    if(actual_mechs != NULL) {
-       *actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc));
-
-       (*actual_mechs)->count = creds_acquired;
 
-       (*actual_mechs)->elements = (gss_OID)
-           malloc(sizeof(gss_OID_desc) * creds_acquired);
-    }
-    
-    /*
-     * copy the mechanisms found and their allocated credentials into the
-     * creds structure. At the same time, build up the actual_mechs
-     * data.
-     */
-    
-    j = 0;
-    
-    for (i=0; i<desired_mechs->count; i++) {
-       if(creds_returned[i].available) {
-
-           creds->mechs_array[j].length =
-               desired_mechs->elements[i].length;
-           creds->mechs_array[j].elements = (void *)
-               malloc(desired_mechs->elements[i].length);
-           memcpy(creds->mechs_array[j].elements,
-                  desired_mechs->elements[i].elements,
-                  desired_mechs->elements[i].length);
-           creds->cred_array[j] = creds_returned[i].cred;
-           if (actual_mechs) {
-                   (*actual_mechs)->elements[j].length =
-                       desired_mechs->elements[i].length;
-                   (*actual_mechs)->elements[j].elements = (void *)
-                       malloc(desired_mechs->elements[i].length);
-                   memcpy((*actual_mechs)->elements[j].elements,
-                          desired_mechs->elements[i].elements,
-                          desired_mechs->elements[i].length);
-           }
-           j++;
-       }
-    }
-    
-    /* free the creds_returned struct, since we are done with it. */
-    
-    free(creds_returned);
-    
-    /* record the information needed for gss_inquire_cred() */
-    
-    creds->auxinfo.creation_time = time(0);
-    creds->auxinfo.time_rec = temp_time_rec;
-    creds->auxinfo.cred_usage =  cred_usage;
-    
     /*
-     * we can't just record the internal name, desired_name, since
-     * it may be destroyed between now and the time gss_inquire_cred()
-     * is called.  So we must record the printable name in a
-     * gss_buffer_t, calling gss_display_name() to fill it in. When
-     * gss_inquire_name() is called, we must then call gss_import_name()
-     * to get the internal name that is required at that point.
+     * fill in output parameters
+     * setup the actual mechs output parameter
      */
-    if (desired_name) {
-       status = gss_display_name(&temp_minor_status, desired_name,
-                                 &creds->auxinfo.name,
-                                 &creds->auxinfo.name_type);
-       if (status) {
-           status = GSS_S_BAD_NAME;
-           goto error_out;
+    if (actual_mechs != NULL) {
+       if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
+                                                creds->count)) == NULL) {
+           (void) gss_release_cred(minor_status,
+                                   (gss_cred_id_t *)&creds);
+           *minor_status = 0;
+           return (GSS_S_FAILURE);
        }
-    } else {
-       status = gss_display_name(&temp_minor_status, union_name,
-                                 &creds->auxinfo.name,
-                                 &creds->auxinfo.name_type);
-       if (status) {
-           status = GSS_S_BAD_NAME;
-           goto error_out;
-       }
-    }
-    
-    *output_cred_handle = (gss_cred_id_t) creds;
-    return(GSS_S_COMPLETE);
-
-error_out:
-    for (k=0; k < creds->count; k++) {
-       free(creds->mechs_array[k].elements);
-       if (actual_mechs)
-           free((*actual_mechs)->elements[k].elements);
     }
-       
-    if (actual_mechs) {
-       free((*actual_mechs)->elements);
-       free(*actual_mechs);
-       *actual_mechs = GSS_C_NULL_OID_SET;
-    }
-    free(creds->cred_array);
-    free(creds->mechs_array);
-    free(creds);
-       
-    return(status);
+
+    if (time_rec)
+       *time_rec = outTime;
+
+
+    *output_cred_handle = (gss_cred_id_t)creds;
+    return (GSS_S_COMPLETE);
 }
 
 /* V2 KRB5_CALLCONV */
@@ -401,36 +229,73 @@ gss_add_cred(minor_status, input_cred_handle,
     OM_uint32          time_req, time_rec;
     gss_union_name_t   union_name;
     gss_union_cred_t   new_union_cred, union_cred;
-    gss_name_t         internal_name;
+    gss_name_t         internal_name = GSS_C_NO_NAME;
+    gss_name_t         allocated_name = GSS_C_NO_NAME;
     gss_mechanism      mech;
-    gss_cred_id_t      cred;
-    gss_OID            new_mechs_array;
-    gss_cred_id_t *    new_cred_array;
+    gss_cred_id_t      cred = NULL;
+    gss_OID            new_mechs_array = NULL;
+    gss_cred_id_t *    new_cred_array = NULL;
+
+    /* check input parameters */
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
+       output_cred_handle == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
+
+    if (output_cred_handle)
+       *output_cred_handle = GSS_C_NO_CREDENTIAL;
 
-    if (input_cred_handle == GSS_C_NO_CREDENTIAL)
-       return GSS_S_NO_CRED;
+    if (actual_mechs)
+       *actual_mechs = NULL;
+
+    if (acceptor_time_rec)
+       *acceptor_time_rec = 0;
 
-    union_cred = (gss_union_cred_t) input_cred_handle;
+    if (initiator_time_rec)
+       *initiator_time_rec = 0;
 
-    mech = __gss_get_mechanism(desired_mech);
+    mech = gssint_get_mechanism(desired_mech);
     if (!mech)
        return GSS_S_BAD_MECH;
+    else if (!mech->gss_acquire_cred)
+       return (GSS_S_UNAVAILABLE);
 
-    if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
-       GSS_C_NO_CREDENTIAL)
-       return GSS_S_DUPLICATE_ELEMENT;
+    if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+       union_cred = malloc(sizeof (gss_union_cred_desc));
+       if (union_cred == NULL)
+           return (GSS_S_FAILURE);
 
-    union_name = (gss_union_name_t) desired_name;
-    if (union_name->mech_type) {
-       if (!g_OID_equal(desired_mech, union_name->mech_type))
-           return GSS_S_BAD_NAMETYPE;
-       internal_name = union_name->mech_name;
+       (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
+
+       /* for default credentials we will use GSS_C_NO_NAME */
+       internal_name = GSS_C_NO_NAME;
     } else {
-       if (__gss_import_internal_name(minor_status, desired_mech,
-                                      union_name, &internal_name))
-           return (GSS_S_BAD_NAME);
+       union_cred = (gss_union_cred_t)input_cred_handle;
+       if (gssint_get_mechanism_cred(union_cred, desired_mech) !=
+           GSS_C_NO_CREDENTIAL)
+           return (GSS_S_DUPLICATE_ELEMENT);
+
+       /* may need to create a mechanism specific name */
+       if (desired_name) {
+           union_name = (gss_union_name_t)desired_name;
+           if (union_name->mech_type &&
+               g_OID_equal(union_name->mech_type,
+                           &mech->mech_type))
+               internal_name = union_name->mech_name;
+           else {
+               if (gssint_import_internal_name(minor_status,
+                                              &mech->mech_type, union_name,
+                                              &allocated_name) != GSS_S_COMPLETE)
+                   return (GSS_S_BAD_NAME);
+               internal_name = allocated_name;
+           }
+       }
     }
 
+
     if (cred_usage == GSS_C_ACCEPT)
        time_req = acceptor_time_req;
     else if (cred_usage == GSS_C_INITIATE)
@@ -443,22 +308,54 @@ gss_add_cred(minor_status, input_cred_handle,
                                    internal_name, time_req,
                                    GSS_C_NULL_OID_SET, cred_usage,
                                    &cred, NULL, &time_rec);
+
     if (status != GSS_S_COMPLETE)
        goto errout;
 
+    /* may need to set credential auxinfo strucutre */
+    if (union_cred->auxinfo.creation_time == 0) {
+       union_cred->auxinfo.creation_time = time(NULL);
+       union_cred->auxinfo.time_rec = time_rec;
+       union_cred->auxinfo.cred_usage = cred_usage;
+
+       /*
+        * we must set the name; if name is not supplied
+        * we must do inquire cred to get it
+        */
+       if (internal_name == NULL) {
+           if (mech->gss_inquire_cred == NULL ||
+               ((status = mech->gss_inquire_cred(
+                     mech->context,
+                     &temp_minor_status, cred,
+                     &allocated_name, NULL, NULL,
+                     NULL)) != GSS_S_COMPLETE))
+               goto errout;
+           internal_name = allocated_name;
+       }
+
+       if (internal_name != GSS_C_NO_NAME) {
+           status = mech->gss_display_name(mech->context,
+                                           &temp_minor_status, internal_name,
+                                           &union_cred->auxinfo.name,
+                                           &union_cred->auxinfo.name_type);
+       
+           if (status != GSS_S_COMPLETE)
+               goto errout;
+       }
+    }
+
+    /* now add the new credential elements */
     new_mechs_array = (gss_OID)
-       malloc(sizeof(gss_OID_desc) * (union_cred->count+1));
-    
+       malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
+
     new_cred_array = (gss_cred_id_t *)
-       malloc(sizeof(gss_cred_id_t) * (union_cred->count+1));
+       malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
 
     if (!new_mechs_array || !new_cred_array) {
-       *minor_status = ENOMEM;
        status = GSS_S_FAILURE;
        goto errout;
     }
 
-
     if (acceptor_time_rec)
        if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
            *acceptor_time_rec = time_rec;
@@ -467,57 +364,77 @@ gss_add_cred(minor_status, input_cred_handle,
            *initiator_time_rec = time_rec;
 
     /*
-     * OK, expand the mechanism array in the union credentials
-     * (Look for the union label...)
+     * OK, expand the mechanism array and the credential array
      */
-    memcpy(new_mechs_array, union_cred->mechs_array,
-          sizeof(gss_OID_desc) * union_cred->count);
-    memcpy(new_cred_array, union_cred->cred_array,
-          sizeof(gss_cred_id_t) * union_cred->count);
-    
+    (void) memcpy(new_mechs_array, union_cred->mechs_array,
+                 sizeof (gss_OID_desc) * union_cred->count);
+    (void) memcpy(new_cred_array, union_cred->cred_array,
+                 sizeof (gss_cred_id_t) * union_cred->count);
+
     new_cred_array[union_cred->count] = cred;
-    new_mechs_array[union_cred->count].length = desired_mech->length;
-    new_mechs_array[union_cred->count].elements = malloc(desired_mech->length);
-    if (!new_mechs_array[union_cred->count].elements) {
-       *minor_status = ENOMEM;
+    if ((new_mechs_array[union_cred->count].elements =
+        malloc(mech->mech_type.length)) == NULL)
        goto errout;
+
+    g_OID_copy(&new_mechs_array[union_cred->count],
+              &mech->mech_type);
+
+    if (actual_mechs) {
+       *actual_mechs = create_actual_mechs(new_mechs_array,
+                                           union_cred->count + 1);
+       if (*actual_mechs == NULL) {
+           free(new_mechs_array[union_cred->count].elements);
+           goto errout;
+       }
     }
-    memcpy(new_mechs_array[union_cred->count].elements, desired_mech->elements,
-          desired_mech->length);
 
     if (output_cred_handle == NULL) {
        free(union_cred->mechs_array);
        free(union_cred->cred_array);
        new_union_cred = union_cred;
     } else {
-       new_union_cred = malloc(sizeof(gss_union_cred_desc));
+       new_union_cred = malloc(sizeof (gss_union_cred_desc));
        if (new_union_cred == NULL) {
-           *minor_status = ENOMEM;
+           free(new_mechs_array[union_cred->count].elements);
            goto errout;
        }
        *new_union_cred = *union_cred;
-       *output_cred_handle = new_union_cred;
+       *output_cred_handle = (gss_cred_id_t)new_union_cred;
     }
+
     new_union_cred->mechs_array = new_mechs_array;
     new_union_cred->cred_array = new_cred_array;
     new_union_cred->count++;
-    new_mechs_array = 0;
-    new_cred_array = 0;
 
-    if (actual_mechs)
-       *actual_mechs = create_actual_mechs(new_union_cred);
-    
-    status = GSS_S_COMPLETE;
-    
+    /* We're done with the internal name. Free it if we allocated it. */
+
+    if (allocated_name)
+       (void) gssint_release_internal_name(&temp_minor_status,
+                                          &mech->mech_type,
+                                          &allocated_name);
+
+    return (GSS_S_COMPLETE);
+
 errout:
     if (new_mechs_array)
        free(new_mechs_array);
     if (new_cred_array)
        free(new_cred_array);
-    if (!union_name->mech_type) {
-       (void) __gss_release_internal_name(&temp_minor_status,
-                                          desired_mech, &internal_name);
+
+    if (cred != NULL && mech->gss_release_cred)
+       mech->gss_release_cred(mech->context,
+                              &temp_minor_status, &cred);
+
+    if (allocated_name)
+       (void) gssint_release_internal_name(&temp_minor_status,
+                                          &mech->mech_type,
+                                          &allocated_name);
+
+    if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
+       if (union_cred->auxinfo.name.value)
+           free(union_cred->auxinfo.name.value);
+       free(union_cred);
     }
 
-    return(status);
+    return (status);
 }
diff --git a/src/lib/gssapi/mechglue/g_canon_name.c b/src/lib/gssapi/mechglue/g_canon_name.c
new file mode 100644 (file)
index 0000000..a726fef
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident       "@(#)g_canon_name.c     1.15    04/02/23 SMI" */
+
+/*
+ * routine gss_canonicalize_name
+ *
+ * This routine is used to produce a mechanism specific
+ * representation of name that has been previously
+ * imported with gss_import_name.  The routine uses the mechanism
+ * specific implementation of gss_import_name to implement this
+ * function.
+ *
+ * We allow a NULL output_name, in which case we modify the
+ * input_name to include the mechanism specific name.
+ */
+
+#include <mglueP.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_canonicalize_name(minor_status,
+                               input_name,
+                               mech_type,
+                               output_name)
+OM_uint32 *minor_status;
+const gss_name_t input_name;
+const gss_OID mech_type;
+gss_name_t *output_name;
+{
+       gss_union_name_t in_union, out_union = NULL, dest_union = NULL;
+       OM_uint32 major_status = GSS_S_FAILURE;
+
+       if (minor_status == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+       *minor_status = 0;
+
+       if (output_name)
+               *output_name = 0;
+
+       /* check the input parameters */
+       if (input_name == NULL || mech_type == GSS_C_NULL_OID)
+               return (GSS_S_CALL_INACCESSIBLE_READ);
+
+       in_union = (gss_union_name_t)input_name;
+       /*
+        * If the caller wants to reuse the name, and the name has already
+        * been converted, then there is nothing for us to do.
+        */
+       if (!output_name && in_union->mech_type &&
+               g_OID_equal(in_union->mech_type, mech_type))
+               return (GSS_S_COMPLETE);
+
+       /* ok, then we need to do something - start by creating data struct */
+       if (output_name) {
+               out_union =
+                       (gss_union_name_t)malloc(sizeof (gss_union_name_desc));
+               if (!out_union)
+                       goto allocation_failure;
+
+               out_union->mech_type = 0;
+               out_union->mech_name = 0;
+               out_union->name_type = 0;
+               out_union->external_name = 0;
+
+               /* Allocate the buffer for the user specified representation */
+               if (gssint_create_copy_buffer(in_union->external_name,
+                               &out_union->external_name, 1))
+                       goto allocation_failure;
+
+               if (in_union->name_type != GSS_C_NULL_OID) {
+                       if ((major_status = generic_gss_copy_oid(minor_status,
+                               in_union->name_type, &out_union->name_type)))
+                       goto allocation_failure;
+               }
+
+       }
+
+       /*
+        * might need to delete any old mechanism names if we are
+        * reusing the buffer.
+        */
+       if (!output_name) {
+               if (in_union->mech_type) {
+                       (void) gssint_release_internal_name(minor_status,
+                                                       in_union->mech_type,
+                                                       &in_union->mech_name);
+                       (void) gss_release_oid(minor_status,
+                                           &in_union->mech_type);
+                       in_union->mech_type = 0;
+               }
+               dest_union = in_union;
+       } else
+               dest_union = out_union;
+
+       /* now let's create the new mech name */
+       if (major_status = generic_gss_copy_oid(minor_status, mech_type,
+                                               &dest_union->mech_type))
+               goto allocation_failure;
+
+       if (major_status =
+               gssint_import_internal_name(minor_status, mech_type,
+                                               dest_union,
+                                               &dest_union->mech_name))
+               goto allocation_failure;
+
+       if (output_name)
+               *output_name = (gss_name_t)dest_union;
+
+       return (GSS_S_COMPLETE);
+
+allocation_failure:
+       /* do not delete the src name external name format */
+       if (output_name) {
+               if (out_union->external_name) {
+                       if (out_union->external_name->value)
+                               free(out_union->external_name->value);
+                       free(out_union->external_name);
+               }
+               if (out_union->name_type)
+                       (void) gss_release_oid(minor_status,
+                                           &out_union->name_type);
+
+               dest_union = out_union;
+       } else
+               dest_union = in_union;
+
+       /*
+        * delete the partially created mech specific name
+        * applies for both src and dest which ever is being used for output
+        */
+
+       if (dest_union->mech_name) {
+               (void) gssint_release_internal_name(minor_status,
+                                               dest_union->mech_type,
+                                               &dest_union->mech_name);
+       }
+
+       if (dest_union->mech_type)
+               (void) gss_release_oid(minor_status, &dest_union->mech_type);
+
+
+       if (output_name)
+               free(out_union);
+
+       return (major_status);
+} /**********  gss_canonicalize_name ********/
index 851be4a85b65c7473d50ab99fac6c03087c05cbe..0a6db1c16bd242dbabbc6dd7c2b30958ee1c46b2 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_compare_name.c 1.13     95/08/02 SMI" */
+/* #pragma ident       "@(#)g_compare_name.c   1.16    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
 #endif
 #include <string.h>
 
-#define g_OID_equal(o1,o2) \
-   (((o1)->length == (o2)->length) && \
-    (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0))
-
 OM_uint32 KRB5_CALLCONV
 gss_compare_name (minor_status,
                   name1,
@@ -54,13 +50,15 @@ int *                       name_equal;
     gss_mechanism      mech;
     gss_name_t         internal_name;
     
-    gss_initialize();
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
 
-    if (name1 == 0 || name2 == 0) {
-       if (name_equal)
-           *name_equal = 0;
-       return GSS_S_BAD_NAME;
-    }
+    if (name1 == 0 || name2 == 0)
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+    if (name_equal == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
     union_name1 = (gss_union_name_t) name1;
     union_name2 = (gss_union_name_t) name2;
@@ -78,16 +76,13 @@ int *                       name_equal;
      * information.
      */
     if (union_name1->mech_type) {
-       mech = __gss_get_mechanism (union_name1->mech_type);
+       mech = gssint_get_mechanism (union_name1->mech_type);
        if (!mech)
            return (GSS_S_BAD_MECH);
        if (!mech->gss_compare_name)
-           return (GSS_S_BAD_BINDINGS);
+                       return (GSS_S_UNAVAILABLE);
     }
        
-    if (name_equal == NULL)
-       return GSS_S_COMPLETE;
-
     *name_equal = 0;           /* Default to *not* equal.... */
 
     /*
@@ -116,8 +111,32 @@ int *                      name_equal;
      * gss_import_name().
      */
     if (!union_name1->mech_type && !union_name2->mech_type) {
-       if (!g_OID_equal(union_name1->name_type, union_name2->name_type))
+               /*
+                * Second case, first sub-case... one name has null
+                * name_type, the other doesn't.
+                *
+                * Not knowing a mech_type we can't import the name with
+                * null name_type so we can't compare.
+                */
+               if ((union_name1->name_type == GSS_C_NULL_OID &&
+                   union_name2->name_type != GSS_C_NULL_OID) ||
+                   (union_name1->name_type != GSS_C_NULL_OID &&
+                   union_name2->name_type == GSS_C_NULL_OID))
+                       return (GSS_S_COMPLETE);
+               /*
+                * Second case, second sub-case... both names have
+                * name_types, but they are different.
+                */
+               if ((union_name1->name_type != GSS_C_NULL_OID &&
+                   union_name2->name_type != GSS_C_NULL_OID) &&
+                   !g_OID_equal(union_name1->name_type,
+                                       union_name2->name_type))
            return (GSS_S_COMPLETE);
+               /*
+                * Second case, third sub-case... both names have equal
+                * name_types (and both have no mech_types) so we just
+                * compare the external_names.
+                */
        if ((union_name1->external_name->length !=
             union_name2->external_name->length) ||
            (memcmp(union_name1->external_name->value,
@@ -141,16 +160,17 @@ int *                     name_equal;
        union_name1 = (gss_union_name_t) name2;
        union_name2 = (gss_union_name_t) name1;
     }
-    major_status = __gss_import_internal_name(minor_status,
+    major_status = gssint_import_internal_name(minor_status,
                                              union_name1->mech_type,
                                              union_name2,
                                              &internal_name);
     if (major_status != GSS_S_COMPLETE)
-       return (GSS_S_COMPLETE);
+       return (GSS_S_COMPLETE); /* return complete, but not equal */
+
     major_status = mech->gss_compare_name(mech->context, minor_status,
                                          union_name1->mech_name,
                                          internal_name, name_equal);
-    __gss_release_internal_name(&temp_minor, union_name1->mech_type,
+    gssint_release_internal_name(&temp_minor, union_name1->mech_type,
                                &internal_name);
     return (major_status);
     
index 6f08c9224eab2653cce3b3a602290a5c78ce0986..5ce6b56d86bf1c0741fcc0b12674640caacb0b04 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_context_time.c 1.8     95/08/07 SMI" */
+/* #pragma ident       "@(#)g_context_time.c   1.12    98/01/22 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -42,18 +42,23 @@ OM_uint32 *         time_rec;
     gss_union_ctx_id_t ctx;
     gss_mechanism      mech;
 
-    gss_initialize();
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (time_rec == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
     if (context_handle == GSS_C_NO_CONTEXT)
-       return GSS_S_NO_CONTEXT;
-    
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
     /*
      * select the approprate underlying mechanism routine and
      * call it.
      */
     
     ctx = (gss_union_ctx_id_t) context_handle;
-    mech = __gss_get_mechanism (ctx->mech_type);
+    mech = gssint_get_mechanism (ctx->mech_type);
     
     if (mech) {
 
@@ -64,10 +69,10 @@ OM_uint32 *         time_rec;
                                            ctx->internal_ctx_id,
                                            time_rec);
        else
-           status = GSS_S_BAD_BINDINGS;
+           status = GSS_S_UNAVAILABLE;
 
        return(status);
     }
     
-    return(GSS_S_NO_CONTEXT);
+    return (GSS_S_BAD_MECH);
 }
index fae0b0ac3397992097ab274d39ec65f6bf11d3f0..de70b8fb79e61a5d898ea1b09a6dc5a333689423 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_delete_sec_context.c 1.10     95/08/07 SMI" */
+/* #pragma ident       "@(#)g_delete_sec_context.c     1.11    97/11/09 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -46,20 +46,25 @@ gss_buffer_t                output_token;
     gss_union_ctx_id_t ctx;
     gss_mechanism      mech;
     
-    gss_initialize();
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    if (output_token != GSS_C_NO_BUFFER) {
+       output_token->length = 0;
+       output_token->value = NULL;
+    }
 
     /* if the context_handle is Null, return NO_CONTEXT error */
-    
     if(context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
-       return(GSS_S_NO_CONTEXT);
-    
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
     /*
      * select the approprate underlying mechanism routine and
      * call it.
      */
     
     ctx = (gss_union_ctx_id_t) *context_handle;
-    mech = __gss_get_mechanism (ctx->mech_type);
+    mech = gssint_get_mechanism (ctx->mech_type);
     
     if (mech) {
 
@@ -70,10 +75,9 @@ gss_buffer_t         output_token;
                                                  &ctx->internal_ctx_id,
                                                  output_token);
        else
-           status = GSS_S_BAD_BINDINGS;
+           status = GSS_S_UNAVAILABLE;
 
        /* now free up the space for the union context structure */
-       
        free(ctx->mech_type->elements);
        free(ctx->mech_type);
        free(*context_handle);
@@ -81,6 +85,6 @@ gss_buffer_t          output_token;
 
        return(status);
     }
-    
-    return(GSS_S_NO_CONTEXT);
+
+    return (GSS_S_BAD_MECH);
 }
index 8bd0426c3343f4b312be68ddde3136ac6a877aac..161b2707e37d986911496e9e33cae1962a5e4cf1 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)g_dsp_name.c 1.2     96/02/06 SMI" */
+/* #pragma ident       "@(#)g_dsp_name.c       1.13    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -49,8 +49,18 @@ gss_OID *            output_name_type;
     OM_uint32          major_status;
     gss_union_name_t   union_name;
     
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
     if (input_name == 0)
-       return GSS_S_BAD_NAME;
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+    if (output_name_buffer == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    if (output_name_type)
+       *output_name_type = NULL;
 
     union_name = (gss_union_name_t) input_name;
 
@@ -58,7 +68,7 @@ gss_OID *             output_name_type;
        /*
         * OK, we have a mechanism-specific name; let's use it!
         */
-       return (__gss_display_internal_name(minor_status,
+       return (gssint_display_internal_name(minor_status,
                                            union_name->mech_type,
                                            union_name->mech_name,
                                            output_name_buffer,
@@ -70,27 +80,29 @@ gss_OID *           output_name_type;
      * name into the output_name_buffer and point the output_name_type
      * to the name_type component of union_name
      */
-    if (output_name_type != NULL) {
+    if (output_name_type != NULL &&
+       union_name->name_type != GSS_C_NULL_OID) {
        major_status = generic_gss_copy_oid(minor_status,
                                            union_name->name_type,
                                            output_name_type);
-       if (major_status)
+       if (major_status != GSS_S_COMPLETE)
            return (major_status);
     }
-    
-    if (output_name_buffer != NULL) {
-       output_name_buffer->length = union_name->external_name->length;
-
-       output_name_buffer->value =
-           (void *) malloc(output_name_buffer->length);
 
-       memcpy(output_name_buffer->value,
-              union_name->external_name->value,
-              output_name_buffer->length);
+    if ((output_name_buffer->value =
+        malloc(union_name->external_name->length + 1)) == NULL) {
+       if (output_name_type && *output_name_type != GSS_C_NULL_OID) {
+           (void) generic_gss_release_oid(minor_status,
+                                          output_name_type);
+           *output_name_type = NULL;
+       }
+       return (GSS_S_FAILURE);
     }
-    
-    if (minor_status)
-       *minor_status = 0;
+    output_name_buffer->length = union_name->external_name->length;
+    (void) memcpy(output_name_buffer->value,
+                 union_name->external_name->value,
+                 union_name->external_name->length);
+    ((char *)output_name_buffer->value)[output_name_buffer->length] = '\0';
 
     return(GSS_S_COMPLETE);
 }
index 4b58c38f7091e1363538408971f96521994c8184..83583035fcaa07f865204f2d695855bcdf46962b 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_display_status.c 1.8     95/08/07 SMI" */
+/* #pragma ident       "@(#)g_dsp_status.c     1.17    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
 
 #include "mglueP.h"
 #include <stdio.h>
-#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
-#endif
+#include <string.h>
+
+/* local function */
+static OM_uint32 displayMajor(OM_uint32, OM_uint32 *, gss_buffer_t);
 
 OM_uint32 KRB5_CALLCONV
 gss_display_status (minor_status,
@@ -49,36 +51,275 @@ OM_uint32 *                message_context;
 gss_buffer_t           status_string;
 
 {
-    OM_uint32          status;
     gss_OID            mech_type = (gss_OID) req_mech_type;
     gss_mechanism      mech;
 
-    gss_initialize();
+    /* check the input parameters */
+    if (!minor_status)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    *minor_status = 0;
+
+    if (!message_context || status_string == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    status_string->length = 0;
+    status_string->value = NULL;
+
+    /* we handle major status codes, and the mechs do the minor */
+    if (status_type == GSS_C_GSS_CODE)
+       return (displayMajor(status_value, message_context,
+                            status_string));
 
     /*
-     * select the approprate underlying mechanism routine and
+     * must be the minor status - let mechs do the work
+     * select the appropriate underlying mechanism routine and
      * call it.
      */
 
-    mech = __gss_get_mechanism (mech_type);
+    mech = gssint_get_mechanism (mech_type);
+
+    if (mech && mech->gss_display_status) {
+       if (mech_type == GSS_C_NULL_OID)
+           mech_type = &mech->mech_type;
 
-    if (mech == NULL) 
+       return (mech->gss_display_status(mech->context, minor_status,
+                                        status_value, status_type, mech_type,
+                                        message_context, status_string));
+    }
+
+    if (!mech)
        return (GSS_S_BAD_MECH);
 
-    if (mech_type == GSS_C_NULL_OID)
-       mech_type = &mech->mech_type;
-
-    if (mech->gss_display_status)
-       status = mech->gss_display_status(
-                                         mech->context,
-                                         minor_status,
-                                         status_value,
-                                         status_type,
-                                         mech_type,
-                                         message_context,
-                                         status_string);
-    else
-       status = GSS_S_BAD_BINDINGS;
-
-    return(status);
+    return (GSS_S_UNAVAILABLE);
 }
+
+/*
+ * function to map the major error codes
+ * it uses case statements so that the strings could be wrapped by gettext
+ * msgCtxt is interpreted as:
+ *     0 - first call
+ *     1 - routine error
+ *     >= 2 - the supplementary error code bit shifted by 1
+ */
+static OM_uint32
+displayMajor(status, msgCtxt, outStr)
+OM_uint32 status;
+OM_uint32 *msgCtxt;
+gss_buffer_t outStr;
+{
+       OM_uint32 oneVal, mask = 0x1, currErr;
+       char *errStr = NULL;
+       int i, haveErr = 0;
+
+       /* take care of the success value first */
+       if (status == GSS_S_COMPLETE)
+               errStr = "The routine completed successfully";
+       else if (*msgCtxt == 0 && (oneVal = GSS_CALLING_ERROR(status))) {
+               switch (oneVal) {
+               case GSS_S_CALL_INACCESSIBLE_READ:
+                       errStr = "A required input parameter"
+                               " could not be read";
+                       break;
+
+               case GSS_S_CALL_INACCESSIBLE_WRITE:
+                       errStr = "A required output parameter"
+                               " could not be written";
+                       break;
+
+               case GSS_S_CALL_BAD_STRUCTURE:
+                       errStr = "A parameter was malformed";
+                       break;
+
+               default:
+                       errStr = "An invalid status code was supplied";
+                       break;
+               }
+
+               /* we now need to determine new value of msgCtxt */
+               if (GSS_ROUTINE_ERROR(status))
+                       *msgCtxt = 1;
+               else if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
+                       *msgCtxt = (OM_uint32)(oneVal << 1);
+               else
+                       *msgCtxt = 0;
+
+       } else if ((*msgCtxt == 0 || *msgCtxt == 1) &&
+               (oneVal = GSS_ROUTINE_ERROR(status))) {
+               switch (oneVal) {
+               case GSS_S_BAD_MECH:
+                       errStr = "An unsupported mechanism"
+                               " was requested";
+                       break;
+
+               case GSS_S_BAD_NAME:
+                       errStr = "An invalid name was supplied";
+                       break;
+
+               case GSS_S_BAD_NAMETYPE:
+                       errStr = "A supplied name was of an"
+                               " unsupported type";
+                       break;
+
+               case GSS_S_BAD_BINDINGS:
+                       errStr = "Incorrect channel bindings"
+                               " were supplied";
+                       break;
+
+               case GSS_S_BAD_SIG: /* same as GSS_S_BAD_MIC: */
+                       errStr = "A token had an invalid Message"
+                               " Integrity Check (MIC)";
+                       break;
+
+               case GSS_S_NO_CRED:
+                       errStr = "No credentials were supplied, or the"
+                               " credentials were unavailable or"
+                               " inaccessible";
+                       break;
+
+               case GSS_S_NO_CONTEXT:
+                       errStr = "No context has been established";
+                       break;
+
+               case GSS_S_DEFECTIVE_TOKEN:
+                       errStr = "Invalid token was supplied";
+                       break;
+
+               case GSS_S_DEFECTIVE_CREDENTIAL:
+                       errStr = "Invalid credential was supplied";
+                       break;
+
+               case GSS_S_CREDENTIALS_EXPIRED:
+                       errStr = "The referenced credential has"
+                               " expired";
+                       break;
+
+               case GSS_S_CONTEXT_EXPIRED:
+                       errStr = "The referenced context has expired";
+                       break;
+
+               case GSS_S_FAILURE:
+                       errStr = "Unspecified GSS failure.  Minor code"
+                               " may provide more information";
+                       break;
+
+               case GSS_S_BAD_QOP:
+                       errStr = "The quality-of-protection (QOP) "
+                               "requested could not be provided";
+                       break;
+
+               case GSS_S_UNAUTHORIZED:
+                       errStr = "The operation is forbidden by local"
+                               " security policy";
+                       break;
+
+               case GSS_S_UNAVAILABLE:
+                       errStr = "The operation or option is not"
+                               " available or unsupported";
+                       break;
+
+               case GSS_S_DUPLICATE_ELEMENT:
+                       errStr = "The requested credential element"
+                               " already exists";
+                       break;
+
+               case GSS_S_NAME_NOT_MN:
+                       errStr = "The provided name was not mechanism"
+                               " specific (MN)";
+                       break;
+
+               case GSS_S_BAD_STATUS:
+               default:
+                       errStr = "An invalid status code was supplied";
+               }
+
+               /* we must determine if the caller should call us again */
+               if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
+                       *msgCtxt = (OM_uint32)(oneVal << 1);
+               else
+                       *msgCtxt = 0;
+
+       } else if ((*msgCtxt == 0 || *msgCtxt >= 2) &&
+               (oneVal = GSS_SUPPLEMENTARY_INFO(status))) {
+               /*
+                * if msgCtxt is not 0, then it should encode
+                * the supplementary error code we should be printing
+                */
+               if (*msgCtxt >= 2)
+                       oneVal = (OM_uint32) (*msgCtxt) >> 1;
+               else
+                       oneVal = GSS_SUPPLEMENTARY_INFO(status);
+
+               /* we display the errors LSB first */
+               for (i = 0; i < 16; i++) {
+                       if (oneVal & mask) {
+                               haveErr = 1;
+                               break;
+                       }
+                       mask <<= 1;
+               }
+
+               /* isolate the bit or if not found set to illegal value */
+               if (haveErr)
+                       currErr = oneVal & mask;
+               else
+                       currErr = 1 << 17; /* illegal value */
+
+               switch (currErr) {
+               case GSS_S_CONTINUE_NEEDED:
+                       errStr = "The routine must be called again to"
+                               " complete its function";
+                       break;
+
+               case GSS_S_DUPLICATE_TOKEN:
+                       errStr = "The token was a duplicate of an"
+                               " earlier token";
+                       break;
+
+               case GSS_S_OLD_TOKEN:
+                       errStr = "The token's validity period"
+                               " has expired";
+                       break;
+
+               case GSS_S_UNSEQ_TOKEN:
+                       errStr = "A later token has already been"
+                               " processed";
+                       break;
+
+               case GSS_S_GAP_TOKEN:
+                       errStr = "An expected per-message token was"
+                               " not received";
+                       break;
+
+               default:
+                       errStr = "An invalid status code was supplied";
+               }
+
+               /*
+                * we must check if there is any other supplementary errors
+                * if found, then turn off current bit, and store next value
+                * in msgCtxt shifted by 1 bit
+                */
+               if (!haveErr)
+                       *msgCtxt = 0;
+               else if (GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask)
+                       *msgCtxt = (OM_uint32)
+                               ((GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) << 1);
+               else
+                       *msgCtxt = 0;
+       }
+
+       if (errStr == NULL)
+               errStr = "An invalid status code was supplied";
+
+       /* now copy the status code and return to caller */
+       outStr->length = strlen(errStr);
+       outStr->value = malloc((size_t)outStr->length+1);
+       if (outStr->value == NULL) {
+               outStr->length = 0;
+               return (GSS_S_FAILURE);
+       }
+
+       (void) strcpy((char *)outStr->value, errStr);
+       return (GSS_S_COMPLETE);
+} /* displayMajor */
diff --git a/src/lib/gssapi/mechglue/g_dup_name.c b/src/lib/gssapi/mechglue/g_dup_name.c
new file mode 100644 (file)
index 0000000..1f8815f
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident       "@(#)g_dup_name.c       1.14    04/02/23 SMI" */
+
+/*
+ *  routine gss_duplicate_name
+ *
+ * This routine does not rely on mechanism implementation of this
+ * name, but instead uses mechanism specific gss_import_name routine.
+ */
+
+#include <mglueP.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_duplicate_name(minor_status,
+               src_name,
+               dest_name)
+OM_uint32 *minor_status;
+const gss_name_t src_name;
+gss_name_t *dest_name;
+{
+               gss_union_name_t src_union, dest_union;
+               OM_uint32 major_status = GSS_S_FAILURE;
+
+
+       if (!minor_status)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+       *minor_status = 0;
+
+       /* if output_name is NULL, simply return */
+       if (dest_name == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_BAD_NAME);
+
+       *dest_name = 0;
+
+       if (src_name == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_READ);
+
+       src_union = (gss_union_name_t)src_name;
+
+       /*
+        * First create the union name struct that will hold the external
+        * name and the name type.
+        */
+       dest_union = (gss_union_name_t)malloc(sizeof (gss_union_name_desc));
+       if (!dest_union)
+               goto allocation_failure;
+
+       dest_union->mech_type = 0;
+       dest_union->mech_name = 0;
+       dest_union->name_type = 0;
+       dest_union->external_name = 0;
+
+       /* Now copy the external representaion */
+       if (gssint_create_copy_buffer(src_union->external_name,
+                               &dest_union->external_name, 0))
+               goto allocation_failure;
+
+       if (src_union->name_type != GSS_C_NULL_OID) {
+               major_status = generic_gss_copy_oid(minor_status,
+                                               src_union->name_type,
+                                               &dest_union->name_type);
+               if (major_status != GSS_S_COMPLETE)
+                       goto allocation_failure;
+       }
+
+       /*
+        * See if source name is mechanim specific, if so then need to import it
+        */
+       if (src_union->mech_type) {
+               major_status = generic_gss_copy_oid(minor_status,
+                                                       src_union->mech_type,
+                                                       &dest_union->mech_type);
+               if (major_status != GSS_S_COMPLETE)
+                       goto allocation_failure;
+
+               major_status = gssint_import_internal_name(minor_status,
+                                                       dest_union->mech_type,
+                                                       dest_union,
+                                                       &dest_union->mech_name);
+               if (major_status != GSS_S_COMPLETE)
+                       goto allocation_failure;
+       }
+
+
+       *dest_name = (gss_name_t)dest_union;
+       return (GSS_S_COMPLETE);
+
+allocation_failure:
+       if (dest_union) {
+               if (dest_union->external_name) {
+                       if (dest_union->external_name->value)
+                               free(dest_union->external_name->value);
+                               free(dest_union->external_name);
+               }
+               if (dest_union->name_type)
+                       (void) generic_gss_release_oid(minor_status,
+                                                       &dest_union->name_type);
+               if (dest_union->mech_name)
+                       (void) gssint_release_internal_name(minor_status,
+                                               dest_union->mech_type,
+                                               &dest_union->mech_name);
+               if (dest_union->mech_type)
+                       (void) generic_gss_release_oid(minor_status,
+                                                       &dest_union->mech_type);
+               free(dest_union);
+       }
+       return (major_status);
+} /*   gss_duplicate_name      */
index 958553b49b6e647c44ac1ce7f0cdbc2698d6b994..539920b49b0225d1a392f938f0706dabb9328881 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)g_exp_sec_context.c 1.2     96/01/18 SMI" */
+/* #pragma ident       "@(#)g_exp_sec_context.c        1.14    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -45,16 +45,21 @@ gss_buffer_t                interprocess_token;
 
 {
     OM_uint32          status;
-    size_t             length;
+    OM_uint32          length;
     gss_union_ctx_id_t ctx;
     gss_mechanism      mech;
     gss_buffer_desc    token;
     char               *buf;
     
-    gss_initialize();
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
 
     if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
-       return GSS_S_NO_CONTEXT;
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    if (interprocess_token == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_READ);
 
     /*
      * select the approprate underlying mechanism routine and
@@ -62,11 +67,11 @@ gss_buffer_t                interprocess_token;
      */
     
     ctx = (gss_union_ctx_id_t) *context_handle;
-    mech = __gss_get_mechanism (ctx->mech_type);
+    mech = gssint_get_mechanism (ctx->mech_type);
     if (!mech)
        return GSS_S_BAD_MECH;
     if (!mech->gss_export_sec_context)
-       return GSS_S_BAD_BINDINGS;
+       return (GSS_S_UNAVAILABLE);
     
     status = mech->gss_export_sec_context(mech->context, minor_status,
                                          &ctx->internal_ctx_id, &token);
@@ -78,7 +83,6 @@ gss_buffer_t          interprocess_token;
     interprocess_token->value = malloc(length);
     if (interprocess_token->value == 0) {
        (void) gss_release_buffer(minor_status, &token);
-       *minor_status = ENOMEM;
        return (GSS_S_FAILURE);
     }
     buf = interprocess_token->value;
diff --git a/src/lib/gssapi/mechglue/g_export_name.c b/src/lib/gssapi/mechglue/g_export_name.c
new file mode 100644 (file)
index 0000000..a6aab3a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1996,1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* #pragma ident       "@(#)g_export_name.c    1.11    00/07/17 SMI" */
+
+/*
+ * glue routine gss_export_name
+ *
+ * Will either call the mechanism defined gss_export_name, or if one is
+ * not defined will call a generic_gss_export_name routine.
+ */
+
+#include <mglueP.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_export_name(minor_status,
+                       input_name,
+                       exported_name)
+OM_uint32 *            minor_status;
+const gss_name_t       input_name;
+gss_buffer_t           exported_name;
+{
+       gss_union_name_t                union_name;
+
+
+       if (minor_status)
+               *minor_status = 0;
+
+       /* check out parameter */
+       if (!exported_name)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+       exported_name->value = NULL;
+       exported_name->length = 0;
+
+       /* check input parameter */
+       if (!input_name)
+               return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+       union_name = (gss_union_name_t)input_name;
+
+       /* the name must be in mechanism specific format */
+       if (!union_name->mech_type)
+               return (GSS_S_NAME_NOT_MN);
+
+       return gssint_export_internal_name(minor_status, union_name->mech_type,
+                                       union_name->mech_name, exported_name);
+}
index 6aecab7fb6d9489a13165507725392cbdb73bb9a..030fbfdfa571cdb06422d804f76ea2ba9aefa0e2 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident      "@(#)g_glue.c 1.1     96/02/06 SMI" */
+/* #pragma ident       "@(#)g_glue.c   1.25    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
 #include <string.h>
 #include <errno.h>
 
-#define g_OID_equal(o1,o2) \
-   (((o1)->length == (o2)->length) && \
-    (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0))
+#define        MSO_BIT (8*(sizeof (int) - 1))  /* Most significant octet bit */
 
-extern gss_mechanism *__gss_mechs_array;
+extern gss_mechanism *gssint_mechs_array;
 
 /*
  * This file contains the support routines for the glue layer.
  */
 
 /*
- *  given the mechs_array and a mechanism OID, return the 
- *  pointer to the mechanism, or NULL if that mechanism is
- *  not supported.  If the requested OID is NULL, then return
- *  the first mechanism.
+ * get_der_length: Givin a pointer to a buffer that contains a DER encoded
+ * length, decode the length updating the buffer to point to the character
+ * after the DER encoding. The parameter bytes will point to the number of
+ * bytes that made up the DER encoding of the length originally pointed to
+ * by the buffer. Note we return -1 on error.
  */
+int
+gssint_get_der_length(unsigned char **buf, unsigned int buf_len, unsigned int *bytes)
+{
+    /* p points to the beginning of the buffer */
+    unsigned char *p = *buf;
+    int length, new_length;
+    int octets;
+
+    if (buf_len < 1)
+       return (-1);
+
+    /* We should have at least one byte */
+    *bytes = 1;
+
+    /*
+     * If the High order bit is not set then the length is just the value
+     * of *p.
+     */
+    if (*p < 128) {
+       *buf = p+1;     /* Advance the buffer */
+       return (*p);            /* return the length */
+    }
+
+    /*
+     * if the High order bit is set, then the low order bits represent
+     * the number of bytes that contain the DER encoding of the length.
+     */
+
+    octets = *p++ & 0x7f;
+    *bytes += octets;
 
-gss_mechanism __gss_get_mechanism (type)
-     gss_OID type;
+    /* See if the supplied buffer contains enough bytes for the length. */
+    if (octets > buf_len - 1)
+       return (-1);
+
+    /*
+     * Calculate a multibyte length. The length is encoded as an
+     * unsigned integer base 256.
+     */
+    for (length = 0; octets; octets--) {
+       new_length = (length << 8) + *p++;
+       if (new_length < length)  /* overflow */
+           return (-1);
+       length = new_length;
+    }
+
+    *buf = p; /* Advance the buffer */
+
+    return (length);
+}
+
+/*
+ * der_length_size: Return the number of bytes to encode a given length.
+ */
+unsigned int
+gssint_der_length_size(unsigned int len)
 {
-    int        i;
+    int i;
 
-    if (type == GSS_C_NULL_OID)
-       return (__gss_mechs_array[0]);
+    if (len < 128)
+       return (1);
 
-    for (i=0; __gss_mechs_array[i]->mech_type.length != 0; i++) {
-       if ((__gss_mechs_array[i]->mech_type.length == type->length) &&
-           (memcmp (__gss_mechs_array[i]->mech_type.elements, type->elements,
-                    type->length) == 0)) {
+    for (i = 0; len; i++) {
+       len >>= 8;
+    }
+
+    return (i+1);
+}
+
+/*
+ * put_der_length: Encode the supplied length into the buffer pointed to
+ * by buf. max_length represents the maximum length of the buffer pointed
+ * to by buff. We will advance buf to point to the character after the newly
+ * DER encoded length. We return 0 on success or -l it the length cannot
+ * be encoded in max_len characters.
+ */
+int
+gssint_put_der_length(unsigned int length, unsigned char **buf, unsigned int max_len)
+{
+    unsigned char *s = *buf, *p;
+    unsigned int buf_len = 0;
+    int i, first;
+
+    /* Oops */
+    if (buf == 0 || max_len < 1)
+       return (-1);
+
+    /* Single byte is the length */
+    if (length < 128) {
+       *s++ = length;
+       *buf = s;
+       return (0);
+    }
+
+    /* First byte contains the number of octets */
+    p = s + 1;
+
+    /* Running total of the DER encoding length */
+    buf_len = 0;
 
-           return (__gss_mechs_array[i]);
+    /*
+     * Encode MSB first. We do the encoding by setting a shift
+     * factor to MSO_BIT (24 for 32 bit words) and then shifting the length
+     * by the factor. We then encode the resulting low order byte.
+     * We subtract 8 from the shift factor and repeat to ecnode the next
+     * byte. We stop when the shift factor is zero or we've run out of
+     * buffer to encode into.
+     */
+    first = 0;
+    for (i = MSO_BIT; i >= 0 && buf_len <= max_len; i -= 8) {
+       unsigned int v;
+       v = (length >> i) & 0xff;
+       if ((v) || first) {
+           buf_len += 1;
+           *p++ = v;
+           first = 1;
        }
     }
-    return NULL;
+    if (i >= 0)                        /* buffer overflow */
+       return (-1);
+
+    /*
+     * We go back now and set the first byte to be the length with
+     * the high order bit set.
+     */
+    *s = buf_len | 0x80;
+    *buf = p;
+
+    return (0);
 }
 
 
@@ -72,7 +182,7 @@ gss_mechanism __gss_get_mechanism (type)
  *
  */
 
-OM_uint32 __gss_get_mech_type(OID, token)
+OM_uint32 gssint_get_mech_type(OID, token)
     gss_OID            OID;
     gss_buffer_t       token;
 {
@@ -102,7 +212,10 @@ OM_uint32 __gss_get_mech_type(OID, token)
      * The routine fills in the OID value and returns an error as necessary.
      */
     
-    if (token == NULL)
+       if (OID == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+       if ((token == NULL) || (token->value == NULL))
        return (GSS_S_DEFECTIVE_TOKEN);
     
     /* Skip past the APP/Sequnce byte and the token length */
@@ -112,6 +225,11 @@ OM_uint32 __gss_get_mech_type(OID, token)
     if (*(buffer_ptr++) != 0x60)
        return (GSS_S_DEFECTIVE_TOKEN);
     length = *buffer_ptr++;
+
+       /* check if token length is null */
+       if (length == 0)
+           return (GSS_S_DEFECTIVE_TOKEN);
+
     if (length & 0x80) {
        if ((length & 0x7f) > 4)
            return (GSS_S_DEFECTIVE_TOKEN);
@@ -133,7 +251,7 @@ OM_uint32 __gss_get_mech_type(OID, token)
 
 #include "mglueP.h"
 
-OM_uint32 __gss_import_internal_name (minor_status, mech_type, union_name, 
+OM_uint32 gssint_import_internal_name (minor_status, mech_type, union_name, 
                                internal_name)
 OM_uint32      *minor_status;
 gss_OID                mech_type;
@@ -143,7 +261,7 @@ gss_name_t  *internal_name;
     OM_uint32          status;
     gss_mechanism      mech;
 
-    mech = __gss_get_mechanism (mech_type);
+    mech = gssint_get_mechanism (mech_type);
     if (mech) {
        if (mech->gss_import_name)
            status = mech->gss_import_name (
@@ -153,7 +271,7 @@ gss_name_t  *internal_name;
                                            union_name->name_type,
                                            internal_name);
        else
-           status = GSS_S_BAD_BINDINGS;
+           status = GSS_S_UNAVAILABLE;
 
        return (status);
     }
@@ -161,7 +279,124 @@ gss_name_t        *internal_name;
     return (GSS_S_BAD_MECH);
 }
 
-OM_uint32 __gss_display_internal_name (minor_status, mech_type, internal_name, 
+OM_uint32 gssint_export_internal_name(minor_status, mech_type,
+                                    internal_name, name_buf)
+    OM_uint32          *minor_status;
+    const gss_OID              mech_type;
+    const gss_name_t   internal_name;
+    gss_buffer_t               name_buf;
+{
+    OM_uint32 status;
+    gss_mechanism mech;
+    gss_buffer_desc dispName;
+    gss_OID nameOid;
+    unsigned char *buf = NULL;
+    const unsigned char tokId[] = "\x04\x01";
+    const unsigned int tokIdLen = 2;
+    const int mechOidLenLen = 2, mechOidTagLen = 1, nameLenLen = 4;
+    int mechOidDERLen = 0;
+    int mechOidLen = 0;
+
+    mech = gssint_get_mechanism(mech_type);
+    if (!mech)
+       return (GSS_S_BAD_MECH);
+
+    if (mech->gss_export_name)
+       return (mech->gss_export_name(mech->context,
+                                     minor_status,
+                                     internal_name,
+                                     name_buf));
+
+    /*
+     * if we are here it is because the mechanism does not provide
+     * a gss_export_name so we will use our implementation.  We
+     * do required that the mechanism define a gss_display_name.
+     */
+    if (!mech->gss_display_name)
+       return (GSS_S_UNAVAILABLE);
+
+    /*
+     * NOTE: RFC2743 (section 3.2) governs the format of the outer
+     *  wrapper of exported names; the mechanisms' specs govern
+     *  the format of the inner portion of the exported name
+     *  and, for some (e.g., RFC1964, the Kerberos V mech), a
+     *  generic default as implemented here will do.
+     *
+     * The outer wrapper of an exported MN is: 2-octet tok Id
+     * (0x0401) + 2-octet network-byte order mech OID length + mech
+     * oid (in DER format, including DER tag and DER length) +
+     * 4-octet network-byte order length of inner portion + inner
+     * portion.
+     *
+     * For the Kerberos V mechanism the inner portion of an exported
+     * MN is the display name string and ignores the name type OID
+     * altogether.  And we hope this will be so for any future
+     * mechanisms also, so that factoring name export/import out of
+     * the mech and into libgss pays off.
+     */
+    if ((status = mech->gss_display_name(mech->context,
+                                        minor_status,
+                                        internal_name,
+                                        &dispName,
+                                        &nameOid))
+       != GSS_S_COMPLETE)
+       return (status);
+
+    /* determine the size of the buffer needed */
+    mechOidDERLen = gssint_der_length_size(mech_type->length);
+    name_buf->length = tokIdLen + mechOidLenLen +
+       mechOidTagLen + mechOidDERLen +
+       mech_type->length +
+       nameLenLen + dispName.length;
+    if ((name_buf->value = (void*)malloc(name_buf->length)) ==
+       (void*)NULL) {
+       name_buf->length = 0;
+       (void) gss_release_buffer(&status, &dispName);
+       return (GSS_S_FAILURE);
+    }
+
+    /* now create the name ..... */
+    buf = (unsigned char *)name_buf->value;
+    (void) memset(name_buf->value, 0, name_buf->length);
+    (void) memcpy(buf, tokId, tokIdLen);
+    buf += tokIdLen;
+
+    /* spec allows only 2 bytes for the mech oid length */
+    mechOidLen = mechOidDERLen + mechOidTagLen + mech_type->length;
+    *buf++ = (mechOidLen & 0xFF00) >> 8;
+    *buf++ = (mechOidLen & 0x00FF);
+
+    /*
+     * DER Encoding of mech OID contains OID Tag (0x06), length and
+     * mech OID value
+     */
+    *buf++ = 0x06;
+    if (gssint_put_der_length(mech_type->length, &buf,
+                      (name_buf->length - tokIdLen -2)) != 0) {
+       name_buf->length = 0;
+       free(name_buf->value);
+       (void) gss_release_buffer(&status, &dispName);
+       return (GSS_S_FAILURE);
+    }
+
+    (void) memcpy(buf, mech_type->elements, mech_type->length);
+    buf += mech_type->length;
+
+    /* spec designates the next 4 bytes for the name length */
+    *buf++ = (dispName.length & 0xFF000000) >> 24;
+    *buf++ = (dispName.length & 0x00FF0000) >> 16;
+    *buf++ = (dispName.length & 0x0000FF00) >> 8;
+    *buf++ = (dispName.length & 0X000000FF);
+
+    /* for the final ingredient - add the name from gss_display_name */
+    (void) memcpy(buf, dispName.value, dispName.length);
+
+    /* release the buffer obtained from gss_display_name */
+    (void) gss_release_buffer(minor_status, &dispName);
+    return (GSS_S_COMPLETE);
+} /*  gssint_export_internal_name */
+
+OM_uint32 gssint_display_internal_name (minor_status, mech_type, internal_name, 
                                 external_name, name_type)
 OM_uint32      *minor_status;
 gss_OID                mech_type;
@@ -172,7 +407,7 @@ gss_OID             *name_type;
     OM_uint32          status;
     gss_mechanism      mech;
 
-    mech = __gss_get_mechanism (mech_type);
+    mech = gssint_get_mechanism (mech_type);
     if (mech) {
        if (mech->gss_display_name)
            status = mech->gss_display_name (
@@ -182,7 +417,7 @@ gss_OID             *name_type;
                                             external_name,
                                             name_type);
        else
-           status = GSS_S_BAD_BINDINGS;
+           status = GSS_S_UNAVAILABLE;
 
        return (status);
     }
@@ -190,7 +425,7 @@ gss_OID             *name_type;
     return (GSS_S_BAD_MECH);
 }
 
-OM_uint32 __gss_release_internal_name (minor_status, mech_type, internal_name)
+OM_uint32 gssint_release_internal_name (minor_status, mech_type, internal_name)
 OM_uint32      *minor_status;
 gss_OID                mech_type;
 gss_name_t     *internal_name;
@@ -198,7 +433,7 @@ gss_name_t  *internal_name;
     OM_uint32          status;
     gss_mechanism      mech;
 
-    mech = __gss_get_mechanism (mech_type);
+    mech = gssint_get_mechanism (mech_type);
     if (mech) {
        if (mech->gss_release_name)
            status = mech->gss_release_name (
@@ -206,7 +441,7 @@ gss_name_t  *internal_name;
                                             minor_status,
                                             internal_name);
        else
-           status = GSS_S_BAD_BINDINGS;
+           status = GSS_S_UNAVAILABLE;
 
        return (status);
     }
@@ -220,7 +455,7 @@ gss_name_t  *internal_name;
  * name.  Note that internal_name should be considered "consumed" by
  * this call, whether or not we return an error.
  */
-OM_uint32 __gss_convert_name_to_union_name(minor_status, mech,
+OM_uint32 gssint_convert_name_to_union_name(minor_status, mech,
                                           internal_name, external_name)
     OM_uint32 *minor_status;
     gss_mechanism      mech;
@@ -232,7 +467,6 @@ OM_uint32 __gss_convert_name_to_union_name(minor_status, mech,
 
     union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));
     if (!union_name) {
-           *minor_status = ENOMEM;
            goto allocation_failure;
     }
     union_name->mech_type = 0;
@@ -248,7 +482,6 @@ OM_uint32 __gss_convert_name_to_union_name(minor_status, mech,
     union_name->external_name =
        (gss_buffer_t) malloc(sizeof(gss_buffer_desc));
     if (!union_name->external_name) {
-           *minor_status = ENOMEM;
            goto allocation_failure;
     }
        
@@ -271,13 +504,17 @@ allocation_failure:
        }
        if (union_name->name_type)
            gss_release_oid(&tmp, &union_name->name_type);
-       if (union_name->mech_name)
-           __gss_release_internal_name(minor_status, union_name->mech_type,
-                                       &union_name->mech_name);
        if (union_name->mech_type)
            gss_release_oid(&tmp, &union_name->mech_type);
        free(union_name);
     }
+    /*
+     * do as the top comment says - since we are now owners of
+     * internal_name, we must clean it up
+     */
+    if (internal_name)
+       (void) gssint_release_internal_name(&tmp, &mech->mech_type,
+                                          &internal_name);
     return (major_status);
 }
 
@@ -286,7 +523,7 @@ allocation_failure:
  * external union credential.
  */
 gss_cred_id_t
-__gss_get_mechanism_cred(union_cred, mech_type)
+gssint_get_mechanism_cred(union_cred, mech_type)
     gss_union_cred_t   union_cred;
     gss_OID            mech_type;
 {
@@ -302,4 +539,46 @@ __gss_get_mechanism_cred(union_cred, mech_type)
     return GSS_C_NO_CREDENTIAL;
 }
 
-    
+/*
+ * Routine to create and copy the gss_buffer_desc structure.
+ * Both space for the structure and the data is allocated.
+ */
+OM_uint32
+gssint_create_copy_buffer(srcBuf, destBuf, addNullChar)
+    const gss_buffer_t srcBuf;
+    gss_buffer_t               *destBuf;
+    int                        addNullChar;
+{
+    gss_buffer_t aBuf;
+    unsigned int len;
+
+    if (destBuf == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    *destBuf = 0;
+
+    aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
+    if (!aBuf)
+       return (GSS_S_FAILURE);
+
+    if (addNullChar)
+       len = srcBuf->length + 1;
+    else
+       len = srcBuf->length;
+
+    if (!(aBuf->value = (void*)malloc(len))) {
+       free(aBuf);
+       return (GSS_S_FAILURE);
+    }
+
+
+    (void) memcpy(aBuf->value, srcBuf->value, srcBuf->length);
+    aBuf->length = srcBuf->length;
+    *destBuf = aBuf;
+
+    /* optionally add a NULL character */
+    if (addNullChar)
+       ((char *)aBuf->value)[aBuf->length] = '\0';
+
+    return (GSS_S_COMPLETE);
+} /* ****** gssint_create_copy_buffer  ****** */
index e93b4c9acd980465f4d97c68c1049cd790d78274..48815b3615accde9acb860abedb86986ba67aad7 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)g_imp_name.c 1.2     96/02/06 SMI" */
+/* #pragma ident       "@(#)g_imp_name.c       1.26    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -35,6 +35,9 @@
 #include <string.h>
 #include <errno.h>
 
+/* local function to import GSS_C_EXPORT_NAME names */
+static OM_uint32 importExportName(OM_uint32 *, gss_union_name_t);
+
 OM_uint32 KRB5_CALLCONV
 gss_import_name(minor_status,
                 input_name_buffer,
@@ -49,33 +52,32 @@ gss_name_t *                output_name;
 {
     gss_union_name_t   union_name;
     OM_uint32          tmp, major_status = GSS_S_FAILURE;
-    gss_OID            mech;
-
-    gss_initialize();
 
-    if (minor_status)
-       *minor_status = 0;
+    /* check output parameters */
+    if (!minor_status)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
-    /* if output_name is NULL, simply return */
+    *minor_status = 0;
 
-    if(output_name == NULL)
-       return (GSS_S_COMPLETE);
+    if (output_name == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
     *output_name = 0;
 
     if (input_name_buffer == GSS_C_NO_BUFFER)
        return (GSS_S_BAD_NAME);
 
+    if (GSS_EMPTY_BUFFER(input_name_buffer))
+       return (GSS_S_BAD_NAME);
+
     /*
      * First create the union name struct that will hold the external
      * name and the name type.
      */
-
     union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));
-    if (!union_name) {
-           *minor_status = ENOMEM;
-           goto allocation_failure;
-    }
+    if (!union_name)
+       return (GSS_S_FAILURE);
+
     union_name->mech_type = 0;
     union_name->mech_name = 0;
     union_name->name_type = 0;
@@ -84,61 +86,43 @@ gss_name_t *                output_name;
     /*
      * All we do here is record the external name and name_type.
      * When the name is actually used, the underlying gss_import_name()
-     * is called for the appropriate mechanism. Note that the name type
-     * is assumed to be constant, so only a pointer to it is stored in
-     * union_name
+     * is called for the appropriate mechanism.  The exception to this
+     * rule is when the name of GSS_C_NT_EXPORT_NAME type.  If that is
+     * the case, then we make it MN in this call.
      */
-    union_name->external_name =
-       (gss_buffer_t) malloc(sizeof(gss_buffer_desc));
-    if (!union_name->external_name) {
-           *minor_status = ENOMEM;
-           goto allocation_failure;
-    }
-    
-    union_name->external_name->length = input_name_buffer->length;
-    /* we malloc length+1 to stick a NULL on the end, just in case */
-    /* Note that this NULL is not included in ->length for a reason! */
-    union_name->external_name->value =
-       (void  *) malloc(input_name_buffer->length+1);
-    if (!union_name->external_name->value) {
-       *minor_status = ENOMEM;
-       goto allocation_failure;
+    major_status = gssint_create_copy_buffer(input_name_buffer,
+                                           &union_name->external_name, 0);
+    if (major_status != GSS_S_COMPLETE) {
+       free(union_name);
+       return (major_status);
     }
-       
-    memcpy(union_name->external_name->value, input_name_buffer->value,
-          input_name_buffer->length);
-
-    /* add NULL to end of external_name->value, just in case... */
-    ((char *)union_name->external_name->value)
-                               [input_name_buffer->length] = '\0';
 
-    major_status = generic_gss_copy_oid(minor_status, input_name_type,
-                                       &union_name->name_type);
-    if (major_status != GSS_S_COMPLETE)
-       goto allocation_failure;
+    if (input_name_type != GSS_C_NULL_OID) {
+       major_status = generic_gss_copy_oid(minor_status,
+                                           input_name_type,
+                                           &union_name->name_type);
+       if (major_status != GSS_S_COMPLETE)
+           goto allocation_failure;
+    }
 
     /*
-     * See if this is a mechanism-specific name.  If so, let's import
-     * it now so we can get any error messages, and to avoid trouble
-     * later...
+     * In MIT Distribution the mechanism is determined from the nametype;
+     * This is not a good idea - first mechanism that supports a given
+     * name type is picked up; later on the caller can request a
+     * different mechanism. So we don't determine the mechanism here. Now
+     * the user level and kernel level import_name routine looks similar
+     * except the kernel routine makes a copy of the nametype structure. We
+     * do however make this an MN for names of GSS_C_NT_EXPORT_NAME type.
      */
-    mech = gss_find_mechanism_from_name_type(input_name_type);
-    if (mech) {
-       major_status = generic_gss_copy_oid(minor_status, mech,
-                                           &union_name->mech_type);
+    if (input_name_type != GSS_C_NULL_OID &&
+       g_OID_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) {
+       major_status = importExportName(minor_status, union_name);
        if (major_status != GSS_S_COMPLETE)
            goto allocation_failure;
-
-       major_status = __gss_import_internal_name(minor_status, mech, 
-                                                 union_name,
-                                                 &union_name->mech_name);
-       if (major_status)
-           goto allocation_failure;
     }
 
-    *output_name = (gss_name_t) union_name;
-
-    return(GSS_S_COMPLETE);
+    *output_name = (gss_name_t)union_name;
+    return (GSS_S_COMPLETE);
 
 allocation_failure:
     if (union_name) {
@@ -150,7 +134,7 @@ allocation_failure:
        if (union_name->name_type)
            generic_gss_release_oid(&tmp, &union_name->name_type);
        if (union_name->mech_name)
-           __gss_release_internal_name(minor_status, union_name->mech_type,
+           gssint_release_internal_name(minor_status, union_name->mech_type,
                                        &union_name->mech_name);
        if (union_name->mech_type)
            generic_gss_release_oid(&tmp, &union_name->mech_type);
@@ -158,3 +142,187 @@ allocation_failure:
     }
     return (major_status);
 }
+
+/*
+ * GSS export name constants
+ */
+static const char *expNameTokId = "\x04\x01";
+static const unsigned int expNameTokIdLen = 2;
+static const unsigned int mechOidLenLen = 2;
+static const unsigned int nameTypeLenLen = 2;
+
+static OM_uint32
+importExportName(minor, unionName)
+    OM_uint32 *minor;
+    gss_union_name_t unionName;
+{
+    gss_OID_desc mechOid;
+    gss_buffer_desc expName;
+    unsigned char *buf;
+    gss_mechanism mech;
+    OM_uint32 major, mechOidLen, nameLen, curLength;
+    unsigned int bytes;
+
+    expName.value = unionName->external_name->value;
+    expName.length = unionName->external_name->length;
+
+    curLength = expNameTokIdLen + mechOidLenLen;
+    if (expName.length < curLength)
+       return (GSS_S_DEFECTIVE_TOKEN);
+
+    buf = (unsigned char *)expName.value;
+    if (memcmp(expNameTokId, buf, expNameTokIdLen) != 0)
+       return (GSS_S_DEFECTIVE_TOKEN);
+
+    buf += expNameTokIdLen;
+
+    /* extract the mechanism oid length */
+    mechOidLen = (*buf++ << 8);
+    mechOidLen |= (*buf++);
+    curLength += mechOidLen;
+    if (expName.length < curLength)
+       return (GSS_S_DEFECTIVE_TOKEN);
+    /*
+     * The mechOid itself is encoded in DER format, OID Tag (0x06)
+     * length and the value of mech_OID
+     */
+    if (*buf++ != 0x06)
+       return (GSS_S_DEFECTIVE_TOKEN);
+
+    /*
+     * mechoid Length is encoded twice; once in 2 bytes as
+     * explained in RFC2743 (under mechanism independent exported
+     * name object format) and once using DER encoding
+     *
+     * We verify both lengths.
+     */
+
+    mechOid.length = gssint_get_der_length(&buf,
+                                   (expName.length - curLength), &bytes);
+    mechOid.elements = (void *)buf;
+
+    /*
+     * 'bytes' is the length of the DER length, '1' is for the DER
+     * tag for OID
+     */
+    if ((bytes + mechOid.length + 1) != mechOidLen)
+       return (GSS_S_DEFECTIVE_TOKEN);
+
+    buf += mechOid.length;
+    if ((mech = gssint_get_mechanism(&mechOid)) == NULL)
+       return (GSS_S_BAD_MECH);
+
+    if (mech->gss_import_name == NULL)
+       return (GSS_S_UNAVAILABLE);
+
+    /*
+     * we must now determine if we should unwrap the name ourselves
+     * or make the mechanism do it - we should only unwrap it
+     * if we create it; so if mech->gss_export_name == NULL, we must
+     * have created it.
+     */
+    if (mech->gss_export_name) {
+       if ((major = mech->gss_import_name(mech->context, minor,
+                                          &expName, (gss_OID)GSS_C_NT_EXPORT_NAME,
+                                          &unionName->mech_name)) != GSS_S_COMPLETE ||
+           (major = generic_gss_copy_oid(minor, &mechOid,
+                                         &unionName->mech_type)) !=
+           GSS_S_COMPLETE) {
+           return (major);
+       }
+       return (major);
+    }
+    /*
+     * we must have exported the name - so we now need to reconstruct it
+     * and call the mechanism to create it
+     *
+     * WARNING:        Older versions of gssint_export_internal_name() did
+     *         not export names correctly, but now it does.  In
+     *         order to stay compatible with existing exported
+     *         names we must support names exported the broken
+     *         way.
+     *
+     * Specifically, gssint_export_internal_name() used to include
+     * the name type OID in the encoding of the exported MN.
+     * Additionally, the Kerberos V mech used to make display names
+     * that included a null terminator which was counted in the
+     * display name gss_buffer_desc.
+     */
+    curLength += 4;            /* 4 bytes for name len */
+    if (expName.length < curLength)
+       return (GSS_S_DEFECTIVE_TOKEN);
+
+    /* next 4 bytes in the name are the name length */
+    nameLen = (*buf++) << 24;
+    nameLen |= (*buf++ << 16);
+    nameLen |= (*buf++ << 8);
+    nameLen |= (*buf++);
+
+    /*
+     * we use < here because bad code in rpcsec_gss rounds up exported
+     * name token lengths and pads with nulls, otherwise != would be
+     * appropriate
+     */
+    curLength += nameLen;   /* this is the total length */
+    if (expName.length < curLength)
+       return (GSS_S_DEFECTIVE_TOKEN);
+
+    /*
+     * We detect broken exported names here: they always start with
+     * a two-octet network-byte order OID length, which is always
+     * less than 256 bytes, so the first octet of the length is
+     * always '\0', which is not allowed in GSS-API display names
+     * (or never occurs in them anyways).  Of course, the OID
+     * shouldn't be there, but it is.  After the OID (sans DER tag
+     * and length) there's the name itself, though null-terminated;
+     * this null terminator should also not be there, but it is.
+     */
+    if (nameLen > 0 && *buf == '\0') {
+       OM_uint32 nameTypeLen;
+       /* next two bytes are the name oid */
+       if (nameLen < nameTypeLenLen)
+           return (GSS_S_DEFECTIVE_TOKEN);
+
+       nameLen -= nameTypeLenLen;
+
+       nameTypeLen = (*buf++) << 8;
+       nameTypeLen |= (*buf++);
+
+       if (nameLen < nameTypeLen)
+           return (GSS_S_DEFECTIVE_TOKEN);
+
+       buf += nameTypeLen;
+       nameLen -= nameTypeLen;
+
+       /*
+        * adjust for expected null terminator that should
+        * really not be there
+        */
+       if (nameLen > 0 && *(buf + nameLen - 1) == '\0')
+           nameLen--;
+    }
+
+    /*
+     * Can a name be null?  Let the mech decide.
+     *
+     * NOTE: We use GSS_C_NULL_OID as the name type when importing
+     *  the unwrapped name.  Presumably the exported name had,
+     *  prior to being exported been obtained in such a way
+     *  that it has been properly perpared ("canonicalized," in
+     *  GSS-API terms) accroding to some name type; we cannot
+     *  tell what that name type was now, but the name should
+     *  need no further preparation other than the lowest
+     *  common denominator afforded by the mech to names
+     *  imported with GSS_C_NULL_OID.  For the Kerberos V mech
+     *  this means doing less busywork too (particularly once
+     *  IDN is thrown in with Kerberos V extensions).
+     */
+    expName.length = nameLen;
+    expName.value = nameLen ? (void *)buf : NULL;
+    major = mech->gss_import_name(mech->context, minor, &expName,
+                                 GSS_C_NULL_OID, &unionName->mech_name);
+    if (major != GSS_S_COMPLETE)
+       return (major);
+
+    return (generic_gss_copy_oid(minor, &mechOid, &unionName->mech_type));
+} /* importExportName */
index eed9bbedaf34ffe6ecfe83936f7b8cdeb7af3ce3..533b0175c0f66a43be9621aa6b1cf268d63c1ca5 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)g_imp_sec_context.c 1.2     96/01/18 SMI" */
+/* #pragma ident       "@(#)g_imp_sec_context.c        1.18    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -44,48 +44,59 @@ gss_buffer_t                interprocess_token;
 gss_ctx_id_t *         context_handle;
 
 {
-    size_t             length;
+    OM_uint32          length = 0;
     OM_uint32          status;
     char               *p;
     gss_union_ctx_id_t ctx;
     gss_buffer_desc    token;
     gss_mechanism      mech;
     
-    gss_initialize();
-
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
     *minor_status = 0;
     
-    if (interprocess_token->length == 0 || interprocess_token->value == 0)
-       return (GSS_S_DEFECTIVE_TOKEN);
+    if (context_handle == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CONTEXT);
+    *context_handle = GSS_C_NO_CONTEXT;
+
+    if (GSS_EMPTY_BUFFER(interprocess_token))
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_DEFECTIVE_TOKEN);
 
     status = GSS_S_FAILURE;
 
     ctx = (gss_union_ctx_id_t) malloc(sizeof(gss_union_ctx_id_desc));
-    if (!ctx) {
-       *minor_status = ENOMEM;
-       goto error_out;
-    }
+    if (!ctx)
+       return (GSS_S_FAILURE);
+
     ctx->mech_type = (gss_OID) malloc(sizeof(gss_OID_desc));
     if (!ctx->mech_type) {
-       *minor_status = ENOMEM;
-       goto error_out;
+       free(ctx);
+       return (GSS_S_FAILURE);
+    }
+
+    if (interprocess_token->length >= sizeof (OM_uint32)) {
+       p = interprocess_token->value;
+       length = (OM_uint32)*p++;
+       length = (OM_uint32)(length << 8) + *p++;
+       length = (OM_uint32)(length << 8) + *p++;
+       length = (OM_uint32)(length << 8) + *p++;
+    }
+
+    if (length == 0 ||
+       length > (interprocess_token->length - sizeof (OM_uint32))) {
+       free(ctx);
+       return (GSS_S_CALL_BAD_STRUCTURE | GSS_S_DEFECTIVE_TOKEN);
     }
-    p = interprocess_token->value;
-    length = *p++;
-    length = (length << 8) + *p++;
-    length = (length << 8) + *p++;
-    length = (length << 8) + *p++;
 
     ctx->mech_type->length = length;
     ctx->mech_type->elements = malloc(length);
     if (!ctx->mech_type->elements) {
-       *minor_status = ENOMEM;
        goto error_out;
     }
     memcpy(ctx->mech_type->elements, p, length);
     p += length;
 
-    token.length = interprocess_token->length - 4 - length;
+    token.length = interprocess_token->length - sizeof (OM_uint32) - length;
     token.value = p;
 
     /*
@@ -93,13 +104,13 @@ gss_ctx_id_t *             context_handle;
      * call it.
      */
     
-    mech = __gss_get_mechanism (ctx->mech_type);
+    mech = gssint_get_mechanism (ctx->mech_type);
     if (!mech) {
        status = GSS_S_BAD_MECH;
        goto error_out;
     }
     if (!mech->gss_import_sec_context) {
-       status = GSS_S_BAD_BINDINGS;
+       status = GSS_S_UNAVAILABLE;
        goto error_out;
     }
     
index 334f7c1b940acb5b7a5125b7f0e26e53f588db29..e2c8d414fea16668df77755517af99fe86d36018 100644 (file)
@@ -33,7 +33,7 @@
 #endif
 #include <string.h>
 
-extern gss_mechanism *__gss_mechs_array;
+extern gss_mechanism *gssint_mechs_array;
 
 static gss_OID_set_desc        supported_mechs_desc; 
 static gss_OID_set supported_mechs = NULL;
@@ -65,7 +65,7 @@ gss_OID_set *         mech_set;
 
        /* Build the mech_set from the OIDs in mechs_array. */
 
-       for(i=0; __gss_mechs_array[i]->mech_type.length != 0; i++) 
+       for(i=0; gssint_mechs_array[i]->mech_type.length != 0; i++) 
            supported_mechs->count++;
 
        supported_mechs->elements =
@@ -74,12 +74,12 @@ gss_OID_set *               mech_set;
 
        for(i=0; i < supported_mechs->count; i++) {
            supported_mechs->elements[i].length =
-               __gss_mechs_array[i]->mech_type.length;
+               gssint_mechs_array[i]->mech_type.length;
            supported_mechs->elements[i].elements = (void *)
-               malloc(__gss_mechs_array[i]->mech_type.length);
+               malloc(gssint_mechs_array[i]->mech_type.length);
            memcpy(supported_mechs->elements[i].elements,
-                  __gss_mechs_array[i]->mech_type.elements,
-                  __gss_mechs_array[i]->mech_type.length);
+                  gssint_mechs_array[i]->mech_type.elements,
+                  gssint_mechs_array[i]->mech_type.length);
        }
     }
     
index 8f55ac5f4cef0dedecef9a236891346fb8749839..53252f798a53090fb74736d7bf9a7e15426b37ac 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_init_sec_context.c 1.20     95/08/07 SMI" */
+/* #pragma ident       "@(#)g_init_sec_context.c       1.20    03/10/24 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
 #endif
 #include <string.h>
 
-#define g_OID_equal(o1,o2) \
-   (((o1)->length == (o2)->length) && \
-    (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0))
-
 OM_uint32 KRB5_CALLCONV
 gss_init_sec_context (minor_status,
                       claimant_cred_handle,
@@ -67,7 +63,7 @@ OM_uint32 *           ret_flags;
 OM_uint32 *            time_rec;
 
 {
-    OM_uint32          status, temp_status, temp_minor_status;
+    OM_uint32          status, temp_minor_status;
     gss_union_name_t   union_name;
     gss_union_cred_t   union_cred;
     gss_name_t         internal_name;
@@ -76,32 +72,48 @@ OM_uint32 *         time_rec;
     gss_mechanism      mech;
     gss_cred_id_t      input_cred_handle;
 
-    gss_initialize();
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
     output_token->length = 0;
     output_token->value = NULL;
 
+    /* clear output values */
+    if (actual_mech_type)
+       *actual_mech_type = NULL;
+
     if (context_handle == NULL)
-       return GSS_S_NO_CONTEXT;
+       return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CONTEXT);
 
     union_name = (gss_union_name_t) target_name;
 
-    /*
-     * If mech_type is NULL, and the target_name is
-     * mechanism-specific, then set it to the mech_type of
-     * target_name.
-     */
-    if ((mech_type == GSS_C_NULL_OID) && union_name->mech_type)
-       mech_type = union_name->mech_type;
+    if (target_name == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+    if (output_token == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    output_token->value = NULL;
+    output_token->length = 0;
+
+
+    if (req_mech_type)
+       mech_type = (gss_OID)req_mech_type;
+
+    union_name = (gss_union_name_t)target_name;
     
     /*
      * obtain the gss mechanism information for the requested
      * mechanism.  If mech_type is NULL, set it to the resultant
      * mechanism
      */
-    mech = __gss_get_mechanism (mech_type);
+    mech = gssint_get_mechanism (mech_type);
     if (mech == NULL)
        return (GSS_S_BAD_MECH);
 
+    if (mech->gss_init_sec_context == NULL)
+       return (GSS_S_UNAVAILABLE);
+
     if (mech_type == GSS_C_NULL_OID)
        mech_type = &mech->mech_type;
 
@@ -110,15 +122,14 @@ OM_uint32 *               time_rec;
      * mech_type that we're about to use.  Otherwise, do an import on
      * the external_name form of the target name.
      */
-    if (union_name->mech_type) {
-       if (!g_OID_equal(union_name->mech_type, mech_type))
-           return (GSS_S_BAD_MECH);
+    if (union_name->mech_type &&
+       g_OID_equal(union_name->mech_type, mech_type)) {
        internal_name = union_name->mech_name;
     } else {
-       if ((temp_status = __gss_import_internal_name(minor_status, mech_type,
-                                                     union_name,
-                                                     &internal_name)))
-           return (GSS_S_BAD_NAME);
+       if ((status = gssint_import_internal_name(minor_status, mech_type,
+                                                union_name,
+                                                &internal_name)) != GSS_S_COMPLETE)
+           return (status);
     }
 
     /*
@@ -129,23 +140,22 @@ OM_uint32 *               time_rec;
      */
     
     if(*context_handle == GSS_C_NO_CONTEXT) {
+       status = GSS_S_FAILURE;
        union_ctx_id = (gss_union_ctx_id_t)
            malloc(sizeof(gss_union_ctx_id_desc));
+       if (union_ctx_id == NULL)
+           goto end;
 
        union_ctx_id->mech_type = (gss_OID)
            malloc(sizeof(gss_OID_desc));
 
-       /* copy in the mech type information */
-
-       union_ctx_id->mech_type->elements = (void *)
-           malloc(mech_type->length);
-
-       union_ctx_id->mech_type->length = mech_type->length;
-       memcpy(union_ctx_id->mech_type->elements, mech_type->elements,
-              mech_type->length);
+       if (generic_gss_copy_oid(&temp_minor_status, mech_type,
+                                &union_ctx_id->mech_type) != GSS_S_COMPLETE) {
+           free(union_ctx_id);
+           goto end;
+       }
 
        /* copy the supplied context handle */
-
        union_ctx_id->internal_ctx_id = *context_handle;
     } else
        union_ctx_id = *context_handle;
@@ -156,37 +166,47 @@ OM_uint32 *               time_rec;
      * use the default credential.
      */
     union_cred = (gss_union_cred_t) claimant_cred_handle;
-    input_cred_handle = __gss_get_mechanism_cred(union_cred, mech_type);
+    input_cred_handle = gssint_get_mechanism_cred(union_cred, mech_type);
     
     /*
      * now call the approprate underlying mechanism routine 
      */
     
-    if (mech->gss_init_sec_context) {
-       status = mech->gss_init_sec_context(
-                                           mech->context,
-                                           minor_status,
-                                           input_cred_handle,
-                                           &union_ctx_id->internal_ctx_id,
-                                           internal_name,
-                                           mech_type,
-                                           req_flags,
-                                           time_req,
-                                           input_chan_bindings,
-                                           input_token,
-                                           actual_mech_type,
-                                           output_token,
-                                           ret_flags,
-                                           time_rec);
-
-       if (*context_handle == GSS_C_NO_CONTEXT)
-           *context_handle = (gss_ctx_id_t) union_ctx_id;
-
-    } else
-       status = GSS_S_BAD_BINDINGS;
-
-    if (!union_name->mech_type) {
-       (void) __gss_release_internal_name(&temp_minor_status,
+    status = mech->gss_init_sec_context(
+       mech->context,
+       minor_status,
+       input_cred_handle,
+       &union_ctx_id->internal_ctx_id,
+       internal_name,
+       mech_type,
+       req_flags,
+       time_req,
+       input_chan_bindings,
+       input_token,
+       actual_mech_type,
+       output_token,
+       ret_flags,
+       time_rec);
+
+    if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) {
+       /*
+        * the spec says (the preferred) method is to delete all
+        * context info on the first call to init, and on all
+        * subsequent calls make the caller responsible for
+        * calling gss_delete_sec_context
+        */
+       if (*context_handle == GSS_C_NO_CONTEXT) {
+           free(union_ctx_id->mech_type->elements);
+           free(union_ctx_id->mech_type);
+           free(union_ctx_id);
+       }
+    } else if (*context_handle == GSS_C_NO_CONTEXT)
+       *context_handle = (gss_ctx_id_t)union_ctx_id;
+
+end:
+    if (union_name->mech_name == NULL ||
+       union_name->mech_name != internal_name) {
+       (void) gssint_release_internal_name(&temp_minor_status,
                                           mech_type, &internal_name);
     }
 
index 09e14deed11fbdc9a4fcee5b2ca2de086d00c160..21677562756034eff3df5779d3f18cc991fc7287 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)g_initialize.c 1.2     96/02/06 SMI" */
+/* #pragma ident       "@(#)g_initialize.c     1.36    05/02/02 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
 #include <ctype.h>
 #include <errno.h>
 
-#ifdef USE_SOLARIS_SHARED_LIBRARIES
 #include <dlfcn.h>
 
-#define MECH_CONF "/etc/mech.conf"
+#define        MECH_CONF "/etc/gss/mech"
+
+#define        MECH_LIB_PREFIX1        "/usr/lib/"
+
+#define        MECH_LIB_PREFIX2        ""
+
+#define        MECH_LIB_DIR            "gss/"
+
+#define        MECH_LIB_PREFIX MECH_LIB_PREFIX1 MECH_LIB_PREFIX2 MECH_LIB_DIR
+
 #define MECH_SYM "gss_mech_initialize"
 
-static void solaris_initialize (void);
-#endif /* USE_SOLARIS_SHARED_LIBRARIES */
+#define        M_DEFAULT       "default"
+
+#include <sys/stat.h>
+
+#include "k5-thread.h"
+
+/* Local functions */
+static gss_mech_info searchMechList(const gss_OID);
+static void loadConfigFile(const char *);
+static void updateMechList(void);
+static void register_mech(gss_mechanism, const char *, void *);
+
+static OM_uint32 build_mechSet(void);
+static void init_hardcoded(void);
+
+/*
+ * list of mechanism libraries and their entry points.
+ * the list also maintains state of the mech libraries (loaded or not).
+ */
+static gss_mech_info g_mechList = NULL;
+static gss_mech_info g_mechListTail = NULL;
+static k5_mutex_t g_mechListLock = K5_MUTEX_PARTIAL_INITIALIZER;
+static time_t g_confFileModTime = (time_t)0;
+
+static time_t g_mechSetTime = (time_t)0;
+static gss_OID_set_desc g_mechSet = { 0, NULL };
+static k5_mutex_t g_mechSetLock = K5_MUTEX_PARTIAL_INITIALIZER;
+
+int
+gssint_mechglue_init(void)
+{
+       int err;
 
-#define g_OID_equal(o1,o2) \
-   (((o1)->length == (o2)->length) && \
-    (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0))
+       err = k5_mutex_finish_init(&g_mechSetLock);
+       return k5_mutex_finish_init(&g_mechListLock);
+}
 
-extern gss_mechanism krb5_gss_initialize();
+void
+gssint_mechglue_fini(void)
+{
+       k5_mutex_destroy(&g_mechSetLock);
+       k5_mutex_destroy(&g_mechListLock);
+}
 
-static int _gss_initialized = 0;
 
-static struct gss_config null_mech = {
-  {0,NULL}};
+/*
+ * function used to reclaim the memory used by a gss_OID structure.
+ * This routine requires direct access to the mechList.
+ */
+OM_uint32 KRB5_CALLCONV
+gss_release_oid(minor_status, oid)
+OM_uint32 *minor_status;
+gss_OID *oid;
+{
+       OM_uint32 major;
+       gss_mech_info aMech;
+
+       if (minor_status == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+       *minor_status = 0;
+
+       k5_mutex_lock(&g_mechListLock);
+       aMech = g_mechList;
+       while (aMech != NULL) {
+
+               /*
+                * look through the loaded mechanism libraries for
+                * gss_internal_release_oid until one returns success.
+                * gss_internal_release_oid will only return success when
+                * the OID was recognized as an internal mechanism OID. if no
+                * mechanisms recognize the OID, then call the generic version.
+                */
+               if (aMech->mech && aMech->mech->gss_internal_release_oid) {
+                       major = aMech->mech->gss_internal_release_oid(
+                                       aMech->mech->context,
+                                       minor_status, oid);
+                       if (major == GSS_S_COMPLETE) {
+                               k5_mutex_unlock(&g_mechListLock);
+                               return (GSS_S_COMPLETE);
+                       }
+               }
+               aMech = aMech->next;
+       } /* while */
+       k5_mutex_unlock(&g_mechListLock);
+
+       return (generic_gss_release_oid(minor_status, oid));
+} /* gss_release_oid */
 
-gss_mechanism *__gss_mechs_array = NULL;
 
 /*
- * This function will add a new mechanism to the mechs_array
+ * this function will return an oid set indicating available mechanisms.
+ * The set returned is based on configuration file entries and
+ * NOT on the loaded mechanisms.  This function does not check if any
+ * of these can actually be loaded.
+ * This routine needs direct access to the mechanism list.
+ * To avoid reading the configuration file each call, we will save a
+ * a mech oid set, and only update it once the file has changed.
  */
+OM_uint32 KRB5_CALLCONV
+gss_indicate_mechs(minorStatus, mechSet)
+OM_uint32 *minorStatus;
+gss_OID_set *mechSet;
+{
+       char *fileName;
+       struct stat fileInfo;
+       int i, j;
+       gss_OID curItem;
+
+       if (!minorStatus)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+       if (gssint_initialize_library())
+               return GSS_S_FAILURE;
+
+       *minorStatus = 0;
+
+
+       /* check output parameter */
+       if (mechSet == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+       fileName = MECH_CONF;
+
+#if 0
+       /*
+        * If we have already computed the mechanisms supported and if it
+        * is still valid; make a copy and return to caller,
+        * otherwise build it first.
+        */
+       if ((stat(fileName, &fileInfo) == 0 &&
+               fileInfo.st_mtime > g_mechSetTime)) {
+       } /* if g_mechSet is out of date or not initialized */
+#endif
+       if (build_mechSet())
+               return GSS_S_FAILURE;
+
+       /*
+        * the mech set is created and it is up to date
+        * so just copy it to caller
+        */
+       if ((*mechSet =
+               (gss_OID_set) malloc(sizeof (gss_OID_set_desc))) == NULL)
+       {
+               return (GSS_S_FAILURE);
+       }
+
+       /*
+        * need to lock the g_mechSet in case someone tries to update it while
+        * I'm copying it.
+        */
+       (void) k5_mutex_lock(&g_mechSetLock);
+
+       /* allocate space for the oid structures */
+       if (((*mechSet)->elements =
+               (void*) calloc(g_mechSet.count, sizeof (gss_OID_desc)))
+               == NULL)
+       {
+               (void) k5_mutex_unlock(&g_mechSetLock);
+               free(*mechSet);
+               *mechSet = NULL;
+               return (GSS_S_FAILURE);
+       }
+
+       /* now copy the oid structures */
+       (void) memcpy((*mechSet)->elements, g_mechSet.elements,
+               g_mechSet.count * sizeof (gss_OID_desc));
+
+       (*mechSet)->count = g_mechSet.count;
+
+       /* still need to copy each of the oid elements arrays */
+       for (i = 0; i < (*mechSet)->count; i++) {
+               curItem = &((*mechSet)->elements[i]);
+               curItem->elements =
+                       (void *) malloc(g_mechSet.elements[i].length);
+               if (curItem->elements == NULL) {
+                       (void) k5_mutex_unlock(&g_mechSetLock);
+                       /*
+                        * must still free the allocated elements for
+                        * each allocated gss_OID_desc
+                        */
+                       for (j = 0; j < i; j++) {
+                               free((*mechSet)->elements[j].elements);
+                       }
+                       free((*mechSet)->elements);
+                       free(mechSet);
+                       *mechSet = NULL;
+                       return (GSS_S_FAILURE);
+               }
+               g_OID_copy(curItem, &g_mechSet.elements[i]);
+       }
+       (void) k5_mutex_unlock(&g_mechSetLock);
+       return (GSS_S_COMPLETE);
+} /* gss_indicate_mechs */
+
 
 static OM_uint32
-add_mechanism (mech, replace)
-     gss_mechanism mech;
-     int replace;
+build_mechSet(void)
 {
-    gss_mechanism *    temp_array;
-    gss_OID_set                mech_names;
-    OM_uint32          minor_status, major_status;
-    unsigned int       i;
+       gss_mech_info mList;
+       int i, count;
+       gss_OID curItem;
+
+       /*
+        * lock the mutex since we will be updating
+        * the mechList structure
+        * we need to keep the lock while we build the mechanism list
+        * since we are accessing parts of the mechList which could be
+        * modified.
+        */
+       (void) k5_mutex_lock(&g_mechListLock);
+
+#if 0
+       /*
+        * this checks for the case when we need to re-construct the
+        * g_mechSet structure, but the mechanism list is upto date
+        * (because it has been read by someone calling
+        * gssint_get_mechanism)
+        */
+       if (fileInfo.st_mtime > g_confFileModTime)
+       {
+               g_confFileModTime = fileInfo.st_mtime;
+               loadConfigFile(fileName);
+       }
+#endif
+
+       updateMechList();
+
+       /*
+        * we need to lock the mech set so that no one else will
+        * try to read it as we are re-creating it
+        */
+       (void) k5_mutex_lock(&g_mechSetLock);
+
+       /* if the oid list already exists we must free it first */
+       if (g_mechSet.count != 0) {
+               for (i = 0; i < g_mechSet.count; i++)
+                       free(g_mechSet.elements[i].elements);
+               free(g_mechSet.elements);
+               g_mechSet.elements = NULL;
+               g_mechSet.count = 0;
+       }
+
+       /* determine how many elements to have in the list */
+       mList = g_mechList;
+       count = 0;
+       while (mList != NULL) {
+               count++;
+               mList = mList->next;
+       }
+
+       /* this should always be true, but.... */
+       if (count > 0) {
+               g_mechSet.elements =
+                       (gss_OID) calloc(count, sizeof (gss_OID_desc));
+               if (g_mechSet.elements == NULL) {
+                       (void) k5_mutex_unlock(&g_mechSetLock);
+                       (void) k5_mutex_unlock(&g_mechListLock);
+                       return (GSS_S_FAILURE);
+               }
+
+               (void) memset(g_mechSet.elements, 0,
+                             count * sizeof (gss_OID_desc));
+
+               /* now copy each oid element */
+               g_mechSet.count = count;
+               count = 0;
+               mList = g_mechList;
+               while (mList != NULL) {
+                       curItem = &(g_mechSet.elements[count]);
+                       curItem->elements = (void*)
+                               malloc(mList->mech_type->length);
+                       if (curItem->elements == NULL) {
+                               /*
+                                * this is nasty - we must delete the
+                                * part of the array already copied
+                                */
+                               for (i = 0; i < count; i++) {
+                                       free(g_mechSet.elements[i].
+                                            elements);
+                               }
+                               free(g_mechSet.elements);
+                               g_mechSet.count = 0;
+                               g_mechSet.elements = NULL;
+                               (void) k5_mutex_unlock(&g_mechSetLock);
+                               (void) k5_mutex_unlock(&g_mechListLock);
+                               return (GSS_S_FAILURE);
+                       }
+                       g_OID_copy(curItem, mList->mech_type);
+                       count++;
+                       mList = mList->next;
+               }
+       }
+
+#if 0
+       g_mechSetTime = fileInfo.st_mtime;
+#endif
+       (void) k5_mutex_unlock(&g_mechSetLock);
+       (void) k5_mutex_unlock(&g_mechListLock);
 
-    if (mech == NULL)
        return GSS_S_COMPLETE;
+}
 
-    /* initialize the mechs_array if it hasn't already been initialized */
-    if (__gss_mechs_array == NULL) {
-       __gss_mechs_array = (gss_mechanism *) malloc (sizeof(gss_mechanism));
 
-       if (__gss_mechs_array == NULL)
-           return ENOMEM;
+/*
+ * this function has been added for use by modules that need to
+ * know what (if any) optional parameters are supplied in the
+ * config file (MECH_CONF).
+ * It will return the option string for a specified mechanism.
+ * caller is responsible for freeing the memory
+ */
+char *
+gssint_get_modOptions(oid)
+const gss_OID oid;
+{
+       gss_mech_info aMech;
+       char *modOptions = NULL;
 
-       __gss_mechs_array[0] = &null_mech;
-    }
+       /* make sure we have fresh data */
+       (void) k5_mutex_lock(&g_mechListLock);
+       updateMechList();
 
-    /* 
-     * Find the length of __gss_mechs_array, and look for an existing
-     * entry for this OID
-     */
-    for (i=0; __gss_mechs_array[i]->mech_type.length != 0; i++) {
-       if (!g_OID_equal(&__gss_mechs_array[i]->mech_type,
-                        &mech->mech_type))
-           continue;
+       if ((aMech = searchMechList(oid)) == NULL ||
+               aMech->optionStr == NULL) {
+               (void) k5_mutex_unlock(&g_mechListLock);
+               return (NULL);
+       }
 
-       /* We found a match.  Replace it? */
-       if (!replace)
-           return GSS_S_FAILURE;
+       if (aMech->optionStr)
+               modOptions = strdup(aMech->optionStr);
+       (void) k5_mutex_unlock(&g_mechListLock);
 
-       __gss_mechs_array[i] = mech;
-       return GSS_S_COMPLETE;
-    }
+       return (modOptions);
+} /* gssint_get_modOptions */
 
-    /* we didn't find it -- add it to the end of the __gss_mechs_array */
-    temp_array = (gss_mechanism *) realloc(__gss_mechs_array,
-                                          (i+2)*sizeof(gss_mechanism));
+/*
+ * given a mechanism string return the mechanism oid
+ */
+OM_uint32
+gssint_mech_to_oid(const char *mechStr, gss_OID* oid)
+{
+       gss_mech_info aMech;
 
-    if (temp_array == NULL)
-       return ENOMEM;
+       if (oid == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
-    temp_array[i++] = mech;
-    temp_array[i] = &null_mech;
+       *oid = GSS_C_NULL_OID;
 
-    __gss_mechs_array = temp_array;
+       if ((mechStr == NULL) || (strlen(mechStr) == 0) ||
+               (strcasecmp(mechStr, M_DEFAULT) == 0))
+               return (GSS_S_COMPLETE);
 
-    /*
-     * OK, now let's register all of the name types this mechanism
-     * knows how to deal with.
-     */
-    major_status = gss_inquire_names_for_mech(&minor_status, &mech->mech_type,
-                                             &mech_names);
-    if (major_status != GSS_S_COMPLETE)
-       return (GSS_S_COMPLETE);
-    for (i=0; i < mech_names->count; i++) {
-       gss_add_mech_name_type(&minor_status, &mech_names->elements[i],
-                              &mech->mech_type);
-    }
-    (void) gss_release_oid_set(&minor_status, &mech_names);
+       /* ensure we have fresh data */
+       (void) k5_mutex_lock(&g_mechListLock);
+       updateMechList();
+       (void) k5_mutex_unlock(&g_mechListLock);
+
+       aMech = g_mechList;
+
+       /* no lock required - only looking at fields that are not updated */
+       while (aMech != NULL) {
+               if ((aMech->mechNameStr) &&
+                       strcmp(aMech->mechNameStr, mechStr) == 0) {
+                       *oid = aMech->mech_type;
+                       return (GSS_S_COMPLETE);
+               }
+               aMech = aMech->next;
+       }
+       return (GSS_S_FAILURE);
+} /* gssint_mech_to_oid */
 
-    return GSS_S_COMPLETE;
-}
 
-void gss_initialize ()
+/*
+ * Given the mechanism oid, return the readable mechanism name
+ * associated with that oid from the mech config file
+ * (/etc/gss/mech).
+ */
+const char *
+gssint_oid_to_mech(const gss_OID oid)
 {
-    gss_mechanism mech;
+       gss_mech_info aMech;
 
-    /* Make sure we've not run already */
-    if (_gss_initialized)
-       return;
-    _gss_initialized = 1;
+       if (oid == GSS_C_NULL_OID)
+               return (M_DEFAULT);
 
-#ifdef USE_SOLARIS_SHARED_LIBRARIES
-    solaris_initialize();
+       /* ensure we have fresh data */
+       (void) k5_mutex_lock(&g_mechListLock);
+       updateMechList();
+       aMech = searchMechList(oid);
+       (void) k5_mutex_unlock(&g_mechListLock);
 
-#else
-    /* 
-     * Use hard-coded in mechanisms...  I need to know what mechanisms
-     * are supported...  As more mechanisms become supported, they
-     * should be added here, unless shared libraries are used.
-     */
+       if (aMech == NULL)
+               return (NULL);
 
-    /* Initialize the krb5 mechanism */
-    mech = (gss_mechanism)krb5_gss_initialize();
-    if (mech)
-       add_mechanism (mech, 1);
+       return (aMech->mechNameStr);
+} /* gssint_oid_to_mech */
 
-#endif /* USE_SOLARIS_SHARED_LIBRARIES */
 
-    if (__gss_mechs_array == NULL) { /* this is very bad! */
-      fprintf(stderr,"gss_initialize fatal error: no mechanisms loaded!\n");
-      exit(-1);
-    }
+/*
+ * return a list of mechanism strings supported
+ * upon return the array is terminated with a NULL entry
+ */
+OM_uint32
+gssint_get_mechanisms(char *mechArray[], int arrayLen)
+{
+       gss_mech_info aMech;
+       int i;
+
+       if (gssint_initialize_library())
+               return GSS_S_FAILURE;
+       if (mechArray == NULL || arrayLen < 1)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+       /* ensure we have fresh data */
+       (void) k5_mutex_lock(&g_mechListLock);
+       updateMechList();
+       (void) k5_mutex_unlock(&g_mechListLock);
+
+       aMech = g_mechList;
+
+       /* no lock required - only looking at fields that are not updated */
+       for (i = 1; i < arrayLen; i++) {
+               if (aMech != NULL) {
+                       *mechArray = aMech->mechNameStr;
+                       mechArray++;
+                       aMech = aMech->next;
+               } else
+                       break;
+       }
+       *mechArray = NULL;
+       return (GSS_S_COMPLETE);
+} /* gss_get_mechanisms */
 
-    return;
+
+/*
+ * determines if the mechList needs to be updated from file
+ * and performs the update.
+ * this functions must be called with a lock of g_mechListLock
+ */
+static void
+updateMechList(void)
+{
+       char *fileName;
+       struct stat fileInfo;
+
+       init_hardcoded();
+       fileName = MECH_CONF;
+
+#if 0
+       /* check if mechList needs updating */
+       if (stat(fileName, &fileInfo) == 0 &&
+               (fileInfo.st_mtime > g_confFileModTime)) {
+               loadConfigFile(fileName);
+               g_confFileModTime = fileInfo.st_mtime;
+       }
+#endif
+} /* updateMechList */
+
+/*
+ * Register a mechanism.  Called with g_mechListLock held.
+ */
+static void
+register_mech(gss_mechanism mech, const char *namestr, void *dl_handle)
+{
+       gss_mech_info cf, new_cf;
+
+       new_cf = malloc(sizeof(*new_cf));
+       if (new_cf == NULL)
+               return;
+
+       memset(new_cf, 0, sizeof(*new_cf));
+       new_cf->kmodName = NULL;
+       new_cf->uLibName = strdup(namestr);
+       new_cf->mechNameStr = strdup(mech->mechNameStr);
+       new_cf->mech_type = &mech->mech_type;
+       new_cf->mech = mech;
+       new_cf->next = NULL;
+
+       if (g_mechList == NULL) {
+               g_mechList = new_cf;
+               g_mechListTail = new_cf;
+               return;
+       } else if (mech->priority < g_mechList->mech->priority) {
+               new_cf->next = g_mechList;
+               g_mechList = new_cf;
+               return;
+       }
+       for (cf = g_mechList; cf != NULL; cf = cf->next) {
+               if (cf->next == NULL ||
+                   mech->priority < cf->next->mech->priority) {
+                       new_cf->next = cf->next;
+                       cf->next = new_cf;
+                       if (g_mechListTail == cf) {
+                               g_mechListTail = new_cf;
+                       }
+                       break;
+               }
+       }
 }
 
-#ifdef USE_SOLARIS_SHARED_LIBRARIES
-/* 
- * read the configuration file to find out what mechanisms to
- * load, load them, and then load the mechanism defitions in
- * and add the mechanisms
+/*
+ * Initialize the hardcoded mechanisms.  This function is called with
+ * g_mechListLock held.
  */
-static void solaris_initialize ()
+static void
+init_hardcoded(void)
 {
-    char buffer[BUFSIZ], *filename, *symname, *endp;
-    FILE *conffile;
-    void *dl;
-    gss_mechanism (*sym)(void), mech;
+       extern gss_mechanism *krb5_gss_get_mech_configs(void);
+       extern gss_mechanism *spnego_gss_get_mech_configs(void);
+       gss_mechanism *cflist;
+       static int inited;
+       gss_mech_info cf;
+
+       if (inited)
+               return;
+
+       cflist = krb5_gss_get_mech_configs();
+       if (cflist == NULL)
+               return;
+       for ( ; *cflist != NULL; cflist++) {
+               register_mech(*cflist, "<builtin krb5>", NULL);
+       }
+       cflist = spnego_gss_get_mech_configs();
+       if (cflist == NULL)
+               return;
+       for ( ; *cflist != NULL; cflist++) {
+               register_mech(*cflist, "<builtin spnego>", NULL);
+       }
+       inited = 1;
+}
 
-    if ((filename = getenv("GSSAPI_MECH_CONF")) == NULL)
-       filename = MECH_CONF;
 
-    if ((conffile = fopen(filename, "r")) == NULL)
-       return;
+/*
+ * given the mechanism type, return the mechanism structure
+ * containing the mechanism library entry points.
+ * will return NULL if mech type is not found
+ * This function will also trigger the loading of the mechanism
+ * module if it has not been already loaded.
+ */
+gss_mechanism
+gssint_get_mechanism(oid)
+const gss_OID oid;
+{
+       gss_mech_info aMech;
+       gss_mechanism (*sym)(const gss_OID);
+       void *dl;
+
+       if (gssint_initialize_library())
+               return NULL;
+
+       (void) k5_mutex_lock(&g_mechListLock);
+       /* check if the mechanism is already loaded */
+       if ((aMech = searchMechList(oid)) != NULL && aMech->mech) {
+               (void) k5_mutex_unlock(&g_mechListLock);
+               return (aMech->mech);
+       }
 
-    while (fgets (buffer, BUFSIZ, conffile) != NULL) {
-       /* ignore lines beginning with # */
-       if (*buffer == '#')
-           continue;
+       /*
+        * might need to re-read the configuration file before loading
+        * the mechanism to ensure we have the latest info.
+        */
+       updateMechList();
 
-       /* find the first white-space character after the filename */
-       for (symname = buffer; *symname && !isspace(*symname); symname++);
+       aMech = searchMechList(oid);
 
-       /* Now find the first non-white-space character */
-       if (*symname) {
-           *symname = '\0';
-           symname++;
-           while (*symname && isspace(*symname))
-               symname++;
+       /* is the mechanism present in the list ? */
+       if (aMech == NULL) {
+               (void) k5_mutex_unlock(&g_mechListLock);
+               return ((gss_mechanism)NULL);
        }
 
-       if (! *symname)
-           symname = MECH_SYM;
-       else {
-         /* Find the end of the symname and make sure it is NULL-terminated */
-         for (endp = symname; *endp && !isspace(*endp); endp++);
-         if (*endp)
-           *endp = '\0';
+       /* has another thread loaded the mech */
+       if (aMech->mech) {
+               (void) k5_mutex_unlock(&g_mechListLock);
+               return (aMech->mech);
        }
 
-       if ((dl = dlopen(buffer, RTLD_NOW)) == NULL) {
-               /* for debugging only */
-               fprintf(stderr,"can't open %s: %s\n",buffer, dlerror());
-               continue;
+       /* we found the mechanism, but it is not loaded */
+       if ((dl = dlopen(aMech->uLibName, RTLD_NOW)) == NULL) {
+#if 0
+               (void) syslog(LOG_INFO, "libgss dlopen(%s): %s\n",
+                               aMech->uLibName, dlerror());
+#endif
+               (void) k5_mutex_unlock(&g_mechListLock);
+               return ((gss_mechanism)NULL);
        }
 
-       if ((sym = (gss_mechanism (*)(void))dlsym(dl, symname)) == NULL) {
-           dlclose(dl);
-           continue;
+       if ((sym = (gss_mechanism (*)(const gss_OID))dlsym(dl, MECH_SYM))
+                       == NULL) {
+               (void) dlclose(dl);
+#if 0
+               (void) syslog(LOG_INFO, "unable to initialize mechanism"
+                               " library [%s]\n", aMech->uLibName);
+#endif
+               (void) k5_mutex_unlock(&g_mechListLock);
+               return ((gss_mechanism)NULL);
        }
 
        /* Call the symbol to get the mechanism table */
-       mech = sym();
+       aMech->mech = (*sym)(aMech->mech_type);
+
+       if (aMech->mech == NULL) {
+               (void) dlclose(dl);
+#if 0
+               (void) syslog(LOG_INFO, "unable to initialize mechanism"
+                               " library [%s]\n", aMech->uLibName);
+#endif
+               (void) k5_mutex_unlock(&g_mechListLock);
+               return ((gss_mechanism)NULL);
+       }
+
+       aMech->dl_handle = dl;
+
+       (void) k5_mutex_unlock(&g_mechListLock);
+       return (aMech->mech);
+} /* gssint_get_mechanism */
 
-       /* And add the mechanism (or close the shared library) */
-       if (mech)
-           add_mechanism (mech, 1);
+gss_mechanism_ext
+gssint_get_mechanism_ext(oid)
+const gss_OID oid;
+{
+       gss_mech_info aMech;
+       gss_mechanism_ext mech_ext;
+
+       /* check if the mechanism is already loaded */
+       if ((aMech = searchMechList(oid)) != NULL && aMech->mech_ext != NULL)
+               return (aMech->mech_ext);
+
+       if (gssint_get_mechanism(oid) == NULL)
+               return (NULL);
+
+       if (aMech->dl_handle == NULL)
+               return (NULL);
+
+       /* Load the gss_config_ext struct for this mech */
+
+       mech_ext = (gss_mechanism_ext)malloc(sizeof (struct gss_config_ext));
+
+       if (mech_ext == NULL)
+               return (NULL);
+
+       /*
+        * dlsym() the mech's 'method' functions for the extended APIs
+        *
+        * NOTE:  Until the void *context argument is removed from the
+        * SPI method functions' signatures it will be necessary to have
+        * different function pointer typedefs and function names for
+        * the SPI methods than for the API.  When this argument is
+        * removed it will be possible to rename gss_*_sfct to gss_*_fct
+        * and and gssspi_* to gss_*.
+        */
+       mech_ext->gss_acquire_cred_with_password =
+               (gss_acquire_cred_with_password_sfct)dlsym(aMech->dl_handle,
+                       "gssspi_acquire_cred_with_password");
+
+       /* Set aMech->mech_ext */
+       (void) k5_mutex_lock(&g_mechListLock);
+
+       if (aMech->mech_ext == NULL)
+               aMech->mech_ext = mech_ext;
        else
-           dlclose(dl);
+               free(mech_ext); /* we raced and lost; don't leak */
 
-    } /* while */
+       (void) k5_mutex_unlock(&g_mechListLock);
 
-    return;
-}
-#endif /* USE_SOLARIS_SHARED_LIBRARIES */
+       return (aMech->mech_ext);
+
+} /* gssint_get_mechanism_ext */
+
+
+/*
+ * this routine is used for searching the list of mechanism data.
+ *
+ * this needs to be called with g_mechListLock held.
+ */
+static gss_mech_info searchMechList(oid)
+const gss_OID oid;
+{
+       gss_mech_info aMech = g_mechList;
+
+       /* if oid is null -> then get default which is the first in the list */
+       if (oid == GSS_C_NULL_OID)
+               return (aMech);
+
+       while (aMech != NULL) {
+               if (g_OID_equal(aMech->mech_type, oid))
+                       return (aMech);
+               aMech = aMech->next;
+       }
+
+       /* none found */
+       return ((gss_mech_info) NULL);
+} /* searchMechList */
+
+
+/*
+ * loads the configuration file
+ * this is called while having a mutex lock on the mechanism list
+ * entries for libraries that have been loaded can't be modified
+ * mechNameStr and mech_type fields are not updated during updates
+ */
+static void loadConfigFile(fileName)
+const char *fileName;
+{
+       char buffer[BUFSIZ], *oidStr, *oid, *sharedLib, *kernMod, *endp;
+       char *modOptions;
+       char sharedPath[sizeof (MECH_LIB_PREFIX) + BUFSIZ];
+       char *tmpStr;
+       FILE *confFile;
+       gss_OID mechOid;
+       gss_mech_info aMech, tmp;
+       OM_uint32 minor;
+       gss_buffer_desc oidBuf;
+
+       if ((confFile = fopen(fileName, "r")) == NULL) {
+               return;
+       }
+
+       (void) memset(buffer, 0, sizeof (buffer));
+       while (fgets(buffer, BUFSIZ, confFile) != NULL) {
+
+               /* ignore lines beginning with # */
+               if (*buffer == '#')
+                       continue;
+
+               /*
+                * find the first white-space character after
+                * the mechanism name
+                */
+               oidStr = buffer;
+               for (oid = buffer; *oid && !isspace(*oid); oid++);
+
+               /* Now find the first non-white-space character */
+               if (*oid) {
+                       *oid = '\0';
+                       oid++;
+                       while (*oid && isspace(*oid))
+                               oid++;
+               }
+
+               /*
+                * If that's all, then this is a corrupt entry. Skip it.
+                */
+               if (! *oid)
+                       continue;
+
+               /* Find the end of the oid and make sure it is NULL-ended */
+               for (endp = oid; *endp && !isspace(*endp); endp++)
+                       ;
+
+               if (*endp) {
+                       *endp = '\0';
+               }
+
+               /*
+                * check if an entry for this oid already exists
+                * if it does, and the library is already loaded then
+                * we can't modify it, so skip it
+                */
+               oidBuf.value = (void *)oid;
+               oidBuf.length = strlen(oid);
+               if (generic_gss_str_to_oid(&minor, &oidBuf, &mechOid)
+                       != GSS_S_COMPLETE) {
+#if 0
+                       (void) syslog(LOG_INFO, "invalid mechanism oid"
+                                       " [%s] in configuration file", oid);
+#endif
+                       continue;
+               }
+
+               k5_mutex_lock(&g_mechListLock);
+               aMech = searchMechList(mechOid);
+               if (aMech && aMech->mech) {
+                       free(mechOid->elements);
+                       free(mechOid);
+                       k5_mutex_unlock(&g_mechListLock);
+                       continue;
+               }
+               k5_mutex_unlock(&g_mechListLock);
+
+               /* Find the start of the shared lib name */
+               for (sharedLib = endp+1; *sharedLib && isspace(*sharedLib);
+                       sharedLib++)
+                       ;
+
+               /*
+                * If that's all, then this is a corrupt entry. Skip it.
+                */
+               if (! *sharedLib) {
+                       free(mechOid->elements);
+                       free(mechOid);
+                       continue;
+               }
+
+               /*
+                * Find the end of the shared lib name and make sure it is
+                *  NULL-terminated.
+                */
+               for (endp = sharedLib; *endp && !isspace(*endp); endp++)
+                       ;
+
+               if (*endp) {
+                       *endp = '\0';
+               }
+
+               /* Find the start of the optional kernel module lib name */
+               for (kernMod = endp+1; *kernMod && isspace(*kernMod);
+                       kernMod++)
+                       ;
+
+               /*
+                * If this item starts with a bracket "[", then
+                * it is not a kernel module, but is a list of
+                * options for the user module to parse later.
+                */
+               if (*kernMod && *kernMod != '[') {
+                       /*
+                        * Find the end of the shared lib name and make sure
+                        * it is NULL-terminated.
+                        */
+                       for (endp = kernMod; *endp && !isspace(*endp); endp++)
+                               ;
+
+                       if (*endp) {
+                               *endp = '\0';
+                       }
+               } else
+                       kernMod = NULL;
+
+               /* Find the start of the optional module options list */
+               for (modOptions = endp+1; *modOptions && isspace(*modOptions);
+                       modOptions++);
+
+               if (*modOptions == '[')  {
+                       /* move past the opening bracket */
+                       for (modOptions = modOptions+1;
+                           *modOptions && isspace(*modOptions);
+                           modOptions++);
+
+                       /* Find the closing bracket */
+                       for (endp = modOptions;
+                               *endp && *endp != ']'; endp++);
+
+                       if (endp)
+                               *endp = '\0';
+
+               } else {
+                       modOptions = NULL;
+               }
+
+               (void) strcpy(sharedPath, MECH_LIB_PREFIX);
+               (void) strcat(sharedPath, sharedLib);
+
+               /*
+                * are we creating a new mechanism entry or
+                * just modifying existing (non loaded) mechanism entry
+                */
+               if (aMech) {
+                       /*
+                        * delete any old values and set new
+                        * mechNameStr and mech_type are not modified
+                        */
+                       if (aMech->kmodName) {
+                               free(aMech->kmodName);
+                               aMech->kmodName = NULL;
+                       }
+
+                       if (aMech->optionStr) {
+                               free(aMech->optionStr);
+                               aMech->optionStr = NULL;
+                       }
+
+                       if ((tmpStr = strdup(sharedPath)) != NULL) {
+                               if (aMech->uLibName)
+                                       free(aMech->uLibName);
+                               aMech->uLibName = tmpStr;
+                       }
+
+                       if (kernMod) /* this is an optional parameter */
+                               aMech->kmodName = strdup(kernMod);
+
+                       if (modOptions) /* optional module options */
+                               aMech->optionStr = strdup(modOptions);
+
+                       /* the oid is already set */
+                       free(mechOid->elements);
+                       free(mechOid);
+                       continue;
+               }
+
+               /* adding a new entry */
+               aMech = malloc(sizeof (struct gss_mech_config));
+               if (aMech == NULL) {
+                       free(mechOid->elements);
+                       free(mechOid);
+                       continue;
+               }
+               (void) memset(aMech, 0, sizeof (struct gss_mech_config));
+               aMech->mech_type = mechOid;
+               aMech->uLibName = strdup(sharedPath);
+               aMech->mechNameStr = strdup(oidStr);
+
+               /* check if any memory allocations failed - bad news */
+               if (aMech->uLibName == NULL || aMech->mechNameStr == NULL) {
+                       if (aMech->uLibName)
+                               free(aMech->uLibName);
+                       if (aMech->mechNameStr)
+                               free(aMech->mechNameStr);
+                       free(mechOid->elements);
+                       free(mechOid);
+                       free(aMech);
+                       continue;
+               }
+               if (kernMod)    /* this is an optional parameter */
+                       aMech->kmodName = strdup(kernMod);
+
+               if (modOptions)
+                       aMech->optionStr = strdup(modOptions);
+               /*
+                * add the new entry to the end of the list - make sure
+                * that only complete entries are added because other
+                * threads might currently be searching the list.
+                */
+               tmp = g_mechListTail;
+               g_mechListTail = aMech;
+
+               if (tmp != NULL)
+                       tmp->next = aMech;
+
+               if (g_mechList == NULL)
+                       g_mechList = aMech;
+       } /* while */
+       (void) fclose(confFile);
+} /* loadConfigFile */
index 3f28c484fca8f49170a0af9102d04c53cd5ff2ea..e717aa3473b5c93fcb0c6469c482b8a9a9992c6f 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident      "@(#)g_inquire_context.c 1.2     96/01/18 SMI" */
+/* #pragma ident       "@(#)g_inquire_context.c        1.15    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -59,13 +59,26 @@ int *               open;
     gss_union_ctx_id_t ctx;
     gss_mechanism      mech;
     OM_uint32          status, temp_minor;
+    gss_name_t localTargName = NULL, localSourceName = NULL;
     
-    gss_initialize();
+    if (!minor_status)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
-    /* if the context_handle is Null, return NO_CONTEXT error */
+    *minor_status = 0;
     
-    if(context_handle == GSS_C_NO_CONTEXT)
-       return(GSS_S_NO_CONTEXT);
+    /* if the context_handle is Null, return NO_CONTEXT error */
+    if (context_handle == GSS_C_NO_CONTEXT)
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    /* set all output value to NULL */
+    if (src_name)
+       *src_name = NULL;
+
+    if (targ_name)
+       *targ_name = NULL;
+
+    if (mech_type)
+       *mech_type = NULL;
     
     /*
      * select the approprate underlying mechanism routine and
@@ -73,21 +86,21 @@ int *               open;
      */
     
     ctx = (gss_union_ctx_id_t) context_handle;
-    mech = __gss_get_mechanism (ctx->mech_type);
+    mech = gssint_get_mechanism (ctx->mech_type);
     
-    if (!mech || !mech->gss_inquire_context || !mech->gss_display_name) {
-       return(GSS_S_NO_CONTEXT);
-
+    if (!mech || !mech->gss_inquire_context || !mech->gss_display_name ||
+       !mech->gss_release_name) {
+       return (GSS_S_UNAVAILABLE);
     }
 
     status = mech->gss_inquire_context(
                        mech->context,
                        minor_status,
                        ctx->internal_ctx_id,
-                       src_name,
-                       targ_name,
+                       (src_name ? &localSourceName : NULL),
+                       (targ_name ? &localTargName : NULL),
                        lifetime_rec,
-                       mech_type,
+                       NULL,
                        ctx_flags,
                        locally_initiated,
                        open);
@@ -99,34 +112,33 @@ int *              open;
     /* need to convert names */
 
     if (src_name) {
-           status = __gss_convert_name_to_union_name(minor_status, mech,
-                                                     *src_name, src_name);
+           status = gssint_convert_name_to_union_name(minor_status, mech,
+                                                     localSourceName, src_name);
 
            if (status != GSS_S_COMPLETE) {
-               (void) mech->gss_release_name(mech->context,
-                                               &temp_minor, src_name);
-               (void) mech->gss_release_name(mech->context,
-                                               &temp_minor, targ_name);
-               if (mech_type) {
-                               gss_release_oid(&temp_minor, mech_type);
-               }
-               return (GSS_S_FAILURE);
+               if (localTargName)
+                   mech->gss_release_name(mech->context,
+                                          &temp_minor, &localTargName);
+               return (status);
            }
 
     }
 
     if (targ_name) {
-           status = __gss_convert_name_to_union_name(minor_status, mech,
-                                                     *targ_name, targ_name);
+           status = gssint_convert_name_to_union_name(minor_status, mech,
+                                                     localTargName, targ_name);
 
            if (status != GSS_S_COMPLETE) {
-               if (mech_type) {
-                       gss_release_oid(&temp_minor, mech_type);
-               }
-               return (GSS_S_FAILURE);
+               if (src_name)
+                   (void) gss_release_name(&temp_minor, src_name);
+
+               return (status);
            }
     }
 
+    /* spec says mech type must point to static storage */
+    if (mech_type)
+       *mech_type = &mech->mech_type;
     return(GSS_S_COMPLETE);
 }
 
index e0a2bc4a83ee1f37652519702dc3f7944aab930f..c4b59114d35d1b7995d05d9dcbd309b73dd63b93 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_inquire_cred.c 1.9     95/08/02 SMI" */
+/* #pragma ident       "@(#)g_inquire_cred.c   1.16    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -56,7 +56,16 @@ gss_OID_set *                mechanisms;
     gss_name_t         internal_name;
     int                        i;
     
-    gss_initialize();
+    /* check parms and set to defaults */
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (name)
+       *name = NULL;
+
+    if (mechanisms)
+       *mechanisms = NULL;
 
     if (cred_handle == GSS_C_NO_CREDENTIAL) {
        /*
@@ -67,11 +76,11 @@ gss_OID_set *               mechanisms;
         * array, which becomes the default mechanism.
         */
 
-       if ((mech = __gss_get_mechanism(GSS_C_NULL_OID)) == NULL)
-           return(GSS_S_NO_CRED);
+       if ((mech = gssint_get_mechanism(GSS_C_NULL_OID)) == NULL)
+           return (GSS_S_DEFECTIVE_CREDENTIAL);
 
        if (!mech->gss_inquire_cred)
-               return (GSS_S_FAILURE);
+           return (GSS_S_UNAVAILABLE);
        
        status = mech->gss_inquire_cred(mech->context, minor_status,
                                        GSS_C_NO_CREDENTIAL,
@@ -85,14 +94,16 @@ gss_OID_set *               mechanisms;
            /*
             * Convert internal_name into a union_name equivalent.
             */
-           status = __gss_convert_name_to_union_name(&temp_minor_status,
+           status = gssint_convert_name_to_union_name(&temp_minor_status,
                                                      mech, internal_name,
                                                      name);
            if (status != GSS_S_COMPLETE) {
-               if (minor_status)
-                   *minor_status = temp_minor_status;
-               __gss_release_internal_name(&temp_minor_status,
-                                           &mech->mech_type, &internal_name);
+               *minor_status = temp_minor_status;
+               if (mechanisms && *mechanisms) {
+                   (void) gss_release_oid_set(
+                       &temp_minor_status,
+                       mechanisms);
+               }
                return (status);
            }
        }
@@ -124,39 +135,68 @@ gss_OID_set *             mechanisms;
      * caller. If this call fails, return failure to our caller.
      */
     
-    if(name != NULL)
-       if(gss_import_name(&temp_minor_status,
-                          &union_cred->auxinfo.name,
-                          union_cred->auxinfo.name_type,
-                          name) != GSS_S_COMPLETE)
-           return(GSS_S_DEFECTIVE_CREDENTIAL);
-    
+    if(name != NULL) {
+       if ((gss_import_name(&temp_minor_status,
+                            &union_cred->auxinfo.name,
+                            union_cred->auxinfo.name_type,
+                            name) != GSS_S_COMPLETE) ||
+           (gss_canonicalize_name(minor_status, *name,
+                                  &union_cred->mechs_array[0],
+                                  NULL) != GSS_S_COMPLETE)) {
+           status = GSS_S_DEFECTIVE_CREDENTIAL;
+           goto error;
+       }
+    }
+
     /*
      * copy the mechanism set in union_cred into an OID set and return in
      * the mechanisms parameter.
      */
     
     if(mechanisms != NULL) {
-
+       status = GSS_S_FAILURE;
        *mechanisms = (gss_OID_set) malloc(sizeof(gss_OID_set_desc));
+       if (*mechanisms == NULL)
+           goto error;
 
-       (*mechanisms)->count = union_cred->count;
+       (*mechanisms)->count = 0;
        (*mechanisms)->elements =
            (gss_OID) malloc(sizeof(gss_OID_desc) *
                             union_cred->count);
 
+       if ((*mechanisms)->elements == NULL) {
+           free(*mechanisms);
+           *mechanisms = NULL;
+           goto error;
+       }
+
        for(i=0; i < union_cred->count; i++) {
-           (*mechanisms)->elements[i].length =
-               union_cred->mechs_array[i].length;
            (*mechanisms)->elements[i].elements = (void *)
                malloc(union_cred->mechs_array[i].length);
-           memcpy((*mechanisms)->elements[i].elements,
-                  union_cred->mechs_array[i].elements,
-                  union_cred->mechs_array[i].length);
+           if ((*mechanisms)->elements[i].elements == NULL)
+               goto error;
+           g_OID_copy(&(*mechanisms)->elements[i],
+                      &union_cred->mechs_array[i]);
+           (*mechanisms)->count++;
        }
     }
     
     return(GSS_S_COMPLETE);
+
+error:
+    /*
+     * cleanup any allocated memory - we can just call
+     * gss_release_oid_set, because the set is constructed so that
+     * count always references the currently copied number of
+     * elements.
+     */
+    if (mechanisms && *mechanisms != NULL)
+       (void) gss_release_oid_set(&temp_minor_status, mechanisms);
+
+    if (name && *name != NULL)
+       (void) gss_release_name(&temp_minor_status, name);
+
+    return (status);
 }
 
 OM_uint32 KRB5_CALLCONV
@@ -173,19 +213,46 @@ gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name,
     gss_union_cred_t   union_cred;
     gss_cred_id_t      mech_cred;
     gss_mechanism      mech;
+    OM_uint32          status, temp_minor_status;
+    gss_name_t         internal_name;
+
 
-    mech = __gss_get_mechanism (mech_type);
+    mech = gssint_get_mechanism (mech_type);
     if (!mech)
        return (GSS_S_BAD_MECH);
     if (!mech->gss_inquire_cred_by_mech)
        return (GSS_S_BAD_BINDINGS);
      
     union_cred = (gss_union_cred_t) cred_handle;
-    mech_cred = __gss_get_mechanism_cred(union_cred, mech_type);
+    mech_cred = gssint_get_mechanism_cred(union_cred, mech_type);
+
+#if 0
+    if (mech_cred == NULL)
+       return (GSS_S_DEFECTIVE_CREDENTIAL);
+#endif
+
+    status = mech->gss_inquire_cred_by_mech(mech->context, minor_status,
+                                           mech_cred, mech_type,
+                                           name ? &internal_name : NULL,
+                                           initiator_lifetime,
+                                           acceptor_lifetime, cred_usage);
+       
+    if (status != GSS_S_COMPLETE)
+       return (status);
+
+    if (name) {
+       /*
+        * Convert internal_name into a union_name equivalent.
+        */
+       status = gssint_convert_name_to_union_name(
+           &temp_minor_status, mech,
+           internal_name, name);
+       if (status != GSS_S_COMPLETE) {
+           *minor_status = temp_minor_status;
+           return (status);
+       }
+    }
 
-    return (mech->gss_inquire_cred_by_mech(mech->context, minor_status,
-                                          mech_cred, mech_type,
-                                          name, initiator_lifetime,
-                                          acceptor_lifetime, cred_usage));
+    return (GSS_S_COMPLETE);
 }
 
index 7c07f44edd0730d9207b465c0ae9db1a8d35e547..4332e3e0ce6ae547e9abd2adf481899f9ebf4ff5 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident      "@(#)g_inquire_names.c 1.1     95/12/19 SMI" */
+/* #pragma ident       "@(#)g_inquire_names.c  1.16    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -28,6 +28,8 @@
 
 #include "mglueP.h"
 
+#define        MAX_MECH_OID_PAIRS 32
+
 /* Last argument new for V2 */
 OM_uint32 KRB5_CALLCONV
 gss_inquire_names_for_mech(minor_status, mechanism, name_types)
@@ -40,14 +42,19 @@ gss_OID_set *       name_types;
     OM_uint32          status;
     gss_mechanism      mech;
     
-    gss_initialize();
-    
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (name_types == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
     /*
      * select the approprate underlying mechanism routine and
      * call it.
      */
     
-    mech = __gss_get_mechanism (mechanism);
+    mech = gssint_get_mechanism (mechanism);
     
     if (mech) {
 
@@ -58,10 +65,93 @@ gss_OID_set *       name_types;
                                mechanism,
                                name_types);
        else
-           status = GSS_S_BAD_BINDINGS;
+           status = GSS_S_UNAVAILABLE;
 
        return(status);
     }
     
-    return(GSS_S_NO_CONTEXT);
+    return (GSS_S_BAD_MECH);
+}
+OM_uint32 KRB5_CALLCONV
+gss_inquire_mechs_for_name(minor_status, input_name, mech_set)
+
+    OM_uint32 *                minor_status;
+    const gss_name_t   input_name;
+    gss_OID_set *              mech_set;
+
+{
+    OM_uint32          status;
+    static char                *mech_list[MAX_MECH_OID_PAIRS+1];
+    gss_OID_set                mech_name_types;
+    int                        present;
+    char                       *mechanism;
+    gss_OID            mechOid;
+    gss_OID            name_type;
+    gss_buffer_desc            name_buffer;
+    int                        i;
+
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (input_name == NULL)
+       return (GSS_S_BAD_NAME);
+
+    status = gss_create_empty_oid_set(minor_status, mech_set);
+    if (status != GSS_S_COMPLETE)
+       return (status);
+    *mech_list = NULL;
+    status = gssint_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1);
+    if (status != GSS_S_COMPLETE)
+       return (status);
+    for (i = 0; i < MAX_MECH_OID_PAIRS && mech_list[i] != NULL; i++) {
+       mechanism = mech_list[i];
+       if (gssint_mech_to_oid(mechanism, &mechOid) == GSS_S_COMPLETE) {
+           status = gss_inquire_names_for_mech(
+               minor_status,
+               mechOid,
+               &mech_name_types);
+           if (status == GSS_S_COMPLETE) {
+               status = gss_display_name(minor_status,
+                                         input_name,
+                                         &name_buffer,
+                                         &name_type);
+
+               (void) gss_release_buffer(NULL, &name_buffer);
+
+               if (status == GSS_S_COMPLETE && name_type) {
+                   status = gss_test_oid_set_member(
+                       minor_status,
+                       name_type,
+                       mech_name_types,
+                       &present);
+                   if (status == GSS_S_COMPLETE &&
+                       present) {
+                       status = gss_add_oid_set_member(
+                           minor_status,
+                           mechOid,
+                           mech_set);
+                       if (status != GSS_S_COMPLETE) {
+                           (void) gss_release_oid_set(
+                               minor_status,
+                               &mech_name_types);
+                           (void) gss_release_oid_set(
+                               minor_status,
+                               mech_set);
+                           return (status);
+                       }
+                   }
+               }
+               (void) gss_release_oid_set(
+                   minor_status,
+                   &mech_name_types);
+           }
+       } else {
+           (void) gss_release_oid_set(
+               minor_status,
+               mech_set);
+           return (GSS_S_FAILURE);
+       }
+    }
+    return (GSS_S_COMPLETE);
 }
index c013bdc155d92981fcf022a3e954825e6f8f2232..0607c38f10b062156237cb5ff3d4455a07900ff2 100644 (file)
 #include <string.h>
 #include <errno.h>
 
-#define g_OID_equal(o1,o2) \
-   (((o1)->length == (o2)->length) && \
-    (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0))
-
 static gss_mech_spec_name name_list = NULL;
 
 /*
index 4a9d765f27021a0038019953c98ab11c0193c749..86e57972d2a6f810265df9d5e86c41ae9c42c29a 100644 (file)
@@ -1,3 +1,4 @@
+/* #pragma ident       "@(#)g_oid_ops.c        1.11    98/01/22 SMI" */
 /*
  * lib/gssapi/mechglue/g_oid_ops.c
  *
 #include "mglueP.h"
 /* should include to get protos #include "../generic/gssapiP_generic.h" */
 
-extern gss_mechanism *__gss_mechs_array;
+extern gss_mechanism *gssint_mechs_array;
 
-OM_uint32 KRB5_CALLCONV
-gss_release_oid(minor_status, oid)
-    OM_uint32  *minor_status;
-    gss_OID    *oid;
-{
-    int i;
-    OM_uint32   major_status;
-
-    /* first call the gss_internal_release_oid for each mechanism
-     * until one returns success. gss_internal_release_oid will only return
-     * success when the OID was recognized as an internal mechanism OID.
-     * if no mechanisms recognize the OID, then call the generic version.
-     */
-
-    for(i=0; __gss_mechs_array[i]->mech_type.length !=0; i++) {
-        if (__gss_mechs_array[i]->gss_internal_release_oid) {
-           major_status = __gss_mechs_array[i]->gss_internal_release_oid(
-                                           __gss_mechs_array[i]->context,
-                                           minor_status,
-                                           oid);
-           if (major_status == GSS_S_COMPLETE) {
-               return (GSS_S_COMPLETE);
-           }
-       }
-    }
-
-    return generic_gss_release_oid(minor_status, oid);
-}
+/*
+ * gss_release_oid has been moved to g_initialize, becasue it requires access
+ * to the mechanism list.  All functions requiring direct access to the
+ * mechanism list are now in g_initialize.c
+ */
 
 OM_uint32 KRB5_CALLCONV
 gss_create_empty_oid_set(minor_status, oid_set)
index dcb4716bc4dacfbcebd0e69f830c167efd6840ad..beb65a141dc1cdc5b3838530405910b3e67c97de 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_process_context.c 1.9     95/08/07 SMI" */
+/* #pragma ident       "@(#)g_process_context.c        1.12    98/01/22 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -42,10 +42,15 @@ gss_buffer_t                token_buffer;
     gss_union_ctx_id_t ctx;
     gss_mechanism      mech;
     
-    gss_initialize();
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
 
     if (context_handle == GSS_C_NO_CONTEXT)
-       return GSS_S_NO_CONTEXT;
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    if (GSS_EMPTY_BUFFER(token_buffer))
+       return (GSS_S_CALL_INACCESSIBLE_READ);
 
     /*
      * select the approprate underlying mechanism routine and
@@ -53,7 +58,7 @@ gss_buffer_t          token_buffer;
      */
     
     ctx = (gss_union_ctx_id_t) context_handle;
-    mech = __gss_get_mechanism (ctx->mech_type);
+    mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
 
@@ -64,10 +69,10 @@ gss_buffer_t                token_buffer;
                                                    ctx->internal_ctx_id,
                                                    token_buffer);
        else
-           status = GSS_S_BAD_BINDINGS;
+           status = GSS_S_UNAVAILABLE;
 
        return(status);
     }
     
-    return(GSS_S_NO_CONTEXT);
+    return (GSS_S_BAD_MECH);
 }
index 44d82709e41706f539f20fa12c6294f0e3b91f52..ffcce2d7e1a74144fe8db2e35eded720c2f273df 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_release_cred.c 1.15     95/08/07 SMI" */
+/* #pragma ident       "@(#)g_rel_cred.c       1.14    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -45,15 +45,13 @@ gss_cred_id_t *             cred_handle;
     gss_union_cred_t   union_cred;
     gss_mechanism      mech;
     
-    gss_initialize();
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
-    if (minor_status)
-       *minor_status = 0;
+    *minor_status = 0;
 
-    /* if the cred_handle is null, return a NO_CRED error */
-    
-    if (cred_handle == GSS_C_NO_CREDENTIAL)
-       return(GSS_S_NO_CRED);
+    if (cred_handle == NULL)
+       return (GSS_S_NO_CRED | GSS_S_CALL_INACCESSIBLE_READ);
     
     /*
      * Loop through the union_cred struct, selecting the approprate 
@@ -64,14 +62,14 @@ gss_cred_id_t *             cred_handle;
     union_cred = (gss_union_cred_t) *cred_handle;
     *cred_handle = NULL;
 
-    if (union_cred == NULL)
-       return GSS_S_NO_CRED;
+    if (union_cred == (gss_union_cred_t)GSS_C_NO_CREDENTIAL)
+       return (GSS_S_COMPLETE);
 
     status = GSS_S_COMPLETE;
     
     for(j=0; j < union_cred->count; j++) {
 
-       mech = __gss_get_mechanism (&union_cred->mechs_array[j]);
+       mech = gssint_get_mechanism (&union_cred->mechs_array[j]);
 
        if (union_cred->mechs_array[j].elements)
                free(union_cred->mechs_array[j].elements);
@@ -86,9 +84,9 @@ gss_cred_id_t *               cred_handle;
                status = GSS_S_NO_CRED;
 
            } else
-               status = GSS_S_NO_CRED;
+               status = GSS_S_UNAVAILABLE;
        } else
-           status = GSS_S_NO_CRED;
+           status = GSS_S_DEFECTIVE_CREDENTIAL;
     }
 
     gss_release_buffer(minor_status, &union_cred->auxinfo.name);
index 29c3f98199c0d2a3345b26b3fc393685ce3aba1a..ff3c4a10a60cc8ed9221ce52bd551da5186a7dbd 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_release_name.c 1.2     95/05/09 SMI" */
+/* #pragma ident       "@(#)g_rel_name.c       1.11    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -43,11 +43,17 @@ gss_name_t *                input_name;
 {
     gss_union_name_t   union_name;
     
-    /* if input_name is NULL, return error */
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
     
+    /* if input_name is NULL, return error */
     if (input_name == 0)
-       return(GSS_S_BAD_NAME);
-    
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+    if (*input_name == GSS_C_NO_NAME)
+       return GSS_S_COMPLETE;
+
     /*
      * free up the space for the external_name and then
      * free the union_name descriptor
@@ -56,9 +62,6 @@ gss_name_t *          input_name;
     union_name = (gss_union_name_t) *input_name;
     *input_name = 0;
     *minor_status = 0;
-    
-    if (union_name == NULL)
-       return GSS_S_BAD_NAME;
 
     if (union_name->name_type)
            gss_release_oid(minor_status, &union_name->name_type);
@@ -67,7 +70,7 @@ gss_name_t *          input_name;
     free(union_name->external_name);
 
     if (union_name->mech_type) {
-           __gss_release_internal_name(minor_status, union_name->mech_type,
+           gssint_release_internal_name(minor_status, union_name->mech_type,
                                        &union_name->mech_name);
            gss_release_oid(minor_status, &union_name->mech_type);
     }
index 357c00e67e3d107309a57b1ac3089c3c90a06192..f712a891a13298c0f168eb7d697b4c320564fe4e 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_release_oid_set.c 1.12     95/08/23 SMI" */
+/* #pragma ident       "@(#)g_rel_oid_set.c    1.12    97/11/11 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -39,8 +39,8 @@ gss_release_oid_set (minor_status,
 OM_uint32 *            minor_status;
 gss_OID_set *          set;
 {
-   size_t index;
-   gss_OID oid;
+    OM_uint32 index;
+    gss_OID oid;
     if (minor_status)
        *minor_status = 0;
 
index 7d66e469aee4288c8e85e7fd743a3a2b4a5c3bab..2b31c370f1d128c037cdaf39df044d30c0076f26 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_seal.c 1.10     95/08/07 SMI" */
+/* #pragma ident       "@(#)g_seal.c   1.19    98/04/21 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -44,16 +44,25 @@ int                 qop_req;
 gss_buffer_t           input_message_buffer;
 int *                  conf_state;
 gss_buffer_t           output_message_buffer;
-
 {
+ /* EXPORT DELETE START */
+
     OM_uint32          status;
     gss_union_ctx_id_t ctx;
     gss_mechanism      mech;
 
-    gss_initialize();
-    
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
     if (context_handle == GSS_C_NO_CONTEXT)
-       return GSS_S_NO_CONTEXT;
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    if (input_message_buffer == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (output_message_buffer == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
     /*
      * select the approprate underlying mechanism routine and
@@ -61,7 +70,7 @@ gss_buffer_t          output_message_buffer;
      */
     
     ctx = (gss_union_ctx_id_t) context_handle;
-    mech = __gss_get_mechanism (ctx->mech_type);
+    mech = gssint_get_mechanism (ctx->mech_type);
     
     if (mech) {
        if (mech->gss_seal)
@@ -75,12 +84,13 @@ gss_buffer_t                output_message_buffer;
                                    conf_state,
                                    output_message_buffer);
        else
-           status = GSS_S_BAD_BINDINGS;
+           status = GSS_S_UNAVAILABLE;
        
        return(status);
     }
-
-    return(GSS_S_NO_CONTEXT);
+ /* EXPORT DELETE END */
+    return (GSS_S_BAD_MECH);
 }
 
 OM_uint32 KRB5_CALLCONV
@@ -101,9 +111,10 @@ int *                      conf_state;
 gss_buffer_t           output_message_buffer;
 
 {
-       return gss_seal(minor_status, context_handle, conf_req_flag,
-                       (int) qop_req, input_message_buffer, conf_state,
-                       output_message_buffer);
+    return gss_seal(minor_status, (gss_ctx_id_t)context_handle,
+                   conf_req_flag, (int) qop_req,
+                   (gss_buffer_t)input_message_buffer, conf_state,
+                   output_message_buffer);
 }
 
 /*
@@ -119,14 +130,18 @@ gss_wrap_size_limit(minor_status, context_handle, conf_req_flag,
     OM_uint32          req_output_size;
     OM_uint32          *max_input_size;
 {
-    OM_uint32          status;
     gss_union_ctx_id_t ctx;
     gss_mechanism      mech;
 
-    gss_initialize();
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
     
     if (context_handle == GSS_C_NO_CONTEXT)
-       return GSS_S_NO_CONTEXT;
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    if (max_input_size == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
     /*
      * select the approprate underlying mechanism routine and
@@ -134,16 +149,15 @@ gss_wrap_size_limit(minor_status, context_handle, conf_req_flag,
      */
     
     ctx = (gss_union_ctx_id_t) context_handle;
-    mech = __gss_get_mechanism (ctx->mech_type);
+    mech = gssint_get_mechanism (ctx->mech_type);
 
     if (!mech)
-       return (GSS_S_NO_CONTEXT);
+       return (GSS_S_BAD_MECH);
 
     if (!mech->gss_wrap_size_limit)
-       return (GSS_S_BAD_BINDINGS);
+       return (GSS_S_UNAVAILABLE);
     
-    status = mech->gss_wrap_size_limit(mech->context, minor_status,
-                                      context_handle, conf_req_flag, qop_req,
-                                      req_output_size, max_input_size);
-    return(status);
+    return (mech->gss_wrap_size_limit(mech->context, minor_status,
+                                     ctx->internal_ctx_id, conf_req_flag, qop_req,
+                                     req_output_size, max_input_size));
 }
index 4dfd3ec7188850cf95f606aea25261c01a4b8067..72e0ce742c77951d7ecf8e7dbd3584d4c83eb920 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_sign.c 1.10     95/08/07 SMI" */
+/* #pragma ident       "@(#)g_sign.c   1.14    98/04/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -46,18 +46,28 @@ gss_buffer_t                msg_token;
     gss_union_ctx_id_t ctx;
     gss_mechanism      mech;
 
-    gss_initialize();
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
 
     if (context_handle == GSS_C_NO_CONTEXT)
-       return GSS_S_NO_CONTEXT;
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
 
+    if (message_buffer == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (msg_token == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    msg_token->value = NULL;
+    msg_token->length = 0;
     /*
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
-    mech = __gss_get_mechanism (ctx->mech_type);
+    mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
        if (mech->gss_sign)
@@ -69,12 +79,12 @@ gss_buffer_t                msg_token;
                                    message_buffer,
                                    msg_token);
        else
-           status = GSS_S_BAD_BINDINGS;
+           status = GSS_S_UNAVAILABLE;
 
        return(status);
     }
 
-    return(GSS_S_NO_CONTEXT);
+    return (GSS_S_BAD_MECH);
 }
 
 OM_uint32 KRB5_CALLCONV
diff --git a/src/lib/gssapi/mechglue/g_store_cred.c b/src/lib/gssapi/mechglue/g_store_cred.c
new file mode 100644 (file)
index 0000000..92581be
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident       "@(#)g_store_cred.c     1.2     04/04/05 SMI" */
+
+/*
+ *  glue routine for gss_store_cred
+ */
+
+#include <mglueP.h>
+
+OM_uint32 gss_store_cred(minor_status,
+                       input_cred_handle,
+                       cred_usage,
+                       desired_mech,
+                       overwrite_cred,
+                       default_cred,
+                       elements_stored,
+                       cred_usage_stored)
+
+OM_uint32              *minor_status;
+const 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;
+
+{
+       OM_uint32               major_status = GSS_S_FAILURE;
+       gss_union_cred_t        union_cred;
+       gss_cred_id_t           mech_cred;
+       gss_mechanism           mech;
+       gss_OID                 dmech;
+       int                     i;
+
+       /* Start by checking parameters */
+       if (minor_status == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE|GSS_S_NO_CRED);
+       *minor_status = 0;
+
+       if (input_cred_handle == GSS_C_NO_CREDENTIAL)
+               return (GSS_S_CALL_INACCESSIBLE_READ);
+
+       if (elements_stored != NULL)
+               *elements_stored = GSS_C_NULL_OID_SET;
+
+       if (cred_usage_stored != NULL)
+               *cred_usage_stored = GSS_C_BOTH; /* there's no GSS_C_NEITHER */
+
+       union_cred = (gss_union_cred_t)input_cred_handle;
+
+       /* desired_mech != GSS_C_NULL_OID -> store one element */
+       if (desired_mech != GSS_C_NULL_OID) {
+               mech = gssint_get_mechanism(desired_mech);
+               if (mech == NULL)
+                       return (GSS_S_BAD_MECH);
+
+               if (mech->gss_store_cred == NULL)
+                       return (major_status);
+
+               mech_cred = gssint_get_mechanism_cred(union_cred, desired_mech);
+               if (mech_cred == GSS_C_NO_CREDENTIAL)
+                       return (GSS_S_NO_CRED);
+
+               return (mech->gss_store_cred(mech->context,
+                                               minor_status,
+                                               (gss_cred_id_t)mech_cred,
+                                               cred_usage,
+                                               desired_mech,
+                                               overwrite_cred,
+                                               default_cred,
+                                               elements_stored,
+                                               cred_usage_stored));
+       }
+
+       /* desired_mech == GSS_C_NULL_OID -> store all elements */
+
+       *minor_status = 0;
+
+       for (i = 0; i < union_cred->count; i++) {
+               /* Get mech and cred element */
+               dmech = &union_cred->mechs_array[i];
+               mech = gssint_get_mechanism(dmech);
+               if (mech == NULL)
+                       continue;
+
+               if (mech->gss_store_cred == NULL)
+                       continue;
+
+               mech_cred = gssint_get_mechanism_cred(union_cred, dmech);
+               if (mech_cred == GSS_C_NO_CREDENTIAL)
+                       continue; /* can't happen, but safe to ignore */
+
+               major_status = mech->gss_store_cred(mech->context,
+                                               minor_status,
+                                               (gss_cred_id_t)mech_cred,
+                                               cred_usage,
+                                               dmech,
+                                               overwrite_cred,
+                                               default_cred,
+                                               NULL,
+                                               cred_usage_stored);
+               if (major_status != GSS_S_COMPLETE)
+                       continue;
+
+               /* Succeeded for at least one mech */
+
+               if (elements_stored == NULL)
+                       continue;
+
+               if (*elements_stored == GSS_C_NULL_OID_SET) {
+                       major_status = gss_create_empty_oid_set(minor_status,
+                                               elements_stored);
+
+                       if (GSS_ERROR(major_status))
+                               return (major_status);
+               }
+
+               major_status = gss_add_oid_set_member(minor_status, dmech,
+                       elements_stored);
+
+               /* The caller should clean up elements_stored */
+               if (GSS_ERROR(major_status))
+                       return (major_status);
+       }
+
+       /*
+        * Success with some mechs may mask failure with others, but
+        * that's what elements_stored is for.
+        */
+       return (major_status);
+}
index 9ca1c15129cde71fe50c85f81354132b4062a39a..c70c59beb0f14a9ade48ed37be449654e6b9bacd 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_unseal.c 1.10     95/08/07 SMI" */
+/* #pragma ident       "@(#)g_unseal.c 1.13    98/01/22 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -44,14 +44,26 @@ int *                       conf_state;
 int *                  qop_state;
 
 {
+/* EXPORT DELETE START */
     OM_uint32          status;
     gss_union_ctx_id_t ctx;
     gss_mechanism      mech;
 
-    gss_initialize();
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
 
     if (context_handle == GSS_C_NO_CONTEXT)
-       return GSS_S_NO_CONTEXT;
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    if (GSS_EMPTY_BUFFER(input_message_buffer))
+       return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (output_message_buffer == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    output_message_buffer->length = 0;
+    output_message_buffer->value = NULL;
 
     /*
      * select the approprate underlying mechanism routine and
@@ -59,7 +71,7 @@ int *                 qop_state;
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
-    mech = __gss_get_mechanism (ctx->mech_type);
+    mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
        if (mech->gss_unseal) 
@@ -72,12 +84,14 @@ int *                       qop_state;
                                      conf_state,
                                      qop_state);
        else
-           status = GSS_S_BAD_BINDINGS;
+           status = GSS_S_UNAVAILABLE;
 
        return(status);
     }
 
-    return(GSS_S_NO_CONTEXT);
+/* EXPORT DELETE END */
+
+    return (GSS_S_BAD_MECH);
 }
 
 OM_uint32 KRB5_CALLCONV
@@ -89,15 +103,14 @@ gss_unwrap (minor_status,
             qop_state)
 
 OM_uint32 *            minor_status;
-gss_ctx_id_t           context_handle;
-gss_buffer_t           input_message_buffer;
+const gss_ctx_id_t     context_handle;
+const gss_buffer_t     input_message_buffer;
 gss_buffer_t           output_message_buffer;
 int *                  conf_state;
 gss_qop_t *            qop_state;
 
 {
-       return (gss_unseal(minor_status, context_handle,
-                          input_message_buffer,
-                          output_message_buffer,
-                          conf_state, (int *) qop_state));
+    return (gss_unseal(minor_status, (gss_ctx_id_t)context_handle,
+                      (gss_buffer_t)input_message_buffer,
+                      output_message_buffer, conf_state, (int *) qop_state));
 }
diff --git a/src/lib/gssapi/mechglue/g_userok.c b/src/lib/gssapi/mechglue/g_userok.c
new file mode 100644 (file)
index 0000000..4657b8e
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident       "@(#)g_userok.c 1.1     04/03/25 SMI" */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <mglueP.h>
+#include <gssapi/gssapi.h>
+
+
+static OM_uint32
+compare_names(OM_uint32 *minor,
+           const gss_OID mech_type,
+           const gss_name_t name,
+           const char *user,
+           int *user_ok)
+{
+
+       OM_uint32 status, tmpMinor;
+       gss_name_t imported_name;
+       gss_name_t canon_name;
+       gss_buffer_desc gss_user;
+       int match = 0;
+
+       *user_ok = 0;
+
+       gss_user.value = (void *)user;
+       if (!gss_user.value || !name || !mech_type)
+               return (GSS_S_BAD_NAME);
+       gss_user.length = strlen(gss_user.value);
+
+       status = gss_import_name(minor,
+                               &gss_user,
+                               GSS_C_NT_USER_NAME,
+                               &imported_name);
+       if (status != GSS_S_COMPLETE) {
+               goto out;
+       }
+
+       status = gss_canonicalize_name(minor,
+                                   imported_name,
+                                   mech_type,
+                                   &canon_name);
+       if (status != GSS_S_COMPLETE) {
+               (void) gss_release_name(&tmpMinor, &imported_name);
+               goto out;
+       }
+
+       status = gss_compare_name(minor,
+                               canon_name,
+                               name,
+                               &match);
+       (void) gss_release_name(&tmpMinor, &canon_name);
+       (void) gss_release_name(&tmpMinor, &imported_name);
+       if (status == GSS_S_COMPLETE) {
+               if (match)
+                       *user_ok = 1; /* remote user is a-ok */
+       }
+
+out:
+       return (status);
+}
+
+
+OM_uint32
+gssint_userok(OM_uint32 *minor,
+           const gss_name_t name,
+           const char *user,
+           int *user_ok)
+
+{
+       gss_mechanism mech;
+       gss_union_name_t intName;
+       gss_name_t mechName = NULL;
+       OM_uint32 major;
+
+       if (minor == NULL || user_ok == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+       if (name == NULL || user == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_READ);
+
+       *user_ok = 0;
+       *minor = GSS_S_COMPLETE;
+
+       intName = (gss_union_name_t)name;
+
+       mech = gssint_get_mechanism(intName->mech_type);
+       if (mech == NULL)
+               return (GSS_S_UNAVAILABLE);
+
+       /* may need to import the name if this is not MN */
+       if (intName->mech_type == NULL) {
+               return (GSS_S_FAILURE);
+       } else
+               mechName = intName->mech_name;
+
+       if (mech->gssint_userok)
+               major = mech->gssint_userok(mech->context,  minor, mechName,
+                               user, user_ok);
+       else
+               major = compare_names(minor, intName->mech_type,
+                                   name, user, user_ok);
+
+       return (major);
+} /* gss_userok */
diff --git a/src/lib/gssapi/mechglue/g_utils.c b/src/lib/gssapi/mechglue/g_utils.c
new file mode 100644 (file)
index 0000000..82fe70d
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident       "@(#)g_utils.c  1.8     04/02/23 SMI" */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <ctype.h>
+#include <errno.h>
+#include <gssapi/gssapi.h>
+
+#define        Q_DEFAULT               "default"
+#define        BUFLEN                  256
+
+#if 0
+static int qop_num_pair_cnt;
+static const char    QOP_NUM_FILE[] = "/etc/gss/qop";
+static qop_num qop_num_pairs[MAX_QOP_NUM_PAIRS+1];
+static mutex_t qopfile_lock = DEFAULTMUTEX;
+
+static OM_uint32 gssint_read_qop_file(void);
+
+/*
+ * This routine fetches qop and num from "/etc/gss/qop".
+ * There is a memory leak associated with rereading this file,
+ * because we can't free the qop_num_pairs array when we reread
+ * the file (some callers may have been given these pointers).
+ * In general, this memory leak should be a small one, because
+ * we don't expect the qop file to be changed and reread often.
+ */
+static OM_uint32
+gssint_read_qop_file(void)
+{
+       char    buf[BUFLEN];    /* one line from the file */
+       char    *name, *next;
+       char    *qopname, *num_str;
+       char    *line;
+       FILE    *fp;
+       static int last = 0;
+       struct stat stbuf;
+       OM_uint32 major = GSS_S_COMPLETE;
+
+       (void) mutex_lock(&qopfile_lock);
+       if (stat(QOP_NUM_FILE, &stbuf) != 0 || stbuf.st_mtime < last) {
+               if (!qop_num_pairs[0].qop) {
+                       major = GSS_S_FAILURE;
+               }
+               goto done;
+       }
+       last = stbuf.st_mtime;
+
+       fp = fopen(QOP_NUM_FILE, "r");
+       if (fp == (FILE *)0) {
+               major = GSS_S_FAILURE;
+               goto done;
+       }
+
+       /*
+        * For each line in the file parse it appropriately.
+        * File format : qopname        num(int)
+        * Note that we silently ignore corrupt entries.
+        */
+       qop_num_pair_cnt = 0;
+       while (!feof(fp)) {
+               line = fgets(buf, BUFLEN, fp);
+               if (line == NULL)
+                       break;
+
+               /* Skip comments and blank lines */
+               if ((*line == '#') || (*line == '\n'))
+                       continue;
+
+               /* Skip trailing comments */
+               next = strchr(line, '#');
+               if (next)
+                       *next = '\0';
+
+               name = &(buf[0]);
+               while (isspace(*name))
+                       name++;
+               if (*name == '\0')      /* blank line */
+                       continue;
+
+               qopname = name; /* will contain qop name */
+               while (!isspace(*qopname))
+                       qopname++;
+               if (*qopname == '\0') {
+                       continue;
+               }
+               next = qopname+1;
+               *qopname = '\0';        /* null terminate qopname */
+               qop_num_pairs[qop_num_pair_cnt].qop = strdup(name);
+               if (qop_num_pairs[qop_num_pair_cnt].qop == NULL)
+                       continue;
+
+               name = next;
+               while (isspace(*name))
+                       name++;
+               if (*name == '\0') {    /* end of line, no num */
+                       free(qop_num_pairs[qop_num_pair_cnt].qop);
+                       continue;
+               }
+               num_str = name; /* will contain num (n) */
+               while (!isspace(*num_str))
+                       num_str++;
+               next = num_str+1;
+               *num_str++ = '\0';      /* null terminate num_str */
+
+               qop_num_pairs[qop_num_pair_cnt].num = (OM_uint32)atoi(name);
+               name = next;
+               while (isspace(*name))
+                       name++;
+               if (*name == '\0') {    /* end of line, no mechanism */
+                       free(qop_num_pairs[qop_num_pair_cnt].qop);
+                       continue;
+               }
+               num_str = name; /* will contain mech */
+               while (!isspace(*num_str))
+                       num_str++;
+               *num_str = '\0';
+
+               qop_num_pairs[qop_num_pair_cnt].mech = strdup(name);
+               if (qop_num_pairs[qop_num_pair_cnt].mech == NULL) {
+                       free(qop_num_pairs[qop_num_pair_cnt].qop);
+                       continue;
+               }
+
+               if (qop_num_pair_cnt++ >= MAX_QOP_NUM_PAIRS)
+                       break;
+       }
+       (void) fclose(fp);
+done:
+       (void) mutex_unlock(&qopfile_lock);
+       return (major);
+}
+
+OM_uint32
+gssint_qop_to_num(
+       char            *qop,
+       char            *mech,
+       OM_uint32       *num
+)
+{
+       int i;
+       OM_uint32 major = GSS_S_FAILURE;
+
+       if (!num)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+       if (qop == NULL || strlen(qop) == 0 ||
+                       strcasecmp(qop, Q_DEFAULT) == 0) {
+               *num = GSS_C_QOP_DEFAULT;
+               return (GSS_S_COMPLETE);
+       }
+
+       if ((major = gssint_read_qop_file()) != GSS_S_COMPLETE)
+               return (major);
+
+       for (i = 0; i < qop_num_pair_cnt; i++) {
+               if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
+                   (strcasecmp(qop, qop_num_pairs[i].qop) == 0)) {
+                       *num = qop_num_pairs[i].num;
+                       return (GSS_S_COMPLETE);
+               }
+       }
+
+       return (GSS_S_FAILURE);
+}
+
+OM_uint32
+gssint_num_to_qop(
+       char            *mech,
+       OM_uint32       num,
+       char            **qop
+)
+{
+       int i;
+       OM_uint32 major;
+
+       if (!qop)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+       *qop = NULL;
+
+       if (num == GSS_C_QOP_DEFAULT) {
+               *qop = Q_DEFAULT;
+               return (GSS_S_COMPLETE);
+       }
+
+       if (mech == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_READ);
+
+       if ((major = gssint_read_qop_file()) != GSS_S_COMPLETE)
+               return (major);
+
+       for (i = 0; i < qop_num_pair_cnt; i++) {
+               if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
+                   (num == qop_num_pairs[i].num)) {
+                       *qop = qop_num_pairs[i].qop;
+                       return (GSS_S_COMPLETE);
+               }
+       }
+       return (GSS_S_FAILURE);
+}
+
+/*
+ * For a given mechanism pass back qop information about it in a buffer
+ * of size MAX_QOPS_PER_MECH+1.
+ */
+OM_uint32
+gssint_get_mech_info(
+       char            *mech,
+       char            **qops
+)
+{
+       int i, cnt = 0;
+       OM_uint32 major = GSS_S_COMPLETE;
+
+       if (!qops)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+       *qops = NULL;
+
+       if (!mech)
+               return (GSS_S_CALL_INACCESSIBLE_READ);
+
+       if ((major = gssint_read_qop_file()) != GSS_S_COMPLETE)
+               return (major);
+
+       for (i = 0; i < qop_num_pair_cnt; i++) {
+               if (strcmp(mech, qop_num_pairs[i].mech) == 0) {
+                   if (cnt >= MAX_QOPS_PER_MECH) {
+                       return (GSS_S_FAILURE);
+                   }
+                   qops[cnt++] = qop_num_pairs[i].qop;
+               }
+       }
+       qops[cnt] = NULL;
+       return (GSS_S_COMPLETE);
+}
+
+/*
+ * Copy the qop values and names for the mechanism back in a qop_num
+ * buffer of size MAX_QOPS_PER_MECH provided by the caller.
+ */
+OM_uint32
+gssint_mech_qops(
+       char *mech,
+       qop_num *mechqops,
+       int *numqop
+)
+{
+       int i;
+       OM_uint32 major;
+       int cnt = 0;
+
+       if (!mechqops || !numqop)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+       *numqop = 0;
+
+       if (!mech)
+               return (GSS_S_CALL_INACCESSIBLE_READ);
+
+       if ((major = gssint_read_qop_file()) != GSS_S_COMPLETE)
+               return (major);
+
+       for (i = 0; i < qop_num_pair_cnt; i++) {
+           if (strcasecmp(mech, qop_num_pairs[i].mech) == 0) {
+               if (cnt >= MAX_QOPS_PER_MECH) {
+                       return (GSS_S_FAILURE);
+               }
+               mechqops[cnt++] = qop_num_pairs[i];
+           }
+       }
+       *numqop = cnt;
+       return (GSS_S_COMPLETE);
+}
+#endif
index 7fc86b448b251d671dad297c8572caeb2ced8849..e6a01282ab4fd707d150b5f38637be27f64f3021 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gss_verify.c 1.9     95/08/07 SMI" */
+/* #pragma ident       "@(#)g_verify.c 1.13    98/04/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -46,10 +46,16 @@ int *                       qop_state;
     gss_union_ctx_id_t ctx;
     gss_mechanism      mech;
 
-    gss_initialize();
+
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
 
     if (context_handle == GSS_C_NO_CONTEXT)
-       return GSS_S_NO_CONTEXT;
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    if ((message_buffer == NULL) || GSS_EMPTY_BUFFER(token_buffer))
+       return (GSS_S_CALL_INACCESSIBLE_READ);
 
     /*
      * select the approprate underlying mechanism routine and
@@ -57,7 +63,7 @@ int *                 qop_state;
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
-    mech = __gss_get_mechanism (ctx->mech_type);
+    mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
        if (mech->gss_verify)
@@ -69,12 +75,12 @@ int *                       qop_state;
                                      token_buffer,
                                      qop_state);
        else
-           status = GSS_S_BAD_BINDINGS;
+           status = GSS_S_UNAVAILABLE;
 
        return(status);
     }
 
-    return(GSS_S_NO_CONTEXT);
+    return (GSS_S_BAD_MECH);
 }
 
 OM_uint32 KRB5_CALLCONV
index eb7c051acdc9825124925cd67f5cb5d690fd06bd..f15b16c5db17cdc797ea31bd796e3bc6e6b63da5 100644 (file)
@@ -1,4 +1,4 @@
-/* #ident  "@(#)gssd_pname_to_uid.c 1.5     95/08/02 SMI" */
+/* #pragma ident       "@(#)gssd_pname_to_uid.c        1.18    04/02/23 SMI" */
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
@@ -42,14 +42,12 @@ uid_t * uid;
     int status;
     gss_mechanism      mech;
 
-    gss_initialize();
-
     /*
      * find the appropriate mechanism specific pname_to_uid procedure and
      * call it.
      */
 
-    mech = __gss_get_mechanism (mech_type);
+    mech = gssint_get_mechanism (mech_type);
 
     if (mech) {
        if (mech_type == GSS_C_NULL_OID)
index c9a7d4ee3899b298ca851d56f54d9c32d066129c..bfee2524a8ab3f996e12b049f4a3ade6ccba84c6 100644 (file)
 #ifndef _GSS_MECHGLUEP_H
 #define _GSS_MECHGLUEP_H
 
+#include "autoconf.h"
 #include "mechglue.h"
+#include "gssapiP_generic.h"
+
+#define        g_OID_copy(o1, o2)                                      \
+do {                                                           \
+       memcpy((o1)->elements, (o2)->elements, (o2)->length);   \
+       (o1)->length = (o2)->length;                            \
+} while (0)
+
+#define        GSS_EMPTY_BUFFER(buf)   ((buf) == NULL ||\
+       (buf)->value == NULL || (buf)->length == 0)
 
 /*
  * Array of context IDs typed by mechanism OID
@@ -50,7 +61,7 @@ typedef struct gss_mech_spec_name_t {
 typedef struct gss_union_cred_auxinfo {
        gss_buffer_desc         name;
        gss_OID                 name_type;
-       time_t                  creation_time;
+       OM_uint32               creation_time;
        OM_uint32               time_rec;
        int                     cred_usage;
 } gss_union_cred_auxinfo;
@@ -61,10 +72,23 @@ typedef struct gss_union_cred_auxinfo {
 typedef struct gss_union_cred_t {
        int                     count;
        gss_OID                 mechs_array;
-       gss_cred_id_t *         cred_array;
+       gss_cred_id_t           *cred_array;
        gss_union_cred_auxinfo  auxinfo;
 } gss_union_cred_desc, *gss_union_cred_t;
  
+typedef        OM_uint32           (*gss_acquire_cred_with_password_sfct)(
+                   void *,             /* context */
+                   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 */
+       /* */);
+
 /********************************************************/
 /* The Mechanism Dispatch Table -- a mechanism needs to */
 /* define one of these and provide a function to return */
@@ -82,6 +106,8 @@ typedef struct gss_union_cred_t {
  */
  
 typedef struct gss_config {
+    OM_uint32      priority;
+    char *         mechNameStr;
     gss_OID_desc    mech_type;
     void *         context;
     OM_uint32       (*gss_acquire_cred)
@@ -334,79 +360,165 @@ typedef struct gss_config {
                    gss_OID,            /* mech type */
                    uid_t *             /* uid */
                    );
-
+       OM_uint32               (*gssint_userok)
+       (
+                   void *,             /* context */
+                   OM_uint32 *,        /* minor_status */
+                   const gss_name_t,   /* pname */
+                   const char *,       /* local user */
+                   int *               /* user ok? */
+       /* */);
+       OM_uint32               (*gss_export_name)
+       (
+               void *,                 /* context */
+               OM_uint32 *,            /* minor_status */
+               const gss_name_t,       /* input_name */
+               gss_buffer_t            /* exported_name */
+       /* */);
+       OM_uint32       (*gss_store_cred)
+       (
+               void *,                 /* context */
+               OM_uint32 *,            /* minor_status */
+               const gss_cred_id_t,    /* input_cred */
+               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 */
+       /* */);
 } *gss_mechanism;
 
+/* This structure MUST NOT be used by any code outside libgss */
+typedef struct gss_config_ext {
+       gss_acquire_cred_with_password_sfct     gss_acquire_cred_with_password;
+} *gss_mechanism_ext;
+
+/*
+ * In the user space we use a wrapper structure to encompass the
+ * mechanism entry points.  The wrapper contain the mechanism
+ * entry points and other data which is only relevant to the gss-api
+ * layer.  In the kernel we use only the gss_config strucutre because
+ * the kernal does not cantain any of the extra gss-api specific data.
+ */
+typedef struct gss_mech_config {
+       char *kmodName;                 /* kernel module name */
+       char *uLibName;                 /* user library name */
+       char *mechNameStr;              /* mechanism string name */
+       char *optionStr;                /* optional mech parameters */
+       void *dl_handle;                /* RTLD object handle for the mech */
+       gss_OID mech_type;              /* mechanism oid */
+       gss_mechanism mech;             /* mechanism initialization struct */
+       gss_mechanism_ext mech_ext;     /* extensions */
+       struct gss_mech_config *next;   /* next element in the list */
+} *gss_mech_info;
+
 /********************************************************/
 /* Internal mechglue routines */
 
-gss_mechanism __gss_get_mechanism (gss_OID);
-OM_uint32 __gss_get_mech_type (gss_OID, gss_buffer_t);
-OM_uint32 __gss_import_internal_name (OM_uint32 *, gss_OID, gss_union_name_t,
+int gssint_mechglue_init(void);
+void gssint_mechglue_fini(void);
+
+gss_mechanism gssint_get_mechanism (gss_OID);
+gss_mechanism_ext gssint_get_mechanism_ext(const gss_OID);
+OM_uint32 gssint_get_mech_type (gss_OID, gss_buffer_t);
+char *gssint_get_kmodName(const gss_OID);
+char *gssint_get_modOptions(const gss_OID);
+OM_uint32 gssint_import_internal_name (OM_uint32 *, gss_OID, gss_union_name_t,
                                      gss_name_t *);
-OM_uint32 __gss_display_internal_name (OM_uint32 *, gss_OID, gss_name_t,
+OM_uint32 gssint_export_internal_name(OM_uint32 *, const gss_OID,
+       const gss_name_t, gss_buffer_t);
+OM_uint32 gssint_display_internal_name (OM_uint32 *, gss_OID, gss_name_t,
                                       gss_buffer_t, gss_OID *);
-OM_uint32 __gss_release_internal_name (OM_uint32 *, gss_OID, gss_name_t *);
+OM_uint32 gssint_release_internal_name (OM_uint32 *, gss_OID, gss_name_t *);
 
-OM_uint32 __gss_convert_name_to_union_name
+OM_uint32 gssint_convert_name_to_union_name
          (OM_uint32 *,         /* minor_status */
           gss_mechanism,       /* mech */
           gss_name_t,          /* internal_name */
           gss_name_t *         /* external_name */
           );
-gss_cred_id_t __gss_get_mechanism_cred
+gss_cred_id_t gssint_get_mechanism_cred
          (gss_union_cred_t,    /* union_cred */
           gss_OID              /* mech_type */
           );
 
-OM_uint32 generic_gss_release_oid
-          (OM_uint32 *,        /* minor_status */
-           gss_OID *           /* oid */
-          );
+OM_uint32 gssint_create_copy_buffer(
+       const gss_buffer_t,     /* src buffer */
+       gss_buffer_t *,         /* destination buffer */
+       int                     /* NULL terminate buffer ? */
+);
 
-OM_uint32 generic_gss_copy_oid
-          (OM_uint32 *,        /* minor_status */
-           gss_OID,            /* oid */
-           gss_OID *           /* new_oid */
-           );
+OM_uint32 gssint_copy_oid_set(
+       OM_uint32 *,                    /* minor_status */
+       const gss_OID_set_desc *,       /* oid set */
+       gss_OID_set *                   /* new oid set */
+);
 
-OM_uint32 generic_gss_create_empty_oid_set
-          (OM_uint32 *,        /* minor_status */
-           gss_OID_set *       /* oid_set */
-          );
+gss_OID gss_find_mechanism_from_name_type (gss_OID); /* name_type */
 
-OM_uint32 generic_gss_add_oid_set_member
+OM_uint32 gss_add_mech_name_type
           (OM_uint32 *,        /* minor_status */
-           gss_OID,            /* member_oid */
-           gss_OID_set *       /* oid_set */
-          );
+           gss_OID,            /* name_type */
+           gss_OID             /* mech */
+              );
 
-OM_uint32 generic_gss_test_oid_set_member
-          (OM_uint32 *,        /* minor_status */
-           gss_OID,            /* member */
-           gss_OID_set,        /* set */
-           int *               /* present */
-          );
+/*
+ * Sun extensions to GSS-API v2
+ */
 
-OM_uint32 generic_gss_oid_to_str
- (OM_uint32 *, /* minor_status */
-           gss_OID,            /* oid */
-           gss_buffer_t        /* oid_str */
-          );
+OM_uint32
+gssint_mech_to_oid(
+       const char *mech,               /* mechanism string name */
+       gss_OID *oid                    /* mechanism oid */
+);
 
-OM_uint32 generic_gss_str_to_oid
-          (OM_uint32 *,        /* minor_status */
-           gss_buffer_t,       /* oid_str */
-           gss_OID *           /* oid */
-          );
+const char *
+gssint_oid_to_mech(
+       const gss_OID oid               /* mechanism oid */
+);
 
+OM_uint32
+gssint_get_mechanisms(
+       char *mechArray[],              /* array to populate with mechs */
+       int arrayLen                    /* length of passed in array */
+);
 
-gss_OID gss_find_mechanism_from_name_type (gss_OID); /* name_type */
+OM_uint32
+gssint_userok(
+       OM_uint32 *,            /* minor */
+       const gss_name_t,       /* name */
+       const char *,           /* user */
+       int *                   /* user_ok */
+);
 
-OM_uint32 gss_add_mech_name_type
-          (OM_uint32 *,        /* minor_status */
-           gss_OID,            /* name_type */
-           gss_OID             /* mech */
-              );
+OM_uint32
+gss_store_cred(
+       OM_uint32 *,            /* minor_status */
+       const 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 */
+);
+
+int
+gssint_get_der_length(
+       unsigned char **,       /* buf */
+       unsigned int,           /* buf_len */
+       unsigned int *          /* bytes */
+);
+
+unsigned int
+gssint_der_length_size(unsigned int /* len */);
+
+int
+gssint_put_der_length(
+       unsigned int,           /* length */
+       unsigned char **,       /* buf */
+       unsigned int            /* max_len */
+);
 
 #endif /* _GSS_MECHGLUEP_H */
index 8e9da8852c482d26c4aa4b021302c6c1694eed04..ee981a507337cde3e766706c8dfbf11d3473b6d6 100644 (file)
@@ -1,3 +1,4 @@
+/* #pragma ident       "@(#)oid_ops.c  1.19    04/02/23 SMI" */
 /*
  * lib/gssapi/generic/oid_ops.c
  *
@@ -45,7 +46,8 @@ generic_gss_release_oid(minor_status, oid)
     OM_uint32  *minor_status;
     gss_OID    *oid;
 {
-    *minor_status = 0;
+    if (minor_status)
+       *minor_status = 0;
 
     if (*oid == GSS_C_NO_OID)
        return(GSS_S_COMPLETE);
@@ -59,9 +61,20 @@ generic_gss_release_oid(minor_status, oid)
      * descriptor.  This allows applications to freely mix their own heap-
      * allocated OID values with OIDs returned by GSS-API.
      */
-    if ((*oid != gss_nt_user_name) &&
-       (*oid != gss_nt_machine_uid_name) &&
-       (*oid != gss_nt_string_uid_name) &&
+
+    /*
+     * We use the official OID definitions instead of the unofficial OID
+     * defintions. But we continue to support the unofficial OID
+     * gss_nt_service_name just in case if some gss applications use
+     * the old OID.
+     */
+
+    if ((*oid != GSS_C_NT_USER_NAME) &&
+       (*oid != GSS_C_NT_MACHINE_UID_NAME) &&
+       (*oid != GSS_C_NT_STRING_UID_NAME) &&
+       (*oid != GSS_C_NT_HOSTBASED_SERVICE) &&
+       (*oid != GSS_C_NT_ANONYMOUS) &&
+       (*oid != GSS_C_NT_EXPORT_NAME) &&
        (*oid != gss_nt_service_name)) {
        free((*oid)->elements);
        free(*oid);
@@ -73,10 +86,13 @@ generic_gss_release_oid(minor_status, oid)
 OM_uint32
 generic_gss_copy_oid(minor_status, oid, new_oid)
        OM_uint32       *minor_status;
-       gss_OID         oid, *new_oid;
+       const gss_OID_desc * const oid;
+       gss_OID         *new_oid;
 {
        gss_OID         p;
 
+       *minor_status = 0;
+
        p = (gss_OID) malloc(sizeof(gss_OID_desc));
        if (!p) {
                *minor_status = ENOMEM;
@@ -86,7 +102,6 @@ generic_gss_copy_oid(minor_status, oid, new_oid)
        p->elements = malloc(p->length);
        if (!p->elements) {
                free(p);
-               *minor_status = ENOMEM;
                return GSS_S_FAILURE;
        }
        memcpy(p->elements, oid->elements, p->length);
@@ -100,9 +115,10 @@ generic_gss_create_empty_oid_set(minor_status, oid_set)
     OM_uint32  *minor_status;
     gss_OID_set        *oid_set;
 {
+    *minor_status = 0;
+
     if ((*oid_set = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)))) {
        memset(*oid_set, 0, sizeof(gss_OID_set_desc));
-       *minor_status = 0;
        return(GSS_S_COMPLETE);
     }
     else {
@@ -114,12 +130,18 @@ generic_gss_create_empty_oid_set(minor_status, oid_set)
 OM_uint32
 generic_gss_add_oid_set_member(minor_status, member_oid, oid_set)
     OM_uint32  *minor_status;
-    gss_OID    member_oid;
+    const gss_OID_desc * const member_oid;
     gss_OID_set        *oid_set;
 {
     gss_OID    elist;
     gss_OID    lastel;
 
+    *minor_status = 0;
+
+    if (member_oid == NULL || member_oid->length == 0 ||
+       member_oid->elements == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_READ);
+
     elist = (*oid_set)->elements;
     /* Get an enlarged copy of the array */
     if (((*oid_set)->elements = (gss_OID) malloc(((*oid_set)->count+1) *
@@ -159,13 +181,21 @@ generic_gss_add_oid_set_member(minor_status, member_oid, oid_set)
 OM_uint32
 generic_gss_test_oid_set_member(minor_status, member, set, present)
     OM_uint32  *minor_status;
-    gss_OID    member;
+    const gss_OID_desc * const member;
     gss_OID_set        set;
     int                *present;
 {
-    size_t     i;
+    OM_uint32  i;
     int                result;
 
+    *minor_status = 0;
+
+    if (member == NULL || set == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (present == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
     result = 0;
     for (i=0; i<set->count; i++) {
        if ((set->elements[i].length == member->length) &&
@@ -177,7 +207,6 @@ generic_gss_test_oid_set_member(minor_status, member, set, present)
        }
     }
     *present = result;
-    *minor_status = 0;
     return(GSS_S_COMPLETE);
 }
 
@@ -187,17 +216,25 @@ generic_gss_test_oid_set_member(minor_status, member, set, present)
 OM_uint32
 generic_gss_oid_to_str(minor_status, oid, oid_str)
     OM_uint32          *minor_status;
-    gss_OID            oid;
+    const gss_OID_desc * const oid;
     gss_buffer_t       oid_str;
 {
     char               numstr[128];
-    unsigned long      number;
+    OM_uint32          number;
     int                        numshift;
-    size_t             string_length;
-    size_t             i;
+    OM_uint32 string_length;
+    OM_uint32 i;
     unsigned char      *cp;
     char               *bp;
 
+    *minor_status = 0;
+
+    if (oid == NULL || oid->length == 0 || oid->elements == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (oid_str == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
     /* Decoded according to krb5/gssapi_krb5.c */
 
     /* First determine the size of the string */
@@ -206,21 +243,20 @@ generic_gss_oid_to_str(minor_status, oid, oid_str)
     numshift = 0;
     cp = (unsigned char *) oid->elements;
     number = (unsigned long) cp[0];
-    sprintf(numstr, "%ld ", number/40);
+    sprintf(numstr, "%lu ", (unsigned long)number/40);
     string_length += strlen(numstr);
-    sprintf(numstr, "%ld ", number%40);
+    sprintf(numstr, "%lu ", (unsigned long)number%40);
     string_length += strlen(numstr);
     for (i=1; i<oid->length; i++) {
-       if ( (size_t) (numshift+7) < (sizeof(unsigned long)*8)) {
+       if ((OM_uint32) (numshift+7) < (sizeof (OM_uint32)*8)) {/* XXX */
            number = (number << 7) | (cp[i] & 0x7f);
            numshift += 7;
        }
        else {
-           *minor_status = EINVAL;
            return(GSS_S_FAILURE);
        }
        if ((cp[i] & 0x80) == 0) {
-           sprintf(numstr, "%ld ", number);
+           sprintf(numstr, "%lu ", (unsigned long)number);
            string_length += strlen(numstr);
            number = 0;
            numshift = 0;
@@ -233,17 +269,17 @@ generic_gss_oid_to_str(minor_status, oid, oid_str)
     string_length += 4;
     if ((bp = (char *) malloc(string_length))) {
        strcpy(bp, "{ ");
-       number = (unsigned long) cp[0];
-       sprintf(numstr, "%ld ", number/40);
+       number = (OM_uint32) cp[0];
+       sprintf(numstr, "%lu ", (unsigned long)number/40);
        strcat(bp, numstr);
-       sprintf(numstr, "%ld ", number%40);
+       sprintf(numstr, "%lu ", (unsigned long)number%40);
        strcat(bp, numstr);
        number = 0;
        cp = (unsigned char *) oid->elements;
        for (i=1; i<oid->length; i++) {
            number = (number << 7) | (cp[i] & 0x7f);
            if ((cp[i] & 0x80) == 0) {
-               sprintf(numstr, "%ld ", number);
+               sprintf(numstr, "%lu ", (unsigned long)number);
                strcat(bp, numstr);
                number = 0;
            }
@@ -251,7 +287,6 @@ generic_gss_oid_to_str(minor_status, oid, oid_str)
        strcat(bp, "}");
        oid_str->length = strlen(bp)+1;
        oid_str->value = (void *) bp;
-       *minor_status = 0;
        return(GSS_S_COMPLETE);
     }
     *minor_status = ENOMEM;
@@ -264,7 +299,7 @@ generic_gss_str_to_oid(minor_status, oid_str, oid)
     gss_buffer_t       oid_str;
     gss_OID            *oid;
 {
-    char       *cp, *bp, *startp;
+    unsigned char      *cp, *bp, *startp;
     int                brace;
     long       numbuf;
     long       onumbuf;
@@ -272,8 +307,16 @@ generic_gss_str_to_oid(minor_status, oid_str, oid)
     int                index;
     unsigned char *op;
 
+    *minor_status = 0;
+
+    if (GSS_EMPTY_BUFFER(oid_str))
+       return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (oid == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
     brace = 0;
-    bp = (char *) oid_str->value;
+    bp = oid_str->value;
     cp = bp;
     /* Skip over leading space */
     while ((bp < &cp[oid_str->length]) && isspace(*bp))
@@ -290,7 +333,7 @@ generic_gss_str_to_oid(minor_status, oid_str, oid)
     /*
      * The first two numbers are chewed up by the first octet.
      */
-    if (sscanf(bp, "%ld", &numbuf) != 1) {
+    if (sscanf((char *)bp, "%ld", &numbuf) != 1) {
        *minor_status = EINVAL;
        return(GSS_S_FAILURE);
     }
@@ -298,18 +341,18 @@ generic_gss_str_to_oid(minor_status, oid_str, oid)
        bp++;
     while ((bp < &cp[oid_str->length]) && isspace(*bp))
        bp++;
-    if (sscanf(bp, "%ld", &numbuf) != 1) {
+    if (sscanf((char *)bp, "%ld", &numbuf) != 1) {
        *minor_status = EINVAL;
        return(GSS_S_FAILURE);
     }
     while ((bp < &cp[oid_str->length]) && isdigit(*bp))
        bp++;
-    while ((bp < &cp[oid_str->length]) && isspace(*bp))
+    while ((bp < &cp[oid_str->length]) &&
+          (isspace(*bp) || *bp == '.'))
        bp++;
     nbytes++;
     while (isdigit(*bp)) {
-       if (sscanf(bp, "%ld", &numbuf) != 1) {
-           *minor_status = EINVAL;
+       if (sscanf((char *)bp, "%ld", &numbuf) != 1) {
            return(GSS_S_FAILURE);
        }
        while (numbuf) {
@@ -318,11 +361,11 @@ generic_gss_str_to_oid(minor_status, oid_str, oid)
        }
        while ((bp < &cp[oid_str->length]) && isdigit(*bp))
            bp++;
-       while ((bp < &cp[oid_str->length]) && isspace(*bp))
+       while ((bp < &cp[oid_str->length]) &&
+              (isspace(*bp) || *bp == '.'))
            bp++;
     }
     if (brace && (*bp != '}')) {
-       *minor_status = EINVAL;
        return(GSS_S_FAILURE);
     }
 
@@ -330,26 +373,26 @@ generic_gss_str_to_oid(minor_status, oid_str, oid)
      * Phew!  We've come this far, so the syntax is good.
      */
     if ((*oid = (gss_OID) malloc(sizeof(gss_OID_desc)))) {
-       if (((*oid)->elements = (void *) malloc((size_t) nbytes))) {
+       if (((*oid)->elements = (void *) malloc(nbytes))) {
            (*oid)->length = nbytes;
            op = (unsigned char *) (*oid)->elements;
            bp = startp;
-           sscanf(bp, "%ld", &numbuf);
+           (void) sscanf((char *)bp, "%ld", &numbuf);
            while (isdigit(*bp))
                bp++;
-           while (isspace(*bp))
+           while (isspace(*bp) || *bp == '.')
                bp++;
            onumbuf = 40*numbuf;
-           sscanf(bp, "%ld", &numbuf);
+           (void) sscanf((char *)bp, "%ld", &numbuf);
            onumbuf += numbuf;
            *op = (unsigned char) onumbuf;
            op++;
            while (isdigit(*bp))
                bp++;
-           while (isspace(*bp))
+           while (isspace(*bp) || *bp == '.')
                bp++;
            while (isdigit(*bp)) {
-               sscanf(bp, "%ld", &numbuf);
+               (void) sscanf((char *)bp, "%ld", &numbuf);
                nbytes = 0;
                /* Have to fill in the bytes msb-first */
                onumbuf = numbuf;
@@ -369,10 +412,9 @@ generic_gss_str_to_oid(minor_status, oid_str, oid)
                }
                while (isdigit(*bp))
                    bp++;
-               while (isspace(*bp))
+               while (isspace(*bp) || *bp == '.')
                    bp++;
            }
-           *minor_status = 0;
            return(GSS_S_COMPLETE);
        }
        else {
@@ -380,7 +422,82 @@ generic_gss_str_to_oid(minor_status, oid_str, oid)
            *oid = GSS_C_NO_OID;
        }
     }
-    *minor_status = ENOMEM;
     return(GSS_S_FAILURE);
 }
 
+/*
+ * 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.
+ */
+OM_uint32
+gssint_copy_oid_set(
+    OM_uint32 *minor_status,
+    const gss_OID_set_desc * const oidset,
+    gss_OID_set *new_oidset
+    )
+{
+    gss_OID_set_desc *copy;
+    OM_uint32 minor = 0;
+    OM_uint32 major = GSS_S_COMPLETE;
+    OM_uint32 index;
+
+    if (minor_status)
+       *minor_status = 0;
+
+    if (oidset == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (new_oidset == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    *new_oidset = NULL;
+
+    if ((copy = (gss_OID_set_desc *) calloc(1, sizeof (*copy))) == NULL) {
+       major = GSS_S_FAILURE;
+       goto done;
+    }
+
+    if ((copy->elements = (gss_OID_desc *)
+        calloc(oidset->count, sizeof (*copy->elements))) == NULL) {
+       major = GSS_S_FAILURE;
+       goto done;
+    }
+    copy->count = oidset->count;
+
+    for (index = 0; index < copy->count; index++) {
+       gss_OID_desc *out = &copy->elements[index];
+       gss_OID_desc *in = &oidset->elements[index];
+
+       if ((out->elements = (void *) malloc(in->length)) == NULL) {
+           major = GSS_S_FAILURE;
+           goto done;
+       }
+       (void) memcpy(out->elements, in->elements, in->length);
+       out->length = in->length;
+    }
+
+    *new_oidset = copy;
+done:
+    if (major != GSS_S_COMPLETE) {
+       (void) gss_release_oid_set(&minor, &copy);
+    }
+
+    return (major);
+}
diff --git a/src/lib/gssapi/spnego/Makefile.in b/src/lib/gssapi/spnego/Makefile.in
new file mode 100644 (file)
index 0000000..631f474
--- /dev/null
@@ -0,0 +1,23 @@
+thisconfigdir=../../..
+myfulldir=lib/gssapi/spnego
+mydir=spnego
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic -I../mechglue -I$(srcdir)/../mechglue
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=spnego
+##DOS##OBJFILE = ..\$(OUTPRE)spnego.lst
+
+##DOS##DLL_EXP_TYPE=GSS
+
+SRCS = $(srcdir)/spnego_mech.c
+
+OBJS = $(OUTPRE)spnego_mech.$(OBJEXT)
+
+STLIBOBJS = spnego_mech.o
+
+all-unix:: all-libobjs
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
diff --git a/src/lib/gssapi/spnego/gssapiP_spnego.h b/src/lib/gssapi/spnego/gssapiP_spnego.h
new file mode 100644 (file)
index 0000000..2d3e5e2
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef        _GSSAPIP_SPNEGO_H_
+#define        _GSSAPIP_SPNEGO_H_
+
+/* #pragma ident       "@(#)gssapiP_spnego.h   1.3     03/09/18 SMI" */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <gssapi/gssapi.h>
+#include <syslog.h>
+
+#define        SEC_CONTEXT_TOKEN 1
+#define        SPNEGO_SIZE_OF_INT 4
+
+#define        ACCEPT_COMPLETE 0
+#define        ACCEPT_INCOMPLETE 1
+#define        REJECT 2
+#define REQUEST_MIC 3
+#define        ACCEPT_DEFECTIVE_TOKEN 0xffffffffUL
+
+/*
+ * constants for der encoding/decoding routines.
+ */
+
+#define        MECH_OID                0x06
+#define        OCTET_STRING            0x04
+#define        CONTEXT                 0xa0
+#define        SEQUENCE                0x30
+#define        SEQUENCE_OF             0x30
+#define        BIT_STRING              0x03
+#define        BIT_STRING_LENGTH       0x02
+#define        BIT_STRING_PADDING      0x01
+#define        ENUMERATED              0x0a
+#define        ENUMERATION_LENGTH      1
+#define        HEADER_ID               0x60
+
+/*
+ * SPNEGO specific error codes (minor status codes)
+ */
+#define        ERR_SPNEGO_NO_MECHS_AVAILABLE           0x20000001
+#define        ERR_SPNEGO_NO_CREDS_ACQUIRED            0x20000002
+#define        ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR        0x20000003
+#define        ERR_SPNEGO_NEGOTIATION_FAILED           0x20000004
+#define        ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR       0x20000005
+
+/*
+ * send_token_flag is used to indicate in later steps what type
+ * of token, if any should be sent or processed.
+ * NO_TOKEN_SEND = no token should be sent
+ * INIT_TOKEN_SEND = initial token will be sent
+ * CONT_TOKEN_SEND = continuing tokens to be sent
+ * CHECK_MIC = no token to be sent, but have a MIC to check.
+ * ERROR_TOKEN_SEND = error token from peer needs to be sent.
+ */
+
+typedef        enum {NO_TOKEN_SEND, INIT_TOKEN_SEND, CONT_TOKEN_SEND,
+               CHECK_MIC, ERROR_TOKEN_SEND} send_token_flag;
+
+/*
+ * The Mech OID:
+ * { iso(1) org(3) dod(6) internet(1) security(5)
+ *  mechanism(5) spnego(2) }
+ */
+
+#define        SPNEGO_OID_LENGTH 6
+#define        SPNEGO_OID "\053\006\001\005\005\002"
+
+typedef void *spnego_token_t;
+
+/* spnego name structure for internal representation. */
+typedef struct {
+       gss_OID type;
+       gss_buffer_t buffer;
+       gss_OID mech_type;
+       gss_name_t      mech_name;
+} spnego_name_desc, *spnego_name_t;
+
+/* Structure for context handle */
+typedef struct {
+       OM_uint32       magic_num;
+       gss_buffer_desc DER_mechTypes;
+       gss_OID internal_mech;
+       gss_ctx_id_t ctx_handle;
+       char  *optionStr;
+       gss_cred_id_t default_cred;
+       int mic_reqd;
+       int mic_sent;
+       int mic_rcvd;
+       int firstpass;
+       int mech_complete;
+       int nego_done;
+       OM_uint32 ctx_flags;
+       gss_name_t internal_name;
+       gss_OID actual_mech;
+} spnego_gss_ctx_id_rec, *spnego_gss_ctx_id_t;
+
+/*
+ * The magic number must be less than a standard pagesize
+ * to avoid a possible collision with a real address.
+ */
+#define        SPNEGO_MAGIC_ID  0x00000fed
+
+/* SPNEGO oid structure */
+static const gss_OID_desc spnego_oids[] = {
+       {SPNEGO_OID_LENGTH, SPNEGO_OID},
+};
+
+const gss_OID_desc * const gss_mech_spnego = spnego_oids+0;
+static const gss_OID_set_desc spnego_oidsets[] = {
+       {1, (gss_OID) spnego_oids+0},
+};
+const gss_OID_set_desc * const gss_mech_set_spnego = spnego_oidsets+0;
+
+#define        TWRITE_STR(ptr, str, len) \
+       memcpy((ptr), (char *)(str), (len)); \
+       (ptr) += (len);
+
+#ifdef DEBUG
+#define        dsyslog(a) syslog(LOG_DEBUG, a)
+#else
+#define        dsyslog(a)
+#define        SPNEGO_STATIC
+#endif /* DEBUG */
+
+/*
+ * declarations of internal name mechanism functions
+ */
+
+OM_uint32 spnego_gss_acquire_cred
+(
+       void *,                 /* spnego context */
+       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 spnego_gss_release_cred
+(
+       void *,                 /* spnego context */
+       OM_uint32 *,            /* minor_status */
+       /* CSTYLED */
+       gss_cred_id_t   *       /* cred_handle */
+);
+
+OM_uint32 spnego_gss_init_sec_context
+(
+       void *,                 /* spnego 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 spnego_gss_accept_sec_context
+(
+       void *,                 /* spnego 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 */
+       /* CSTYLED */
+       gss_cred_id_t *         /* delegated_cred_handle */
+);
+
+OM_uint32 spnego_gss_display_name
+(
+       void *,
+       OM_uint32 *,            /* minor_status */
+       gss_name_t,             /*  input_name */
+       gss_buffer_t,           /*  output_name_buffer */
+       gss_OID *               /* output_name_type */
+);
+
+OM_uint32 spnego_gss_display_status
+(
+       void *,                 /* spnego context */
+       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 spnego_gss_import_name
+(
+       void *,                 /* spnego context */
+       OM_uint32 *,            /* minor_status */
+       gss_buffer_t,           /* input_name_buffer */
+       gss_OID,                /* input_name_type */
+       /* CSTYLED */
+       gss_name_t *            /* output_name */
+);
+
+OM_uint32 spnego_gss_release_name
+(
+       void *,                 /* spnego context */
+       OM_uint32 *,            /* minor_status */
+       /* CSTYLED */
+       gss_name_t *            /* input_name */
+);
+
+OM_uint32 spnego_gss_inquire_names_for_mech
+(
+       void *,                 /* spnego context */
+       OM_uint32 *,            /* minor_status */
+       gss_OID,                /* mechanism */
+       gss_OID_set *           /* name_types */
+);
+
+OM_uint32 spnego_gss_unseal
+(
+       void *context,
+       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,
+       int *qop_state
+);
+
+OM_uint32 spnego_gss_seal
+(
+       void *context,
+       OM_uint32 *minor_status,
+       gss_ctx_id_t context_handle,
+       int conf_req_flag,
+       int qop_req,
+       gss_buffer_t input_message_buffer,
+       int *conf_state,
+       gss_buffer_t output_message_buffer
+);
+
+OM_uint32 spnego_gss_process_context_token
+(
+       void *context,
+       OM_uint32       *minor_status,
+       const gss_ctx_id_t context_handle,
+       const gss_buffer_t token_buffer
+);
+
+OM_uint32 spnego_gss_delete_sec_context
+(
+       void *context,
+       OM_uint32 *minor_status,
+       gss_ctx_id_t *context_handle,
+       gss_buffer_t output_token
+);
+
+OM_uint32 spnego_gss_context_time
+(
+       void *context,
+       OM_uint32       *minor_status,
+       const gss_ctx_id_t context_handle,
+       OM_uint32       *time_rec
+);
+
+OM_uint32 spnego_gss_export_sec_context
+(
+       void *context,
+       OM_uint32       *minor_status,
+       gss_ctx_id_t    *context_handle,
+       gss_buffer_t    interprocess_token
+);
+
+OM_uint32 spnego_gss_import_sec_context
+(
+       void                    *context,
+       OM_uint32               *minor_status,
+       const gss_buffer_t      interprocess_token,
+       gss_ctx_id_t            *context_handle
+);
+
+OM_uint32 spnego_gss_inquire_context
+(
+       void            *context,
+       OM_uint32       *minor_status,
+       const 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             *open
+);
+
+OM_uint32 spnego_gss_wrap_size_limit
+(
+       void            *context,
+       OM_uint32       *minor_status,
+       const 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 spnego_gss_sign
+(
+       void *context,
+       OM_uint32 *minor_status,
+       const gss_ctx_id_t context_handle,
+       int  qop_req,
+       const gss_buffer_t message_buffer,
+       gss_buffer_t message_token
+);
+
+OM_uint32 spnego_gss_verify
+(
+       void *context,
+       OM_uint32 *minor_status,
+       const gss_ctx_id_t context_handle,
+       const gss_buffer_t msg_buffer,
+       const gss_buffer_t token_buffer,
+       int *qop_state
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GSSAPIP_SPNEGO_H_ */
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
new file mode 100644 (file)
index 0000000..ec8b608
--- /dev/null
@@ -0,0 +1,2843 @@
+/*
+ * Copyright (C) 2006 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 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * A module that implements the spnego security mechanism.
+ * It is used to negotiate the security mechanism between
+ * peers using the GSS-API.
+ *
+ */
+
+/* #pragma ident       "@(#)spnego_mech.c      1.7     04/09/28 SMI" */
+
+#include       <assert.h>
+#include       <stdio.h>
+#include       <stdlib.h>
+#include       <string.h>
+#include       <krb5.h>
+#include       "gssapiP_spnego.h"
+#include       <mglueP.h>
+#include       <gssapi_err_generic.h>
+
+#undef g_token_size
+#undef g_verify_token_header
+#undef g_make_token_header
+
+#define HARD_ERROR(v) ((v) != GSS_S_COMPLETE && (v) != GSS_S_CONTINUE_NEEDED)
+typedef const gss_OID_desc *gss_OID_const;
+
+/* der routines defined in libgss */
+extern unsigned int gssint_der_length_size(OM_uint32);
+extern int gssint_get_der_length(unsigned char **, OM_uint32, OM_uint32*);
+extern int gssint_put_der_length(OM_uint32, unsigned char **, OM_uint32);
+
+
+/* private routines for spnego_mechanism */
+static spnego_token_t make_spnego_token(char *);
+static gss_buffer_desc make_err_msg(char *);
+static int g_token_size(gss_OID_const, OM_uint32);
+static int g_make_token_header(gss_OID_const, int, unsigned char **, int);
+static int g_verify_token_header(gss_OID_const, int *, unsigned char **,
+                                int, int);
+static int g_verify_neg_token_init(unsigned char **, int);
+static gss_OID get_mech_oid(OM_uint32 *, unsigned char **, size_t);
+static gss_buffer_t get_input_token(unsigned char **, int);
+static gss_OID_set get_mech_set(OM_uint32 *, unsigned char **, int);
+static OM_uint32 get_req_flags(unsigned char **, OM_uint32, OM_uint32 *);
+static OM_uint32 get_available_mechs(OM_uint32 *, gss_name_t,
+       gss_cred_usage_t, gss_cred_id_t *, gss_OID_set *);
+static void release_spnego_ctx(spnego_gss_ctx_id_t *);
+static void check_spnego_options(spnego_gss_ctx_id_t);
+static spnego_gss_ctx_id_t create_spnego_ctx(void);
+static int put_req_flags(unsigned char **, OM_uint32, int);
+static int put_mech_set(gss_OID_set mechSet, gss_buffer_t buf);
+static int put_input_token(unsigned char **, gss_buffer_t, int);
+static int put_mech_oid(unsigned char **, gss_OID_const, int);
+static int put_negResult(unsigned char **, OM_uint32, int);
+
+static OM_uint32
+process_mic(OM_uint32 *, gss_buffer_t, spnego_gss_ctx_id_t,
+           gss_buffer_t *, OM_uint32 *, send_token_flag *);
+static OM_uint32
+handle_mic(OM_uint32 *, gss_buffer_t, int, spnego_gss_ctx_id_t,
+          gss_buffer_t *, OM_uint32 *, send_token_flag *);
+
+static OM_uint32
+init_ctx_new(OM_uint32 *, gss_cred_id_t, gss_ctx_id_t *,
+            gss_OID_set *, send_token_flag *);
+static OM_uint32
+init_ctx_nego(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32, gss_OID,
+             gss_buffer_t *, gss_buffer_t *,
+             OM_uint32 *, send_token_flag *);
+static OM_uint32
+init_ctx_cont(OM_uint32 *, gss_ctx_id_t *, gss_buffer_t,
+             gss_buffer_t *, gss_buffer_t *,
+             OM_uint32 *, send_token_flag *);
+static OM_uint32
+init_ctx_reselect(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32,
+                 gss_OID, gss_buffer_t *, gss_buffer_t *,
+                 OM_uint32 *, send_token_flag *);
+static OM_uint32
+init_ctx_call_init(OM_uint32 *, spnego_gss_ctx_id_t, gss_cred_id_t,
+                  gss_name_t, OM_uint32, OM_uint32, gss_buffer_t,
+                  gss_OID *, gss_buffer_t, OM_uint32 *, OM_uint32 *,
+                  OM_uint32 *, send_token_flag *);
+
+static OM_uint32
+acc_ctx_new(OM_uint32 *, gss_buffer_t, gss_ctx_id_t *,
+           gss_cred_id_t, gss_buffer_t *,
+           gss_buffer_t *, OM_uint32 *, send_token_flag *);
+static OM_uint32
+acc_ctx_cont(OM_uint32 *, gss_buffer_t, gss_ctx_id_t *,
+            gss_buffer_t *, gss_buffer_t *,
+            OM_uint32 *, send_token_flag *);
+static OM_uint32
+acc_ctx_vfy_oid(OM_uint32 *, spnego_gss_ctx_id_t, gss_OID,
+               OM_uint32 *, send_token_flag *);
+static OM_uint32
+acc_ctx_call_acc(OM_uint32 *, spnego_gss_ctx_id_t, gss_cred_id_t,
+                gss_buffer_t, gss_OID *, gss_buffer_t,
+                OM_uint32 *, OM_uint32 *, gss_cred_id_t *,
+                OM_uint32 *, send_token_flag *);
+
+static gss_OID
+negotiate_mech_type(OM_uint32 *, gss_OID_set, gss_OID_set,
+               OM_uint32 *);
+static int
+g_get_tag_and_length(unsigned char **, int, int, int *);
+
+static int
+make_spnego_tokenInit_msg(spnego_gss_ctx_id_t, gss_buffer_t,
+                       OM_uint32, gss_buffer_t, send_token_flag,
+                       gss_buffer_t);
+static int
+make_spnego_tokenTarg_msg(OM_uint32, gss_OID, gss_buffer_t,
+                       gss_buffer_t, send_token_flag,
+                       gss_buffer_t);
+
+static OM_uint32
+get_negTokenInit(OM_uint32 *, gss_buffer_t, gss_buffer_t,
+                gss_OID_set *, OM_uint32 *, gss_buffer_t *,
+                gss_buffer_t *);
+static OM_uint32
+get_negTokenResp(OM_uint32 *, unsigned char *, unsigned int,
+                OM_uint32 *, gss_OID *, gss_buffer_t *, gss_buffer_t *);
+
+/*
+ * The Mech OID for SPNEGO:
+ * { iso(1) org(3) dod(6) internet(1) security(5)
+ *  mechanism(5) spnego(2) }
+ */
+static struct gss_config spnego_mechanism =
+{
+       400, "spnego",
+       {SPNEGO_OID_LENGTH, SPNEGO_OID},
+       NULL,
+       spnego_gss_acquire_cred,
+       spnego_gss_release_cred,
+       spnego_gss_init_sec_context,
+       spnego_gss_accept_sec_context,
+       NULL,                           /* gss_process_context_token */
+       spnego_gss_delete_sec_context,  /* gss_delete_sec_context */
+       spnego_gss_context_time,        /* gss_context_time */
+       spnego_gss_sign,                /* gss_sign */
+       spnego_gss_verify,              /* gss_verify */
+       spnego_gss_seal,                /* gss_seal */
+       spnego_gss_unseal,              /* gss_unseal */
+       spnego_gss_display_status,
+       NULL,                           /* gss_indicate_mechs */
+       NULL,                           /* gss_compare_name */
+       spnego_gss_display_name,
+       spnego_gss_import_name,
+       spnego_gss_release_name,
+       NULL,                           /* gss_inquire_cred */
+       NULL,                           /* gss_add_cred */
+       spnego_gss_export_sec_context,  /* gss_export_sec_context */
+       spnego_gss_import_sec_context,  /* gss_import_sec_context */
+       NULL,                           /* gss_inquire_cred_by_mech */
+       spnego_gss_inquire_names_for_mech,
+       spnego_gss_inquire_context,     /* gss_inquire_context */
+       NULL,                           /* gss_internal_release_oid */
+       spnego_gss_wrap_size_limit,     /* gss_wrap_size_limit */
+       NULL,                           /* gss_pname_to_uid */
+       NULL,                           /* gssint_userok */
+       NULL,                           /* gss_export_name */
+       NULL,                           /* gss_store_cred */
+};
+
+static gss_mechanism spnego_mech_configs[] = {
+       &spnego_mechanism, NULL
+};
+
+#if 1
+#define gssint_get_mech_configs spnego_gss_get_mech_configs
+#endif
+
+gss_mechanism *
+gssint_get_mech_configs(void)
+{
+       return spnego_mech_configs;
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_acquire_cred(void *ctx,
+                       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 status;
+       gss_OID_set amechs;
+       dsyslog("Entering spnego_gss_acquire_cred\n");
+
+       if (actual_mechs)
+               *actual_mechs = NULL;
+
+       if (time_rec)
+               *time_rec = 0;
+
+       /*
+        * If the user did not specify a list of mechs,
+        * use get_available_mechs to collect a list of
+        * mechs for which creds are available.
+        */
+       if (desired_mechs == GSS_C_NULL_OID_SET) {
+               status = get_available_mechs(minor_status,
+                               desired_name, cred_usage,
+                               output_cred_handle, &amechs);
+       } else {
+               /*
+                * The caller gave a specific list of mechanisms,
+                * so just get whatever creds are available.
+                * gss_acquire_creds will return the subset of mechs for
+                * which the given 'output_cred_handle' is valid.
+                */
+               status = gss_acquire_cred(minor_status,
+                               desired_name, time_req,
+                               desired_mechs, cred_usage,
+                               output_cred_handle, &amechs,
+                               time_rec);
+       }
+
+       if (actual_mechs && amechs != GSS_C_NULL_OID_SET) {
+               (void) gssint_copy_oid_set(minor_status, amechs, actual_mechs);
+       }
+       (void) gss_release_oid_set(minor_status, &amechs);
+
+       dsyslog("Leaving spnego_gss_acquire_cred\n");
+       return (status);
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_release_cred(void *ctx,
+                       OM_uint32 *minor_status,
+                       gss_cred_id_t *cred_handle)
+{
+       OM_uint32 status;
+
+       dsyslog("Entering spnego_gss_release_cred\n");
+
+       if (minor_status == NULL || cred_handle == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+       *minor_status = 0;
+
+       if (*cred_handle == GSS_C_NO_CREDENTIAL)
+               return (GSS_S_COMPLETE);
+
+       status = gss_release_cred(minor_status, cred_handle);
+
+       dsyslog("Leaving spnego_gss_release_cred\n");
+       return (status);
+}
+
+static void
+check_spnego_options(spnego_gss_ctx_id_t spnego_ctx)
+{
+       spnego_ctx->optionStr = gssint_get_modOptions(
+               (const gss_OID)&spnego_oids[0]);
+}
+
+static spnego_gss_ctx_id_t
+create_spnego_ctx(void)
+{
+       spnego_gss_ctx_id_t spnego_ctx = NULL;
+       spnego_ctx = (spnego_gss_ctx_id_t)
+               malloc(sizeof (spnego_gss_ctx_id_rec));
+
+       if (spnego_ctx == NULL) {
+               return (NULL);
+       }
+
+       spnego_ctx->magic_num = SPNEGO_MAGIC_ID;
+       spnego_ctx->ctx_handle = GSS_C_NO_CONTEXT;
+       spnego_ctx->internal_mech = NULL;
+       spnego_ctx->optionStr = NULL;
+       spnego_ctx->DER_mechTypes.length = 0;
+       spnego_ctx->DER_mechTypes.value = NULL;
+       spnego_ctx->default_cred = GSS_C_NO_CREDENTIAL;
+       spnego_ctx->mic_reqd = 0;
+       spnego_ctx->mic_sent = 0;
+       spnego_ctx->mic_rcvd = 0;
+       spnego_ctx->mech_complete = 0;
+       spnego_ctx->nego_done = 0;
+       spnego_ctx->internal_name = GSS_C_NO_NAME;
+       spnego_ctx->actual_mech = GSS_C_NO_OID;
+
+       check_spnego_options(spnego_ctx);
+
+       return (spnego_ctx);
+}
+
+/*
+ * Both initiator and acceptor call here to verify and/or create
+ * mechListMIC, and to consistency-check the MIC state.
+ */
+static OM_uint32
+handle_mic(OM_uint32 *minor_status, gss_buffer_t mic_in,
+          int send_mechtok, spnego_gss_ctx_id_t sc,
+          gss_buffer_t *mic_out,
+          OM_uint32 *negState, send_token_flag *tokflag)
+{
+       OM_uint32 ret;
+
+       ret = GSS_S_FAILURE;
+       *mic_out = GSS_C_NO_BUFFER;
+       if (mic_in != GSS_C_NO_BUFFER) {
+               if (sc->mic_rcvd) {
+                       /* Reject MIC if we've already received a MIC. */
+                       *negState = REJECT;
+                       *tokflag = ERROR_TOKEN_SEND;
+                       return GSS_S_DEFECTIVE_TOKEN;
+               }
+       } else if (sc->mic_reqd && !send_mechtok) {
+               /*
+                * If the peer sends the final mechanism token, it
+                * must send the MIC with that token if the
+                * negotiation requires MICs.
+                */
+               *negState = REJECT;
+               *tokflag = ERROR_TOKEN_SEND;
+               return GSS_S_DEFECTIVE_TOKEN;
+       }
+       ret = process_mic(minor_status, mic_in, sc, mic_out,
+                         negState, tokflag);
+       if (ret != GSS_S_COMPLETE) {
+               return ret;
+       }
+       if (sc->mic_reqd) {
+               assert(sc->mic_sent || sc->mic_rcvd);
+       }
+       if (sc->mic_sent && sc->mic_rcvd) {
+               ret = GSS_S_COMPLETE;
+               *negState = ACCEPT_COMPLETE;
+               if (*mic_out == GSS_C_NO_BUFFER) {
+                       /*
+                        * We sent a MIC on the previous pass; we
+                        * shouldn't be sending a mechanism token.
+                        */
+                       assert(!send_mechtok);
+                       *tokflag = NO_TOKEN_SEND;
+               } else {
+                       *tokflag = CONT_TOKEN_SEND;
+               }
+       } else if (sc->mic_reqd) {
+               *negState = ACCEPT_INCOMPLETE;
+               ret = GSS_S_CONTINUE_NEEDED;
+       } else if (*negState == ACCEPT_COMPLETE) {
+               ret = GSS_S_COMPLETE;
+       } else {
+               ret = GSS_S_CONTINUE_NEEDED;
+       }
+       return ret;
+}
+
+/*
+ * Perform the actual verification and/or generation of mechListMIC.
+ */
+static OM_uint32
+process_mic(OM_uint32 *minor_status, gss_buffer_t mic_in,
+           spnego_gss_ctx_id_t sc, gss_buffer_t *mic_out,
+           OM_uint32 *negState, send_token_flag *tokflag)
+{
+       OM_uint32 ret, tmpmin;
+       gss_qop_t qop_state;
+       gss_buffer_desc tmpmic = GSS_C_EMPTY_BUFFER;
+
+       ret = GSS_S_FAILURE;
+       if (mic_in != GSS_C_NO_BUFFER) {
+               ret = gss_verify_mic(minor_status, sc->ctx_handle,
+                                    &sc->DER_mechTypes,
+                                    mic_in, &qop_state);
+               if (ret != GSS_S_COMPLETE) {
+                       *negState = REJECT;
+                       *tokflag = ERROR_TOKEN_SEND;
+                       return ret;
+               }
+               /* If we got a MIC, we must send a MIC. */
+               sc->mic_reqd = 1;
+               sc->mic_rcvd = 1;
+       }
+       if (sc->mic_reqd && !sc->mic_sent) {
+               ret = gss_get_mic(minor_status, sc->ctx_handle,
+                                 GSS_C_QOP_DEFAULT,
+                                 &sc->DER_mechTypes,
+                                 &tmpmic);
+               if (ret != GSS_S_COMPLETE) {
+                       gss_release_buffer(&tmpmin, &tmpmic);
+                       *tokflag = NO_TOKEN_SEND;
+                       return ret;
+               }
+               *mic_out = malloc(sizeof(gss_buffer_desc));
+               if (*mic_out == GSS_C_NO_BUFFER) {
+                       gss_release_buffer(&tmpmin, &tmpmic);
+                       *tokflag = NO_TOKEN_SEND;
+                       return GSS_S_FAILURE;
+               }
+               **mic_out = tmpmic;
+               sc->mic_sent = 1;
+       }
+       return GSS_S_COMPLETE;
+}
+
+/*
+ * Initial call to spnego_gss_init_sec_context().
+ */
+static OM_uint32
+init_ctx_new(OM_uint32 *minor_status,
+            gss_cred_id_t cred,
+            gss_ctx_id_t *ctx,
+            gss_OID_set *mechSet,
+            send_token_flag *tokflag)
+{
+       OM_uint32 ret, tmpmin;
+       gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
+       spnego_gss_ctx_id_t sc = NULL;
+
+       /* determine negotiation mech set */
+       if (cred == GSS_C_NO_CREDENTIAL) {
+               ret = get_available_mechs(minor_status, GSS_C_NO_NAME,
+                                         GSS_C_INITIATE, &creds, mechSet);
+               gss_release_cred(&tmpmin, &creds);
+       } else {
+               /*
+                * Use the list of mechs included in the cred that we
+                * were given.
+                */
+               ret = gss_inquire_cred(minor_status, cred,
+                                      NULL, NULL, NULL, mechSet);
+       }
+       if (ret != GSS_S_COMPLETE)
+               return ret;
+
+       sc = create_spnego_ctx();
+       if (sc == NULL)
+               return GSS_S_FAILURE;
+
+       /*
+        * need to pull the first mech from mechSet to do first
+        * gss_init_sec_context()
+        */
+       ret = generic_gss_copy_oid(minor_status, (*mechSet)->elements,
+                                  &sc->internal_mech);
+       if (ret != GSS_S_COMPLETE)
+               goto cleanup;
+
+       if (put_mech_set(*mechSet, &sc->DER_mechTypes) < 0) {
+               generic_gss_release_oid(&tmpmin, &sc->internal_mech);
+               ret = GSS_S_FAILURE;
+               goto cleanup;
+       }
+       /*
+        * The actual context is not yet determined, set the output
+        * context handle to refer to the spnego context itself.
+        */
+       sc->ctx_handle = GSS_C_NO_CONTEXT;
+       *ctx = (gss_ctx_id_t)sc;
+       *tokflag = INIT_TOKEN_SEND;
+       ret = GSS_S_CONTINUE_NEEDED;
+
+cleanup:
+       gss_release_oid_set(&tmpmin, mechSet);
+       return ret;
+}
+
+/*
+ * Called by second and later calls to spnego_gss_init_sec_context()
+ * to decode reply and update state.
+ */
+static OM_uint32
+init_ctx_cont(OM_uint32 *minor_status, gss_ctx_id_t *ctx, gss_buffer_t buf,
+             gss_buffer_t *responseToken, gss_buffer_t *mechListMIC,
+             OM_uint32 *negState, send_token_flag *tokflag)
+{
+       OM_uint32 ret, tmpmin, acc_negState;
+       unsigned char *ptr;
+       spnego_gss_ctx_id_t sc;
+       gss_OID supportedMech = GSS_C_NO_OID;
+
+       sc = (spnego_gss_ctx_id_t)*ctx;
+       *negState = REJECT;
+       *tokflag = ERROR_TOKEN_SEND;
+
+       ptr = buf->value;
+       ret = get_negTokenResp(minor_status, ptr, buf->length,
+                              &acc_negState, &supportedMech,
+                              responseToken, mechListMIC);
+       if (ret != GSS_S_COMPLETE)
+               goto cleanup;
+       if (acc_negState == ACCEPT_DEFECTIVE_TOKEN &&
+           supportedMech == GSS_C_NO_OID &&
+           *responseToken == GSS_C_NO_BUFFER &&
+           *mechListMIC == GSS_C_NO_BUFFER) {
+               /* Reject "empty" token. */
+               ret = GSS_S_DEFECTIVE_TOKEN;
+       }
+       if (acc_negState == REJECT) {
+               *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+               *tokflag = NO_TOKEN_SEND;
+               ret = GSS_S_FAILURE;
+               goto cleanup;
+       }
+       /*
+        * nego_done is false for the first call to init_ctx_cont()
+        */
+       if (!sc->nego_done) {
+               ret = init_ctx_nego(minor_status, sc,
+                                   acc_negState,
+                                   supportedMech, responseToken,
+                                   mechListMIC,
+                                   negState, tokflag);
+       } else if (!sc->mech_complete &&
+                  *responseToken == GSS_C_NO_BUFFER) {
+               /*
+                * mech not finished and mech token missing
+                */
+               ret = GSS_S_DEFECTIVE_TOKEN;
+       } else {
+               *negState = ACCEPT_INCOMPLETE;
+               *tokflag = CONT_TOKEN_SEND;
+               ret = GSS_S_CONTINUE_NEEDED;
+       }
+cleanup:
+       if (supportedMech != GSS_C_NO_OID)
+               generic_gss_release_oid(&tmpmin, &supportedMech);
+       return ret;
+}
+
+/*
+ * Consistency checking and mechanism negotiation handling for second
+ * call of spnego_gss_init_sec_context().  Call init_ctx_reselect() to
+ * update internal state if acceptor has counter-proposed.
+ */
+static OM_uint32
+init_ctx_nego(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+             OM_uint32 acc_negState, gss_OID supportedMech,
+             gss_buffer_t *responseToken, gss_buffer_t *mechListMIC,
+             OM_uint32 *negState, send_token_flag *tokflag)
+{
+       OM_uint32 ret;
+
+       *negState = REJECT;
+       *tokflag = ERROR_TOKEN_SEND;
+       ret = GSS_S_DEFECTIVE_TOKEN;
+       /*
+        * Both supportedMech and negState must be present in first
+        * acceptor token.
+        */
+       if (supportedMech == GSS_C_NO_OID) {
+               *minor_status = ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR;
+               return GSS_S_DEFECTIVE_TOKEN;
+       }
+       if (acc_negState == ACCEPT_DEFECTIVE_TOKEN) {
+               *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+               return GSS_S_DEFECTIVE_TOKEN;
+       }
+       if (!g_OID_equal(supportedMech, sc->internal_mech)) {
+               ret = init_ctx_reselect(minor_status, sc,
+                                       acc_negState, supportedMech,
+                                       responseToken, mechListMIC,
+                                       negState, tokflag);
+
+       } else if (*responseToken == GSS_C_NO_BUFFER) {
+               if (sc->mech_complete) {
+                       /*
+                        * Mech completed on first call to its
+                        * init_sec_context().  Acceptor sends no mech
+                        * token.
+                        */
+                       *negState = ACCEPT_COMPLETE;
+                       *tokflag = NO_TOKEN_SEND;
+                       ret = GSS_S_COMPLETE;
+               } else {
+                       /*
+                        * Reject missing mech token when optimistic
+                        * mech selected.
+                        */
+                       *minor_status = ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR;
+                       ret = GSS_S_DEFECTIVE_TOKEN;
+               }
+       } else if (sc->mech_complete) {
+               /* Reject spurious mech token. */
+               ret = GSS_S_DEFECTIVE_TOKEN;
+       } else {
+               *negState = ACCEPT_INCOMPLETE;
+               *tokflag = CONT_TOKEN_SEND;
+               ret = GSS_S_CONTINUE_NEEDED;
+       }
+       sc->nego_done = 1;
+       return ret;
+}
+
+/*
+ * Handle acceptor's counter-proposal of an alternative mechanism.
+ */
+static OM_uint32
+init_ctx_reselect(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+                 OM_uint32 acc_negState, gss_OID supportedMech,
+                 gss_buffer_t *responseToken, gss_buffer_t *mechListMIC,
+                 OM_uint32 *negState, send_token_flag *tokflag)
+{
+       OM_uint32 ret, tmpmin;
+
+       generic_gss_release_oid(&tmpmin, &sc->internal_mech);
+       gss_delete_sec_context(&tmpmin, &sc->ctx_handle,
+                              GSS_C_NO_BUFFER);
+
+       ret = generic_gss_copy_oid(minor_status, supportedMech,
+                                  &sc->internal_mech);
+       if (ret != GSS_S_COMPLETE) {
+               sc->internal_mech = GSS_C_NO_OID;
+               *tokflag = NO_TOKEN_SEND;
+               return ret;
+       }
+       if (*responseToken != GSS_C_NO_BUFFER) {
+               /* Reject spurious mech token. */
+               return GSS_S_DEFECTIVE_TOKEN;
+       }
+       /*
+        * Windows 2003 and earlier don't correctly send a
+        * negState of request-mic when counter-proposing a
+        * mechanism.  They probably don't handle mechListMICs
+        * properly either.
+        */
+       if (acc_negState != REQUEST_MIC)
+               return GSS_S_DEFECTIVE_TOKEN;
+
+       sc->mech_complete = 0;
+       sc->mic_reqd = 1;
+       *negState = REQUEST_MIC;
+       *tokflag = CONT_TOKEN_SEND;
+       return GSS_S_CONTINUE_NEEDED;
+}
+
+/*
+ * Wrap call to mechanism gss_init_sec_context() and update state
+ * accordingly.
+ */
+static OM_uint32
+init_ctx_call_init(OM_uint32 *minor_status,
+                  spnego_gss_ctx_id_t sc,
+                  gss_cred_id_t claimant_cred_handle,
+                  gss_name_t target_name,
+                  OM_uint32 req_flags,
+                  OM_uint32 time_req,
+                  gss_buffer_t mechtok_in,
+                  gss_OID *actual_mech,
+                  gss_buffer_t mechtok_out,
+                  OM_uint32 *ret_flags,
+                  OM_uint32 *time_rec,
+                  OM_uint32 *negState,
+                  send_token_flag *send_token)
+{
+       OM_uint32 ret;
+
+       ret = gss_init_sec_context(minor_status,
+                                  claimant_cred_handle,
+                                  &sc->ctx_handle,
+                                  target_name,
+                                  sc->internal_mech,
+                                  (req_flags | GSS_C_INTEG_FLAG),
+                                  time_req,
+                                  GSS_C_NO_CHANNEL_BINDINGS,
+                                  mechtok_in,
+                                  &sc->actual_mech,
+                                  mechtok_out,
+                                  &sc->ctx_flags,
+                                  time_rec);
+       if (ret == GSS_S_COMPLETE) {
+               sc->mech_complete = 1;
+               if (ret_flags != NULL)
+                       *ret_flags = sc->ctx_flags;
+               /*
+                * If this isn't the first time we've been called,
+                * we're done unless a MIC needs to be
+                * generated/handled.
+                */
+               if (*send_token == CONT_TOKEN_SEND &&
+                   (!sc->mic_reqd ||
+                    !(sc->ctx_flags & GSS_C_INTEG_FLAG))) {
+
+                       *negState = ACCEPT_COMPLETE;
+                       ret = GSS_S_COMPLETE;
+                       if (mechtok_out->length == 0) {
+                               *send_token = NO_TOKEN_SEND;
+                       }
+               } else {
+                       *negState = ACCEPT_INCOMPLETE;
+                       ret = GSS_S_CONTINUE_NEEDED;
+               }
+       } else if (ret != GSS_S_CONTINUE_NEEDED) {
+               if (*send_token == INIT_TOKEN_SEND) {
+                       /* Don't output token on error if first call. */
+                       *send_token = NO_TOKEN_SEND;
+               } else {
+                       *send_token = ERROR_TOKEN_SEND;
+               }
+               *negState = REJECT;
+       }
+       return ret;
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_init_sec_context(void *ct,
+                       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,
+                       gss_buffer_t output_token,
+                       OM_uint32 *ret_flags,
+                       OM_uint32 *time_rec)
+{
+       /*
+        * send_token is used to indicate in later steps
+        * what type of token, if any should be sent or processed.
+        * NO_TOKEN_SEND = no token should be sent
+        * INIT_TOKEN_SEND = initial token will be sent
+        * CONT_TOKEN_SEND = continuing tokens to be sent
+        * CHECK_MIC = no token to be sent, but have a MIC to check.
+        */
+       send_token_flag send_token = NO_TOKEN_SEND;
+       OM_uint32 tmpmin, ret, negState;
+       gss_buffer_t mechtok_in, mechListMIC_in, mechListMIC_out;
+       gss_buffer_desc mechtok_out = GSS_C_EMPTY_BUFFER;
+       gss_OID_set mechSet = GSS_C_NO_OID_SET;
+       spnego_gss_ctx_id_t spnego_ctx = NULL;
+
+       dsyslog("Entering init_sec_context\n");
+
+       mechtok_in = mechListMIC_out = mechListMIC_in = GSS_C_NO_BUFFER;
+       negState = REJECT;
+
+       if (minor_status != NULL)
+               *minor_status = 0;
+       if (output_token != GSS_C_NO_BUFFER) {
+               output_token->length = 0;
+               output_token->value = NULL;
+       }
+       if (minor_status == NULL ||
+           output_token == GSS_C_NO_BUFFER ||
+           context_handle == NULL)
+               return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+       if (actual_mech != NULL)
+               *actual_mech = GSS_C_NO_OID;
+
+       if (*context_handle == GSS_C_NO_CONTEXT) {
+               ret = init_ctx_new(minor_status, claimant_cred_handle,
+                                  context_handle, &mechSet, &send_token);
+               if (ret != GSS_S_CONTINUE_NEEDED) {
+                       goto cleanup;
+               }
+       } else {
+               ret = init_ctx_cont(minor_status, context_handle,
+                                   input_token, &mechtok_in,
+                                   &mechListMIC_in, &negState, &send_token);
+               if (HARD_ERROR(ret)) {
+                       goto cleanup;
+               }
+       }
+       spnego_ctx = (spnego_gss_ctx_id_t)*context_handle;
+       if (!spnego_ctx->mech_complete) {
+               ret = init_ctx_call_init(
+                       minor_status, spnego_ctx,
+                       claimant_cred_handle,
+                       target_name, req_flags,
+                       time_req, mechtok_in,
+                       actual_mech, &mechtok_out,
+                       ret_flags, time_rec,
+                       &negState, &send_token);
+       }
+       /* create mic/check mic */
+       if (!HARD_ERROR(ret) && spnego_ctx->mech_complete &&
+           (spnego_ctx->ctx_flags & GSS_C_INTEG_FLAG)) {
+
+               ret = handle_mic(minor_status,
+                                mechListMIC_in,
+                                (mechtok_out.length != 0),
+                                spnego_ctx, &mechListMIC_out,
+                                &negState, &send_token);
+       }
+cleanup:
+       if (send_token == INIT_TOKEN_SEND) {
+               if (make_spnego_tokenInit_msg(spnego_ctx,
+                                             mechListMIC_out,
+                                             req_flags,
+                                             &mechtok_out, send_token,
+                                             output_token) < 0) {
+
+                       ret = GSS_S_FAILURE;
+               }
+       } else if (send_token != NO_TOKEN_SEND) {
+               if (make_spnego_tokenTarg_msg(negState, GSS_C_NO_OID,
+                                             &mechtok_out, mechListMIC_out,
+                                             send_token,
+                                             output_token) < 0) {
+                       ret = GSS_S_FAILURE;
+               }
+       }
+       if (ret == GSS_S_COMPLETE) {
+               /*
+                * Now, switch the output context to refer to the
+                * negotiated mechanism's context.
+                */
+               *context_handle = (gss_ctx_id_t)spnego_ctx->ctx_handle;
+               if (actual_mech != NULL)
+                       *actual_mech = spnego_ctx->actual_mech;
+               release_spnego_ctx(&spnego_ctx);
+       } else if (ret != GSS_S_CONTINUE_NEEDED) {
+               if (spnego_ctx != NULL) {
+                       gss_delete_sec_context(&tmpmin,
+                                              &spnego_ctx->ctx_handle,
+                                              GSS_C_NO_BUFFER);
+                       release_spnego_ctx(&spnego_ctx);
+               }
+               *context_handle = GSS_C_NO_CONTEXT;
+       }
+       if (mechtok_in != GSS_C_NO_BUFFER) {
+               gss_release_buffer(&tmpmin, mechtok_in);
+               free(mechtok_in);
+       }
+       if (mechListMIC_in != GSS_C_NO_BUFFER) {
+               gss_release_buffer(&tmpmin, mechListMIC_in);
+               free(mechListMIC_in);
+       }
+       if (mechListMIC_out != GSS_C_NO_BUFFER) {
+               gss_release_buffer(&tmpmin, mechListMIC_out);
+               free(mechListMIC_out);
+       }
+       if (mechSet != GSS_C_NO_OID_SET) {
+               gss_release_oid_set(&tmpmin, &mechSet);
+       }
+       return ret;
+} /* init_sec_context */
+
+/*
+ * Set negState to REJECT if the token is defective, else
+ * ACCEPT_INCOMPLETE or REQUEST_MIC, depending on whether initiator's
+ * preferred mechanism is supported.
+ */
+static OM_uint32
+acc_ctx_new(OM_uint32 *minor_status,
+           gss_buffer_t buf,
+           gss_ctx_id_t *ctx,
+           gss_cred_id_t cred,
+           gss_buffer_t *mechToken,
+           gss_buffer_t *mechListMIC,
+           OM_uint32 *negState,
+           send_token_flag *return_token)
+{
+       OM_uint32 tmpmin, ret, req_flags;
+       gss_OID_set supported_mechSet, mechTypes;
+       gss_buffer_desc der_mechTypes;
+       gss_OID mech_wanted;
+       spnego_gss_ctx_id_t sc = NULL;
+
+       *ctx = GSS_C_NO_CONTEXT;
+       ret = GSS_S_DEFECTIVE_TOKEN;
+       der_mechTypes.length = 0;
+       der_mechTypes.value = NULL;
+       *mechToken = *mechListMIC = GSS_C_NO_BUFFER;
+       supported_mechSet = mechTypes = GSS_C_NO_OID_SET;
+       *return_token = ERROR_TOKEN_SEND;
+       *negState = REJECT;
+       *minor_status = 0;
+
+       ret = get_negTokenInit(minor_status, buf, &der_mechTypes,
+                              &mechTypes, &req_flags,
+                              mechToken, mechListMIC);
+       if (ret != GSS_S_COMPLETE) {
+               goto cleanup;
+       }
+       if (cred != GSS_C_NO_CREDENTIAL) {
+               ret = gss_inquire_cred(minor_status, cred, NULL, NULL,
+                                      NULL, &supported_mechSet);
+               if (ret != GSS_S_COMPLETE) {
+                       *return_token = NO_TOKEN_SEND;
+                       goto cleanup;
+               }
+       } else {
+               ret = get_available_mechs(minor_status, GSS_C_NO_NAME,
+                                         GSS_C_ACCEPT, NULL,
+                                         &supported_mechSet);
+               if (ret != GSS_S_COMPLETE) {
+                       *return_token = NO_TOKEN_SEND;
+                       goto cleanup;
+               }
+       }
+       /*
+        * Select the best match between the list of mechs
+        * that the initiator requested and the list that
+        * the acceptor will support.
+        */
+       mech_wanted = negotiate_mech_type(minor_status,
+                                         supported_mechSet,
+                                         mechTypes,
+                                         negState);
+       if (*negState == REJECT) {
+               ret = GSS_S_BAD_MECH;
+               goto cleanup;
+       }
+       sc = create_spnego_ctx();
+       if (sc == NULL) {
+               ret = GSS_S_FAILURE;
+               *return_token = NO_TOKEN_SEND;
+               generic_gss_release_oid(&tmpmin, &mech_wanted);
+               goto cleanup;
+       }
+       sc->internal_mech = mech_wanted;
+       sc->DER_mechTypes = der_mechTypes;
+       der_mechTypes.length = 0;
+       der_mechTypes.value = NULL;
+
+       if (*negState == REQUEST_MIC)
+               sc->mic_reqd = 1;
+
+       *return_token = INIT_TOKEN_SEND;
+       sc->firstpass = 1;
+       *ctx = (gss_ctx_id_t)sc;
+       ret = GSS_S_COMPLETE;
+cleanup:
+       gss_release_oid_set(&tmpmin, &mechTypes);
+       gss_release_oid_set(&tmpmin, &supported_mechSet);
+       if (der_mechTypes.length != 0)
+               gss_release_buffer(&tmpmin, &der_mechTypes);
+
+       return ret;
+}
+
+static OM_uint32
+acc_ctx_cont(OM_uint32 *minstat,
+            gss_buffer_t buf,
+            gss_ctx_id_t *ctx,
+            gss_buffer_t *responseToken,
+            gss_buffer_t *mechListMIC,
+            OM_uint32 *negState,
+            send_token_flag *return_token)
+{
+       OM_uint32 ret, tmpmin;
+       gss_OID supportedMech;
+       spnego_gss_ctx_id_t sc;
+       int len;
+       unsigned char *ptr, *bufstart;
+
+       sc = (spnego_gss_ctx_id_t)*ctx;
+       ret = GSS_S_DEFECTIVE_TOKEN;
+       *negState = REJECT;
+       *minstat = 0;
+       supportedMech = GSS_C_NO_OID;
+       *return_token = ERROR_TOKEN_SEND;
+       *responseToken = *mechListMIC = GSS_C_NO_BUFFER;
+
+       ptr = bufstart = buf->value;
+#define REMAIN (buf->length - (ptr - bufstart))
+       if (REMAIN > INT_MAX)
+               return GSS_S_DEFECTIVE_TOKEN;
+
+       /*
+        * Attempt to work with old Sun SPNEGO.
+        */
+       if (*ptr == HEADER_ID) {
+               ret = g_verify_token_header(gss_mech_spnego,
+                                           &len, &ptr, 0, REMAIN);
+               if (ret) {
+                       *minstat = ret;
+                       return GSS_S_DEFECTIVE_TOKEN;
+               }
+       }
+       if (*ptr != (CONTEXT | 0x01)) {
+               return GSS_S_DEFECTIVE_TOKEN;
+       }
+       ret = get_negTokenResp(minstat, ptr, REMAIN,
+                              negState, &supportedMech,
+                              responseToken, mechListMIC);
+       if (ret != GSS_S_COMPLETE)
+               goto cleanup;
+
+       if (*responseToken == GSS_C_NO_BUFFER &&
+           *mechListMIC == GSS_C_NO_BUFFER) {
+
+               ret = GSS_S_DEFECTIVE_TOKEN;
+               goto cleanup;
+       }
+       if (supportedMech != GSS_C_NO_OID) {
+               ret = GSS_S_DEFECTIVE_TOKEN;
+               goto cleanup;
+       }
+       sc->firstpass = 0;
+       *negState = ACCEPT_INCOMPLETE;
+       *return_token = CONT_TOKEN_SEND;
+cleanup:
+       if (supportedMech != GSS_C_NO_OID) {
+               generic_gss_release_oid(&tmpmin, &supportedMech);
+       }
+       return ret;
+#undef REMAIN
+}
+
+/*
+ * Verify that mech OID is either exactly the same as the negotiated
+ * mech OID, or is a mech OID supported by the negotiated mech.  MS
+ * implementations can list a most preferred mech using an incorrect
+ * krb5 OID while emitting a krb5 initiator mech token having the
+ * correct krb5 mech OID.
+ */
+static OM_uint32
+acc_ctx_vfy_oid(OM_uint32 *minor_status,
+               spnego_gss_ctx_id_t sc, gss_OID mechoid,
+               OM_uint32 *negState, send_token_flag *tokflag)
+{
+       OM_uint32 ret, tmpmin;
+       gss_mechanism mech = NULL;
+       gss_OID_set mech_set = GSS_C_NO_OID_SET;
+       int present = 0;
+
+       if (g_OID_equal(sc->internal_mech, mechoid))
+               return GSS_S_COMPLETE;
+
+       mech = gssint_get_mechanism(sc->internal_mech);
+       if (mech == NULL || mech->gss_indicate_mechs == NULL) {
+               *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+               *negState = REJECT;
+               *tokflag = ERROR_TOKEN_SEND;
+               return GSS_S_BAD_MECH;
+       }
+       ret = mech->gss_indicate_mechs(NULL, minor_status, &mech_set);
+       if (ret != GSS_S_COMPLETE) {
+               *tokflag = NO_TOKEN_SEND;
+               goto cleanup;
+       }
+       ret = gss_test_oid_set_member(minor_status, mechoid,
+                                     mech_set, &present);
+       if (ret != GSS_S_COMPLETE)
+               goto cleanup;
+       if (!present) {
+               *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+               *negState = REJECT;
+               *tokflag = ERROR_TOKEN_SEND;
+               ret = GSS_S_BAD_MECH;
+       }
+cleanup:
+       gss_release_oid_set(&tmpmin, &mech_set);
+       return ret;
+}
+
+/*
+ * Wrap call to gss_accept_sec_context() and update state
+ * accordingly.
+ */
+static OM_uint32
+acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+                gss_cred_id_t cred, gss_buffer_t mechtok_in,
+                gss_OID *mech_type, gss_buffer_t mechtok_out,
+                OM_uint32 *ret_flags, OM_uint32 *time_rec,
+                gss_cred_id_t *delegated_cred_handle,
+                OM_uint32 *negState, send_token_flag *tokflag)
+{
+       OM_uint32 ret;
+       gss_OID_desc mechoid;
+
+       /*
+        * mechoid is an alias; don't free it.
+        */
+       ret = gssint_get_mech_type(&mechoid, mechtok_in);
+       if (ret != GSS_S_COMPLETE) {
+               *tokflag = NO_TOKEN_SEND;
+               return ret;
+       }
+       ret = acc_ctx_vfy_oid(minor_status, sc, &mechoid,
+                             negState, tokflag);
+       if (ret != GSS_S_COMPLETE)
+               return ret;
+
+       ret = gss_accept_sec_context(minor_status,
+                                    &sc->ctx_handle,
+                                    cred,
+                                    mechtok_in,
+                                    GSS_C_NO_CHANNEL_BINDINGS,
+                                    &sc->internal_name,
+                                    mech_type,
+                                    mechtok_out,
+                                    &sc->ctx_flags,
+                                    time_rec,
+                                    delegated_cred_handle);
+       if (ret == GSS_S_COMPLETE) {
+#ifdef MS_BUG_TEST
+               /*
+                * Force MIC to be not required even if we previously
+                * requested a MIC.
+                */
+               char *envstr = getenv("MS_FORCE_NO_MIC");
+
+               if (envstr != NULL && strcmp(envstr, "1") == 0 &&
+                   !(sc->ctx_flags & GSS_C_MUTUAL_FLAG) &&
+                   sc->mic_reqd) {
+
+                       sc->mic_reqd = 0;
+               }
+#endif
+               sc->mech_complete = 1;
+               if (ret_flags != NULL)
+                       *ret_flags = sc->ctx_flags;
+
+               if (!sc->mic_reqd) {
+                       *negState = ACCEPT_COMPLETE;
+                       ret = GSS_S_COMPLETE;
+               } else {
+                       ret = GSS_S_CONTINUE_NEEDED;
+               }
+       } else if (ret != GSS_S_CONTINUE_NEEDED) {
+               *negState = REJECT;
+               *tokflag = ERROR_TOKEN_SEND;
+       }
+       return ret;
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_accept_sec_context(void *ct,
+                           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 ret, tmpret, tmpmin, negState;
+       send_token_flag return_token;
+       gss_buffer_t mechtok_in, mic_in, mic_out;
+       gss_buffer_desc mechtok_out = GSS_C_EMPTY_BUFFER;
+       spnego_gss_ctx_id_t sc = NULL;
+       OM_uint32 mechstat = GSS_S_FAILURE;
+
+       mechtok_in = mic_in = mic_out = GSS_C_NO_BUFFER;
+
+       if (minor_status != NULL)
+               *minor_status = 0;
+       if (output_token != GSS_C_NO_BUFFER) {
+               output_token->length = 0;
+               output_token->value = NULL;
+       }
+
+       if (minor_status == NULL ||
+           output_token == GSS_C_NO_BUFFER ||
+           context_handle == NULL)
+               return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+       if (input_token == GSS_C_NO_BUFFER)
+               return GSS_S_CALL_INACCESSIBLE_READ;
+
+       if (*context_handle == GSS_C_NO_CONTEXT) {
+               if (src_name != NULL)
+                       *src_name = GSS_C_NO_NAME;
+               if (mech_type != NULL)
+                       *mech_type = GSS_C_NO_OID;
+               if (time_rec != NULL)
+                       *time_rec = 0;
+               if (ret_flags != NULL)
+                       *ret_flags = 0;
+               if (delegated_cred_handle != NULL)
+                       *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+               /* Can set negState to REQUEST_MIC */
+               ret = acc_ctx_new(minor_status, input_token,
+                                 context_handle, verifier_cred_handle,
+                                 &mechtok_in, &mic_in,
+                                 &negState, &return_token);
+               if (ret != GSS_S_COMPLETE)
+                       goto cleanup;
+               ret = GSS_S_CONTINUE_NEEDED;
+       } else {
+               /* Can set negState to ACCEPT_INCOMPLETE */
+               ret = acc_ctx_cont(minor_status, input_token,
+                                  context_handle, &mechtok_in,
+                                  &mic_in, &negState, &return_token);
+               if (ret != GSS_S_COMPLETE)
+                       goto cleanup;
+               ret = GSS_S_CONTINUE_NEEDED;
+       }
+       sc = (spnego_gss_ctx_id_t)*context_handle;
+       /*
+        * Handle mechtok_in and mic_in only if they are
+        * present in input_token.  If neither is present, whether
+        * this is an error depends on whether this is the first
+        * round-trip.  RET is set to a default value according to
+        * whether it is the first round-trip.
+        */
+       mechstat = GSS_S_FAILURE;
+       if (negState != REQUEST_MIC && mechtok_in != GSS_C_NO_BUFFER) {
+               ret = acc_ctx_call_acc(minor_status, sc,
+                                      verifier_cred_handle, mechtok_in,
+                                      mech_type, &mechtok_out,
+                                      ret_flags, time_rec,
+                                      delegated_cred_handle,
+                                      &negState, &return_token);
+       } else if (negState == REQUEST_MIC) {
+               mechstat = GSS_S_CONTINUE_NEEDED;
+       }
+       if (!HARD_ERROR(ret) && sc->mech_complete &&
+           (sc->ctx_flags & GSS_C_INTEG_FLAG)) {
+
+               ret = handle_mic(minor_status, mic_in,
+                                (mechtok_out.length != 0),
+                                sc, &mic_out,
+                                &negState, &return_token);
+       }
+cleanup:
+       if (return_token != NO_TOKEN_SEND && return_token != CHECK_MIC) {
+               tmpret = make_spnego_tokenTarg_msg(negState, sc->internal_mech,
+                                                  &mechtok_out, mic_out,
+                                                  return_token,
+                                                  output_token);
+               if (tmpret != GSS_S_COMPLETE) {
+                       ret = tmpret;
+               }
+       }
+       if (ret == GSS_S_COMPLETE) {
+               *context_handle = (gss_ctx_id_t)sc->ctx_handle;
+               if (sc->internal_name != GSS_C_NO_NAME &&
+                   src_name != NULL) {
+                       *src_name = sc->internal_name;
+               }
+               release_spnego_ctx(&sc);
+       }
+       gss_release_buffer(&tmpmin, &mechtok_out);
+       if (mechtok_in != GSS_C_NO_BUFFER) {
+               gss_release_buffer(&tmpmin, mechtok_in);
+               free(mechtok_in);
+       }
+       if (mic_in != GSS_C_NO_BUFFER) {
+               gss_release_buffer(&tmpmin, mic_in);
+               free(mic_in);
+       }
+       if (mic_out != GSS_C_NO_BUFFER) {
+               gss_release_buffer(&tmpmin, mic_out);
+               free(mic_out);
+       }
+       return ret;
+}
+
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_display_status(void *ctx,
+               OM_uint32 *minor_status,
+               OM_uint32 status_value,
+               int status_type,
+               gss_OID mech_type,
+               OM_uint32 *message_context,
+               gss_buffer_t status_string)
+{
+       dsyslog("Entering display_status\n");
+
+       *message_context = 0;
+       switch (status_value) {
+           case ERR_SPNEGO_NO_MECHS_AVAILABLE:
+               /* CSTYLED */
+               *status_string = make_err_msg("SPNEGO cannot find mechanisms to negotiate");
+               break;
+           case ERR_SPNEGO_NO_CREDS_ACQUIRED:
+               /* CSTYLED */
+               *status_string = make_err_msg("SPNEGO failed to acquire creds");
+               break;
+           case ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR:
+               /* CSTYLED */
+               *status_string = make_err_msg("SPNEGO acceptor did not select a mechanism");
+               break;
+           case ERR_SPNEGO_NEGOTIATION_FAILED:
+               /* CSTYLED */
+               *status_string = make_err_msg("SPNEGO failed to negotiate a mechanism");
+               break;
+           case ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR:
+               /* CSTYLED */
+               *status_string = make_err_msg("SPNEGO acceptor did not return a valid token");
+               break;
+           default:
+               status_string->length = 0;
+               status_string->value = "";
+               break;
+       }
+
+       dsyslog("Leaving display_status\n");
+       return (GSS_S_COMPLETE);
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_import_name(void *ctx,
+                   OM_uint32 *minor_status,
+                   gss_buffer_t input_name_buffer,
+                   gss_OID input_name_type,
+                   gss_name_t *output_name)
+{
+       OM_uint32 status;
+
+       dsyslog("Entering import_name\n");
+
+       status = gss_import_name(minor_status, input_name_buffer,
+                       input_name_type, output_name);
+
+       dsyslog("Leaving import_name\n");
+       return (status);
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_release_name(void *ctx,
+                       OM_uint32 *minor_status,
+                       gss_name_t *input_name)
+{
+       OM_uint32 status;
+
+       dsyslog("Entering release_name\n");
+
+       status = gss_release_name(minor_status, input_name);
+
+       dsyslog("Leaving release_name\n");
+       return (status);
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_display_name(void *ctx,
+                       OM_uint32 *minor_status,
+                       gss_name_t input_name,
+                       gss_buffer_t output_name_buffer,
+                       gss_OID *output_name_type)
+{
+       OM_uint32 status = GSS_S_COMPLETE;
+       dsyslog("Entering display_name\n");
+
+       status = gss_display_name(minor_status, input_name,
+                       output_name_buffer, output_name_type);
+
+       dsyslog("Leaving display_name\n");
+       return (status);
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_inquire_names_for_mech(void *ctx,
+                               OM_uint32       *minor_status,
+                               gss_OID         mechanism,
+                               gss_OID_set     *name_types)
+{
+       OM_uint32   major, minor;
+
+       dsyslog("Entering inquire_names_for_mech\n");
+       /*
+        * We only know how to handle our own mechanism.
+        */
+       if ((mechanism != GSS_C_NULL_OID) &&
+           !g_OID_equal(gss_mech_spnego, mechanism)) {
+               *minor_status = 0;
+               return (GSS_S_FAILURE);
+       }
+
+       major = gss_create_empty_oid_set(minor_status, name_types);
+       if (major == GSS_S_COMPLETE) {
+               /* Now add our members. */
+               if (((major = gss_add_oid_set_member(minor_status,
+                               (gss_OID) GSS_C_NT_USER_NAME,
+                               name_types)) == GSS_S_COMPLETE) &&
+                   ((major = gss_add_oid_set_member(minor_status,
+                               (gss_OID) GSS_C_NT_MACHINE_UID_NAME,
+                               name_types)) == GSS_S_COMPLETE) &&
+                   ((major = gss_add_oid_set_member(minor_status,
+                               (gss_OID) GSS_C_NT_STRING_UID_NAME,
+                               name_types)) == GSS_S_COMPLETE)) {
+                       major = gss_add_oid_set_member(minor_status,
+                               (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
+                               name_types);
+               }
+
+               if (major != GSS_S_COMPLETE)
+                       (void) gss_release_oid_set(&minor, name_types);
+       }
+
+       dsyslog("Leaving inquire_names_for_mech\n");
+       return (major);
+}
+
+OM_uint32
+spnego_gss_unseal(void *context,
+               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,
+               int *qop_state)
+{
+       OM_uint32 ret;
+       ret = gss_unseal(minor_status,
+                       context_handle,
+                       input_message_buffer,
+                       output_message_buffer,
+                       conf_state,
+                       qop_state);
+
+       return (ret);
+}
+
+OM_uint32
+spnego_gss_seal(void *context,
+               OM_uint32 *minor_status,
+               gss_ctx_id_t context_handle,
+               int conf_req_flag,
+               int qop_req,
+               gss_buffer_t input_message_buffer,
+               int *conf_state,
+               gss_buffer_t output_message_buffer)
+{
+       OM_uint32 ret;
+       ret = gss_seal(minor_status,
+                   context_handle,
+                   conf_req_flag,
+                   qop_req,
+                   input_message_buffer,
+                   conf_state,
+                   output_message_buffer);
+
+       return (ret);
+}
+
+OM_uint32
+spnego_gss_process_context_token(void *context,
+                               OM_uint32       *minor_status,
+                               const gss_ctx_id_t context_handle,
+                               const gss_buffer_t token_buffer)
+{
+       OM_uint32 ret;
+       ret = gss_process_context_token(minor_status,
+                                       context_handle,
+                                       token_buffer);
+
+       return (ret);
+}
+
+OM_uint32
+spnego_gss_delete_sec_context(void *context,
+                           OM_uint32 *minor_status,
+                           gss_ctx_id_t *context_handle,
+                           gss_buffer_t output_token)
+{
+       OM_uint32 ret = GSS_S_COMPLETE;
+       spnego_gss_ctx_id_t *ctx =
+                   (spnego_gss_ctx_id_t *)context_handle;
+
+       if (context_handle == NULL)
+               return (GSS_S_FAILURE);
+
+       /*
+        * If this is still an SPNEGO mech, release it locally.
+        */
+       if (*ctx != NULL &&
+           (*ctx)->magic_num == SPNEGO_MAGIC_ID) {
+               (void) release_spnego_ctx(ctx);
+       } else {
+               ret = gss_delete_sec_context(minor_status,
+                                   context_handle,
+                                   output_token);
+       }
+
+       return (ret);
+}
+
+OM_uint32
+spnego_gss_context_time(void *context,
+                       OM_uint32       *minor_status,
+                       const gss_ctx_id_t context_handle,
+                       OM_uint32       *time_rec)
+{
+       OM_uint32 ret;
+       ret = gss_context_time(minor_status,
+                           context_handle,
+                           time_rec);
+       return (ret);
+}
+
+OM_uint32
+spnego_gss_export_sec_context(void *context,
+                           OM_uint32     *minor_status,
+                           gss_ctx_id_t *context_handle,
+                           gss_buffer_t interprocess_token)
+{
+       OM_uint32 ret;
+       ret = gss_export_sec_context(minor_status,
+                                   context_handle,
+                                   interprocess_token);
+       return (ret);
+}
+
+OM_uint32
+spnego_gss_import_sec_context(void *context,
+       OM_uint32               *minor_status,
+       const gss_buffer_t      interprocess_token,
+       gss_ctx_id_t            *context_handle)
+{
+       OM_uint32 ret;
+       ret = gss_import_sec_context(minor_status,
+                                   interprocess_token,
+                                   context_handle);
+       return (ret);
+}
+
+OM_uint32
+spnego_gss_inquire_context(void *context,
+                       OM_uint32       *minor_status,
+                       const 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             *open)
+{
+       OM_uint32 ret = GSS_S_COMPLETE;
+
+       ret = gss_inquire_context(minor_status,
+                               context_handle,
+                               src_name,
+                               targ_name,
+                               lifetime_rec,
+                               mech_type,
+                               ctx_flags,
+                               locally_initiated,
+                               open);
+
+       return (ret);
+}
+
+OM_uint32
+spnego_gss_wrap_size_limit(void *context,
+       OM_uint32       *minor_status,
+       const 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 ret;
+       ret = gss_wrap_size_limit(minor_status,
+                               context_handle,
+                               conf_req_flag,
+                               qop_req,
+                               req_output_size,
+                               max_input_size);
+       return (ret);
+}
+
+OM_uint32
+spnego_gss_sign(void *context,
+               OM_uint32 *minor_status,
+               const gss_ctx_id_t context_handle,
+               int  qop_req,
+               const gss_buffer_t message_buffer,
+               gss_buffer_t message_token)
+{
+       OM_uint32 ret;
+       ret = gss_sign(minor_status,
+                   context_handle,
+                   qop_req,
+                   message_buffer,
+                   message_token);
+       return (ret);
+}
+
+OM_uint32
+spnego_gss_verify(void *context,
+               OM_uint32 *minor_status,
+               const gss_ctx_id_t context_handle,
+               const gss_buffer_t msg_buffer,
+               const gss_buffer_t token_buffer,
+               int *qop_state)
+{
+       OM_uint32 ret;
+       ret = gss_verify_mic(minor_status,
+                           context_handle,
+                           msg_buffer,
+                           token_buffer,
+                           (gss_qop_t *)qop_state); /* XXX */
+       return (ret);
+}
+
+/*
+ * We will release everything but the ctx_handle so that it
+ * can be passed back to init/accept context. This routine should
+ * not be called until after the ctx_handle memory is assigned to
+ * the supplied context handle from init/accept context.
+ */
+static void
+release_spnego_ctx(spnego_gss_ctx_id_t *ctx)
+{
+       spnego_gss_ctx_id_t context;
+       OM_uint32 minor_stat;
+       context = *ctx;
+
+       if (context != NULL) {
+               (void) gss_release_buffer(&minor_stat,
+                                       &context->DER_mechTypes);
+
+               (void) generic_gss_release_oid(&minor_stat,
+                               &context->internal_mech);
+
+               if (context->optionStr != NULL) {
+                       free(context->optionStr);
+                       context->optionStr = NULL;
+               }
+               free(context);
+               *ctx = NULL;
+       }
+}
+
+/*
+ * Can't use gss_indicate_mechs by itself to get available mechs for
+ * SPNEGO because it will also return the SPNEGO mech and we do not
+ * want to consider SPNEGO as an available security mech for
+ * negotiation. For this reason, get_available_mechs will return
+ * all available mechs except SPNEGO.
+ *
+ * If a ptr to a creds list is given, this function will attempt
+ * to acquire creds for the creds given and trim the list of
+ * returned mechanisms to only those for which creds are valid.
+ *
+ */
+static OM_uint32
+get_available_mechs(OM_uint32 *minor_status,
+       gss_name_t name, gss_cred_usage_t usage,
+       gss_cred_id_t *creds, gss_OID_set *rmechs)
+{
+       int             i;
+       int             found = 0;
+       OM_uint32 stat = GSS_S_COMPLETE, tmpmin;
+       gss_OID_set mechs, goodmechs;
+
+       stat = gss_indicate_mechs(minor_status, &mechs);
+
+       if (stat != GSS_S_COMPLETE) {
+               return (stat);
+       }
+
+       stat = gss_create_empty_oid_set(minor_status, rmechs);
+
+       if (stat != GSS_S_COMPLETE) {
+               (void) gss_release_oid_set(minor_status, &mechs);
+               return (stat);
+       }
+
+       for (i = 0; i < mechs->count && stat == GSS_S_COMPLETE; i++) {
+               if ((mechs->elements[i].length
+                   != spnego_mechanism.mech_type.length) ||
+                   memcmp(mechs->elements[i].elements,
+                       spnego_mechanism.mech_type.elements,
+                       spnego_mechanism.mech_type.length)) {
+
+                       stat = gss_add_oid_set_member(minor_status,
+                                           &mechs->elements[i],
+                                           rmechs);
+                       if (stat == GSS_S_COMPLETE)
+                               found++;
+               }
+       }
+
+       /*
+        * If the caller wanted a list of creds returned,
+        * trim the list of mechanisms down to only those
+        * for which the creds are valid.
+        */
+       if (found > 0 && stat == GSS_S_COMPLETE && creds != NULL) {
+               stat = gss_acquire_cred(minor_status,
+                       name, GSS_C_INDEFINITE, *rmechs, usage, creds,
+                       &goodmechs, NULL);
+
+               /*
+                * Drop the old list in favor of the new
+                * "trimmed" list.
+                */
+               (void) gss_release_oid_set(&tmpmin, rmechs);
+               if (stat == GSS_S_COMPLETE) {
+                       (void) gssint_copy_oid_set(&tmpmin,
+                                       goodmechs, rmechs);
+                       (void) gss_release_oid_set(&tmpmin, &goodmechs);
+               }
+       }
+
+       (void) gss_release_oid_set(&tmpmin, &mechs);
+       if (found == 0 || stat != GSS_S_COMPLETE) {
+               *minor_status = ERR_SPNEGO_NO_MECHS_AVAILABLE;
+               if (stat == GSS_S_COMPLETE)
+                       stat = GSS_S_FAILURE;
+       }
+
+       return (stat);
+}
+
+/* following are token creation and reading routines */
+
+/*
+ * If buff_in is not pointing to a MECH_OID, then return NULL and do not
+ * advance the buffer, otherwise, decode the mech_oid from the buffer and
+ * place in gss_OID.
+ */
+static gss_OID
+get_mech_oid(OM_uint32 *minor_status, unsigned char **buff_in, size_t length)
+{
+       OM_uint32       status;
+       gss_OID_desc    toid;
+       gss_OID         mech_out = NULL;
+       unsigned char           *start, *end;
+
+       if (length < 1 || **buff_in != MECH_OID)
+               return (NULL);
+
+       start = *buff_in;
+       end = start + length;
+
+       (*buff_in)++;
+       toid.length = *(*buff_in)++;
+
+       if ((*buff_in + toid.length) > end)
+               return (NULL);
+
+       toid.elements = *buff_in;
+       *buff_in += toid.length;
+
+       status = generic_gss_copy_oid(minor_status, &toid, &mech_out);
+
+       if (status != GSS_S_COMPLETE)
+               mech_out = NULL;
+
+       return (mech_out);
+}
+
+/*
+ * der encode the given mechanism oid into buf_out, advancing the
+ * buffer pointer.
+ */
+
+static int
+put_mech_oid(unsigned char **buf_out, gss_OID_const mech, int buflen)
+{
+       if (buflen < mech->length + 2)
+               return (-1);
+       *(*buf_out)++ = MECH_OID;
+       *(*buf_out)++ = (unsigned char) mech->length;
+       memcpy((void *)(*buf_out), mech->elements, mech->length);
+       *buf_out += mech->length;
+       return (0);
+}
+
+/*
+ * verify that buff_in points to an octet string, if it does not,
+ * return NULL and don't advance the pointer. If it is an octet string
+ * decode buff_in into a gss_buffer_t and return it, advancing the
+ * buffer pointer.
+ */
+static gss_buffer_t
+get_input_token(unsigned char **buff_in, int buff_length)
+{
+       gss_buffer_t input_token;
+       unsigned int bytes;
+
+       if (**buff_in != OCTET_STRING)
+               return (NULL);
+
+       (*buff_in)++;
+       input_token = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
+
+       if (input_token == NULL)
+               return (NULL);
+
+       input_token->length = gssint_get_der_length(buff_in, buff_length, &bytes);
+       if ((int)input_token->length == -1) {
+               free(input_token);
+               return (NULL);
+       }
+       input_token->value = malloc(input_token->length);
+
+       if (input_token->value == NULL) {
+               free(input_token);
+               return (NULL);
+       }
+
+       (void) memcpy(input_token->value, *buff_in, input_token->length);
+       *buff_in += input_token->length;
+       return (input_token);
+}
+
+/*
+ * verify that the input token length is not 0. If it is, just return.
+ * If the token length is greater than 0, der encode as an octet string
+ * and place in buf_out, advancing buf_out.
+ */
+
+static int
+put_input_token(unsigned char **buf_out, gss_buffer_t input_token,
+               int buflen)
+{
+       int ret;
+
+       /* if token length is 0, we do not want to send */
+       if (input_token->length == 0)
+               return (0);
+
+       if (input_token->length > buflen)
+               return (-1);
+
+       *(*buf_out)++ = OCTET_STRING;
+       if ((ret = gssint_put_der_length(input_token->length, buf_out,
+                           input_token->length)))
+               return (ret);
+       TWRITE_STR(*buf_out, input_token->value, ((int)input_token->length));
+       return (0);
+}
+
+/*
+ * verify that buff_in points to a sequence of der encoding. The mech
+ * set is the only sequence of encoded object in the token, so if it is
+ * a sequence of encoding, decode the mechset into a gss_OID_set and
+ * return it, advancing the buffer pointer.
+ */
+static gss_OID_set
+get_mech_set(OM_uint32 *minor_status, unsigned char **buff_in, int buff_length)
+{
+       gss_OID_set returned_mechSet;
+       OM_uint32 major_status;
+       OM_uint32 length;
+       OM_uint32 bytes;
+       OM_uint32 set_length;
+       unsigned char           *start;
+       int i;
+
+       if (**buff_in != SEQUENCE_OF)
+               return (NULL);
+
+       start = *buff_in;
+       (*buff_in)++;
+
+       length = gssint_get_der_length(buff_in, buff_length, &bytes);
+
+       major_status = gss_create_empty_oid_set(minor_status,
+                                               &returned_mechSet);
+       if (major_status != GSS_S_COMPLETE)
+               return (NULL);
+
+       for (set_length = 0, i = 0; set_length < length; i++) {
+               gss_OID_desc *temp = get_mech_oid(minor_status, buff_in,
+                       buff_length - (*buff_in - start));
+               if (temp != NULL) {
+                   major_status = gss_add_oid_set_member(minor_status,
+                                       temp, &returned_mechSet);
+                   if (major_status == GSS_S_COMPLETE) {
+                       set_length += returned_mechSet->elements[i].length +2;
+                       generic_gss_release_oid(minor_status, &temp);
+                   }
+               }
+       }
+
+       return (returned_mechSet);
+}
+
+/*
+ * Encode mechSet into buf.
+ */
+static int
+put_mech_set(gss_OID_set mechSet, gss_buffer_t buf)
+{
+       unsigned char *ptr;
+       int i, tlen, ilen;
+
+       tlen = ilen = 0;
+       for (i = 0; i < mechSet->count; i++) {
+               /*
+                * 0x06 [DER LEN] [OID]
+                */
+               ilen += 1 +
+                       gssint_der_length_size(mechSet->elements[i].length) +
+                       mechSet->elements[i].length;
+       }
+       /*
+        * 0x30 [DER LEN]
+        */
+       tlen = 1 + gssint_der_length_size(ilen) + ilen;
+       ptr = malloc(tlen);
+       if (ptr == NULL)
+               return -1;
+
+       buf->value = ptr;
+       buf->length = tlen;
+#define REMAIN (buf->length - ((unsigned char *)buf->value - ptr))
+
+       *ptr++ = SEQUENCE_OF;
+       if (gssint_put_der_length(ilen, &ptr, REMAIN) < 0)
+               return -1;
+       for (i = 0; i < mechSet->count; i++) {
+               if (put_mech_oid(&ptr, &mechSet->elements[i], REMAIN) < 0) {
+                       return -1;
+               }
+       }
+       return 0;
+#undef REMAIN
+}
+
+/*
+ * Verify that buff_in is pointing to a BIT_STRING with the correct
+ * length and padding for the req_flags. If it is, decode req_flags
+ * and return them, otherwise, return NULL.
+ */
+static OM_uint32
+get_req_flags(unsigned char **buff_in, OM_uint32 bodysize,
+             OM_uint32 *req_flags)
+{
+       int len;
+       unsigned char *start = *buff_in;
+
+       if (**buff_in != (CONTEXT | 0x01))
+               return (0);
+
+       if (g_get_tag_and_length(buff_in, (CONTEXT | 0x01),
+                               bodysize, &len) < 0)
+               return GSS_S_DEFECTIVE_TOKEN;
+
+       if (*(*buff_in)++ != BIT_STRING)
+               return GSS_S_DEFECTIVE_TOKEN;
+
+       if (*(*buff_in)++ != BIT_STRING_LENGTH)
+               return GSS_S_DEFECTIVE_TOKEN;
+
+       if (*(*buff_in)++ != BIT_STRING_PADDING)
+               return GSS_S_DEFECTIVE_TOKEN;
+
+       *req_flags = (OM_uint32) (*(*buff_in)++ >> 1);
+       return (0);
+}
+
+/*
+ * der encode the passed req_flags into buf_out, advancing
+ * the buffer pointer.
+ */
+
+static int
+put_req_flags(unsigned char **buf_out, OM_uint32 req_flags, int buflen)
+{
+       int ret = 0;
+       if (buflen < 6)
+               return (-1);
+
+       *(*buf_out)++ = CONTEXT | 0x01;
+       if ((ret = gssint_put_der_length(4, buf_out, buflen-1)) != 0)
+               return (ret);
+
+       *(*buf_out)++ = BIT_STRING;
+       *(*buf_out)++ = BIT_STRING_LENGTH;
+       *(*buf_out)++ = BIT_STRING_PADDING;
+       *(*buf_out)++ = (unsigned char) (req_flags << 1);
+       return (ret);
+}
+
+static OM_uint32
+get_negTokenInit(OM_uint32 *minor_status,
+                gss_buffer_t buf,
+                gss_buffer_t der_mechSet,
+                gss_OID_set *mechSet,
+                OM_uint32 *req_flags,
+                gss_buffer_t *mechtok,
+                gss_buffer_t *mechListMIC)
+{
+       OM_uint32 err;
+       unsigned char *ptr, *bufstart;
+       int len;
+       gss_buffer_desc tmpbuf;
+
+       *minor_status = 0;
+       der_mechSet->length = 0;
+       der_mechSet->value = NULL;
+       *mechSet = GSS_C_NO_OID_SET;
+       *req_flags = 0;
+       *mechtok = *mechListMIC = GSS_C_NO_BUFFER;
+
+       ptr = bufstart = buf->value;
+       if ((buf->length - (ptr - bufstart)) > INT_MAX)
+               return GSS_S_FAILURE;
+#define REMAIN ((int)(buf->length - (ptr - bufstart)))
+
+       err = g_verify_token_header(gss_mech_spnego,
+                                   &len, &ptr, 0, REMAIN);
+       if (err) {
+               *minor_status = err;
+               return GSS_S_FAILURE;
+       }
+       *minor_status = g_verify_neg_token_init(&ptr, REMAIN);
+       if (*minor_status)
+               return GSS_S_FAILURE;
+
+       /* alias into input_token */
+       tmpbuf.value = ptr;
+       tmpbuf.length = REMAIN;
+       *mechSet = get_mech_set(minor_status, &ptr, REMAIN);
+       if (*mechSet == NULL)
+               return GSS_S_FAILURE;
+
+       tmpbuf.length = ptr - (unsigned char *)tmpbuf.value;
+       der_mechSet->value = malloc(tmpbuf.length);
+       if (der_mechSet->value == NULL)
+               return GSS_S_FAILURE;
+       memcpy(der_mechSet->value, tmpbuf.value, tmpbuf.length);
+       der_mechSet->length = tmpbuf.length;
+
+       err = get_req_flags(&ptr, REMAIN, req_flags);
+       if (err != GSS_S_COMPLETE) {
+               return err;
+       }
+       if (g_get_tag_and_length(&ptr, (CONTEXT | 0x02),
+                                REMAIN, &len) >= 0) {
+               *mechtok = get_input_token(&ptr, len);
+               if (*mechtok == GSS_C_NO_BUFFER) {
+                       return GSS_S_FAILURE;
+               }
+       }
+       if (g_get_tag_and_length(&ptr, (CONTEXT | 0x03),
+                                REMAIN, &len) >= 0) {
+               *mechListMIC = get_input_token(&ptr, len);
+               if (*mechListMIC == GSS_C_NO_BUFFER) {
+                       return GSS_S_FAILURE;
+               }
+       }
+       return GSS_S_COMPLETE;
+#undef REMAIN
+}
+
+static OM_uint32
+get_negTokenResp(OM_uint32 *minor_status,
+                unsigned char *buf, unsigned int buflen,
+                OM_uint32 *negState,
+                gss_OID *supportedMech,
+                gss_buffer_t *responseToken,
+                gss_buffer_t *mechListMIC)
+{
+       unsigned char *ptr, *bufstart;
+       int len, bytes;
+       unsigned int tag;
+
+       *negState = ACCEPT_DEFECTIVE_TOKEN;
+       *supportedMech = GSS_C_NO_OID;
+       *responseToken = *mechListMIC = GSS_C_NO_BUFFER;
+       ptr = bufstart = buf;
+#define REMAIN (buflen - (ptr - bufstart))
+
+       if (g_get_tag_and_length(&ptr, (CONTEXT | 0x01), REMAIN, &len) < 0)
+               return GSS_S_DEFECTIVE_TOKEN;
+       if (*ptr++ == SEQUENCE) {
+               len = gssint_get_der_length(&ptr, REMAIN, &bytes);
+               if (len < 0)
+                       return GSS_S_DEFECTIVE_TOKEN;
+       }
+       if (REMAIN < 1)
+               tag = 0;
+       else
+               tag = *ptr++;
+
+       if (tag == CONTEXT) {
+               len = gssint_get_der_length(&ptr, REMAIN, &bytes);
+               if (len < 0)
+                       return GSS_S_DEFECTIVE_TOKEN;
+
+               if (g_get_tag_and_length(&ptr, ENUMERATED,
+                                        REMAIN, &len) < 0)
+                       return GSS_S_DEFECTIVE_TOKEN;
+
+               if (len != ENUMERATION_LENGTH)
+                       return GSS_S_DEFECTIVE_TOKEN;
+
+               if (REMAIN < 1)
+                       return GSS_S_DEFECTIVE_TOKEN;
+               *negState = *ptr++;
+
+               if (REMAIN < 1)
+                       tag = 0;
+               else
+                       tag = *ptr++;
+       }
+       if (tag == (CONTEXT | 0x01)) {
+               len = gssint_get_der_length(&ptr, REMAIN, &bytes);
+               if (len < 0)
+                       return GSS_S_DEFECTIVE_TOKEN;
+
+               *supportedMech = get_mech_oid(minor_status, &ptr, REMAIN);
+               if (*supportedMech == GSS_C_NO_OID)
+                       return GSS_S_DEFECTIVE_TOKEN;
+
+               if (REMAIN < 1)
+                       tag = 0;
+               else
+                       tag = *ptr++;
+       }
+       if (tag == (CONTEXT | 0x02)) {
+               len = gssint_get_der_length(&ptr, REMAIN, &bytes);
+               if (len < 0)
+                       return GSS_S_DEFECTIVE_TOKEN;
+
+               *responseToken = get_input_token(&ptr, REMAIN);
+               if (*responseToken == GSS_C_NO_BUFFER)
+                       return GSS_S_DEFECTIVE_TOKEN;
+
+               if (REMAIN < 1)
+                       tag = 0;
+               else
+                       tag = *ptr++;
+       }
+       if (tag == (CONTEXT | 0x03)) {
+               len = gssint_get_der_length(&ptr, REMAIN, &bytes);
+               if (len < 0)
+                       return GSS_S_DEFECTIVE_TOKEN;
+
+               *mechListMIC = get_input_token(&ptr, REMAIN);
+               if (*mechListMIC == GSS_C_NO_BUFFER)
+                       return GSS_S_DEFECTIVE_TOKEN;
+       }
+       return GSS_S_COMPLETE;
+#undef REMAIN
+}
+
+/*
+ * der encode the passed negResults as an ENUMERATED type and
+ * place it in buf_out, advancing the buffer.
+ */
+
+static int
+put_negResult(unsigned char **buf_out, OM_uint32 negResult, int buflen)
+{
+       if (buflen < 3)
+               return (-1);
+       *(*buf_out)++ = ENUMERATED;
+       *(*buf_out)++ = ENUMERATION_LENGTH;
+       *(*buf_out)++ = (unsigned char) negResult;
+       return (0);
+}
+
+/*
+ * This routine compares the recieved mechset to the mechset that
+ * this server can support. It looks sequentially through the mechset
+ * and the first one that matches what the server can support is
+ * chosen as the negotiated mechanism. If one is found, negResult
+ * is set to ACCEPT_INCOMPLETE if it's the first mech, REQUEST_MIC if
+ * it's not the first mech, otherwise we return NULL and negResult
+ * is set to REJECT.
+ *
+ * NOTE: There is currently no way to specify a preference order of
+ * mechanisms supported by the acceptor.
+ */
+static gss_OID
+negotiate_mech_type(OM_uint32 *minor_status,
+                   gss_OID_set supported_mechSet,
+                   gss_OID_set mechset,
+                   OM_uint32 *negResult)
+{
+       gss_OID returned_mech;
+       OM_uint32 status;
+       int present;
+       int i;
+
+       for (i = 0; i < mechset->count; i++) {
+               gss_test_oid_set_member(minor_status, &mechset->elements[i],
+                                       supported_mechSet, &present);
+               if (!present)
+                       continue;
+
+               if (i == 0)
+                       *negResult = ACCEPT_INCOMPLETE;
+               else
+                       *negResult = REQUEST_MIC;
+
+               status = generic_gss_copy_oid(minor_status,
+                                             &mechset->elements[i],
+                                             &returned_mech);
+               if (status != GSS_S_COMPLETE) {
+                       *negResult = REJECT;
+                       return (NULL);
+               }
+               return (returned_mech);
+       }
+       *negResult = REJECT;
+       return (NULL);
+}
+
+/*
+ * the next two routines make a token buffer suitable for
+ * spnego_gss_display_status. These currently take the string
+ * in name and place it in the token. Eventually, if
+ * spnego_gss_display_status returns valid error messages,
+ * these routines will be changes to return the error string.
+ */
+static spnego_token_t
+make_spnego_token(char *name)
+{
+       spnego_token_t token;
+
+       token = (spnego_token_t)malloc(strlen(name)+1);
+
+       if (token == NULL)
+               return (NULL);
+       strcpy(token, name);
+       return (token);
+}
+
+static gss_buffer_desc
+make_err_msg(char *name)
+{
+       gss_buffer_desc buffer;
+
+       if (name == NULL) {
+               buffer.length = 0;
+               buffer.value = NULL;
+       } else {
+               buffer.length = strlen(name)+1;
+               buffer.value = make_spnego_token(name);
+       }
+
+       return (buffer);
+}
+
+/*
+ * Create the client side spnego token passed back to gss_init_sec_context
+ * and eventually up to the application program and over to the server.
+ *
+ * Use DER rules, definite length method per RFC 2478
+ */
+static int
+make_spnego_tokenInit_msg(spnego_gss_ctx_id_t spnego_ctx,
+                         gss_buffer_t mechListMIC, OM_uint32 req_flags,
+                         gss_buffer_t data, send_token_flag sendtoken,
+                         gss_buffer_t outbuf)
+{
+       int tlen, dataLen = 0, ret = 0;
+       int negTokenInitSize = 0;
+       int negTokenInitSeqSize = 0;
+       int negTokenInitContSize = 0;
+       int rspTokenSize = 0;
+       int mechListTokenSize = 0;
+       int micTokenSize = 0;
+       int i;
+       unsigned char *t;
+       unsigned char *ptr;
+       unsigned char *MechListPtr = NULL;
+       gss_buffer_desc MICbuff;
+
+       if (outbuf == GSS_C_NO_BUFFER)
+               return (-1);
+
+       outbuf->length = 0;
+       outbuf->value = NULL;
+
+       /* calculate the data length */
+
+       /*
+        * 0xa0 [DER LEN] [mechTypes]
+        */
+       mechListTokenSize = 1 +
+               gssint_der_length_size(spnego_ctx->DER_mechTypes.length) +
+               spnego_ctx->DER_mechTypes.length;
+       dataLen += mechListTokenSize;
+       /*
+        * 4 bytes for ret_flags:
+        *   ASN.1 token + ASN.1 Length + Padding + Flags
+        *   0xa1 LENGTH BIT_STRING BIT_STRING_LEN PAD DATA
+        */
+       if (req_flags != 0)
+               dataLen += 6;
+
+       /*
+        * If a token from gss_init_sec_context exists,
+        * add the length of the token + the ASN.1 overhead
+        */
+       if (data != NULL) {
+               /*
+                * Encoded in final output as:
+                * 0xa2 [DER LEN] 0x04 [DER LEN] [DATA]
+                * -----s--------|--------s2----------
+                */
+               rspTokenSize = 1 +
+                       gssint_der_length_size(data->length) +
+                       data->length;
+               dataLen += 1 + gssint_der_length_size(rspTokenSize) +
+                       rspTokenSize;
+       }
+
+       if (mechListMIC) {
+               /*
+                * Encoded in final output as:
+                * 0xa3 [DER LEN] 0x04 [DER LEN] [DATA]
+                *      --s--     -----tlen------------
+                */
+               micTokenSize = 1 +
+                       gssint_der_length_size(mechListMIC->length) +
+                       mechListMIC->length;
+               dataLen += 1 +
+                       gssint_der_length_size(micTokenSize) +
+                       micTokenSize;
+       }
+
+       /*
+        * Add size of DER encoding
+        * [ SEQUENCE { MechTypeList | ReqFLags | Token | mechListMIC } ]
+        *   0x30 [DER_LEN] [data]
+        *
+        */
+       negTokenInitContSize = dataLen;
+       negTokenInitSeqSize = 1 + gssint_der_length_size(dataLen) + dataLen;
+       dataLen = negTokenInitSeqSize;
+
+       /*
+        * negTokenInitSize indicates the bytes needed to
+        * hold the ASN.1 encoding of the entire NegTokenInit
+        * SEQUENCE.
+        * 0xa0 [DER_LEN] + data
+        *
+        */
+       negTokenInitSize = 1 +
+               gssint_der_length_size(negTokenInitSeqSize) +
+               negTokenInitSeqSize;
+
+       tlen = g_token_size(gss_mech_spnego, negTokenInitSize);
+
+       t = (unsigned char *) malloc(tlen);
+
+       if (t == NULL) {
+               return (-1);
+       }
+
+       ptr = t;
+
+       /* create the message */
+       if ((ret = g_make_token_header(gss_mech_spnego, negTokenInitSize,
+                           &ptr, tlen)))
+               goto errout;
+
+       *ptr++ = CONTEXT; /* NegotiationToken identifier */
+       if ((ret = gssint_put_der_length(negTokenInitSeqSize, &ptr, tlen)))
+               goto errout;
+
+       *ptr++ = SEQUENCE;
+       if ((ret = gssint_put_der_length(negTokenInitContSize, &ptr,
+                                        tlen - (int)(ptr-t))))
+               goto errout;
+
+       *ptr++ = CONTEXT; /* MechTypeList identifier */
+       if ((ret = gssint_put_der_length(spnego_ctx->DER_mechTypes.length,
+                                        &ptr, tlen - (int)(ptr-t))))
+               goto errout;
+
+       /* We already encoded the MechSetList */
+       (void) memcpy(ptr, spnego_ctx->DER_mechTypes.value,
+                     spnego_ctx->DER_mechTypes.length);
+
+       ptr += spnego_ctx->DER_mechTypes.length;
+
+       if (req_flags != 0) {
+               if ((ret = put_req_flags(&ptr, req_flags,
+                                        tlen - (int)(ptr-t))))
+                       goto errout;
+       }
+
+       if (data != NULL) {
+               *ptr++ = CONTEXT | 0x02;
+               if ((ret = gssint_put_der_length(rspTokenSize,
+                               &ptr, tlen - (int)(ptr - t))))
+                       goto errout;
+
+               if ((ret = put_input_token(&ptr, data,
+                       tlen - (int)(ptr - t))))
+                       goto errout;
+       }
+
+       if (mechListMIC != GSS_C_NO_BUFFER) {
+               *ptr++ = CONTEXT | 0x03;
+               if ((ret = gssint_put_der_length(micTokenSize,
+                               &ptr, tlen - (int)(ptr - t))))
+                       goto errout;
+
+               if ((ret = put_input_token(&ptr, mechListMIC,
+                               tlen - (int)(ptr - t))))
+                       goto errout;
+       }
+
+errout:
+       if (ret != 0) {
+               if (t)
+                       free(t);
+               t = NULL;
+               tlen = 0;
+       }
+       outbuf->length = tlen;
+       outbuf->value = (void *) t;
+
+       return (ret);
+}
+
+/*
+ * create the server side spnego token passed back to
+ * gss_accept_sec_context and eventually up to the application program
+ * and over to the client.
+ */
+static int
+make_spnego_tokenTarg_msg(OM_uint32 status, gss_OID mech_wanted,
+                         gss_buffer_t data, gss_buffer_t mechListMIC,
+                         send_token_flag sendtoken,
+                         gss_buffer_t outbuf)
+{
+       int tlen;
+       int ret;
+       int NegTokenTargSize;
+       int negresultTokenSize;
+       int NegTokenSize;
+       int rspTokenSize;
+       int micTokenSize;
+       int dataLen = 0;
+       unsigned char *t;
+       unsigned char *ptr;
+
+       if (outbuf == GSS_C_NO_BUFFER)
+               return (GSS_S_DEFECTIVE_TOKEN);
+
+       outbuf->length = 0;
+       outbuf->value = NULL;
+
+       /*
+        * ASN.1 encoding of the negResult
+        * ENUMERATED type is 3 bytes
+        *  ENUMERATED TAG, Length, Value,
+        * Plus 2 bytes for the CONTEXT id and length.
+        */
+       dataLen = 5;
+
+       /*
+        * calculate data length
+        *
+        * If this is the initial token, include length of
+        * mech_type and the negotiation result fields.
+        */
+       if (sendtoken == INIT_TOKEN_SEND) {
+               int mechlistTokenSize;
+               /*
+                * 1 byte for the CONTEXT ID(0xa0),
+                * 1 byte for the OID ID(0x06)
+                * 1 byte for OID Length field
+                * Plus the rest... (OID Length, OID value)
+                */
+               mechlistTokenSize = 3 + mech_wanted->length +
+                       gssint_der_length_size(mech_wanted->length);
+
+               dataLen += mechlistTokenSize;
+       }
+       if (data != NULL && data->length > 0) {
+               /* Length of the inner token */
+               rspTokenSize = 1 + gssint_der_length_size(data->length) +
+                       data->length;
+
+               dataLen += rspTokenSize;
+
+               /* Length of the outer token */
+               dataLen += 1 + gssint_der_length_size(rspTokenSize);
+       }
+       if (mechListMIC != NULL) {
+
+               /* Length of the inner token */
+               micTokenSize = 1 + gssint_der_length_size(mechListMIC->length) +
+                       mechListMIC->length;
+
+               dataLen += micTokenSize;
+
+               /* Length of the outer token */
+               dataLen += 1 + gssint_der_length_size(micTokenSize);
+       }
+       /*
+        * Add size of DER encoded:
+        * NegTokenTarg [ SEQUENCE ] of
+        *    NegResult[0] ENUMERATED {
+        *      accept_completed(0),
+        *      accept_incomplete(1),
+        *      reject(2) }
+        *    supportedMech [1] MechType OPTIONAL,
+        *    responseToken [2] OCTET STRING OPTIONAL,
+        *    mechListMIC   [3] OCTET STRING OPTIONAL
+        *
+        * size = data->length + MechListMic + SupportedMech len +
+        *      Result Length + ASN.1 overhead
+        */
+       NegTokenTargSize = dataLen;
+       dataLen += 1 + gssint_der_length_size(NegTokenTargSize);
+
+       /*
+        * NegotiationToken [ CHOICE ]{
+        *    negTokenInit  [0]  NegTokenInit,
+        *    negTokenTarg  [1]  NegTokenTarg }
+        */
+       NegTokenSize = dataLen;
+       dataLen += 1 + gssint_der_length_size(NegTokenSize);
+
+       tlen = dataLen;
+       t = (unsigned char *) malloc(tlen);
+
+       if (t == NULL) {
+               ret = GSS_S_DEFECTIVE_TOKEN;
+               goto errout;
+       }
+
+       ptr = t;
+
+       /*
+        * Indicate that we are sending CHOICE 1
+        * (NegTokenTarg)
+        */
+       *ptr++ = CONTEXT | 0x01;
+       if (gssint_put_der_length(NegTokenSize, &ptr, dataLen) < 0) {
+               ret = GSS_S_DEFECTIVE_TOKEN;
+               goto errout;
+       }
+       *ptr++ = SEQUENCE;
+       if (gssint_put_der_length(NegTokenTargSize, &ptr,
+                                 tlen - (int)(ptr-t)) < 0) {
+               ret = GSS_S_DEFECTIVE_TOKEN;
+               goto errout;
+       }
+
+       /*
+        * First field of the NegTokenTarg SEQUENCE
+        * is the ENUMERATED NegResult.
+        */
+       *ptr++ = CONTEXT;
+       if (gssint_put_der_length(3, &ptr,
+                                 tlen - (int)(ptr-t)) < 0) {
+               ret = GSS_S_DEFECTIVE_TOKEN;
+               goto errout;
+       }
+       if (put_negResult(&ptr, status, tlen - (int)(ptr - t)) < 0) {
+               ret = GSS_S_DEFECTIVE_TOKEN;
+               goto errout;
+       }
+       if (sendtoken == INIT_TOKEN_SEND) {
+               /*
+                * Next, is the Supported MechType
+                */
+               *ptr++ = CONTEXT | 0x01;
+               if (gssint_put_der_length(mech_wanted->length + 2,
+                                         &ptr,
+                                         tlen - (int)(ptr - t)) < 0) {
+                       ret = GSS_S_DEFECTIVE_TOKEN;
+                       goto errout;
+               }
+               if (put_mech_oid(&ptr, mech_wanted,
+                                tlen - (int)(ptr - t)) < 0) {
+                       ret = GSS_S_DEFECTIVE_TOKEN;
+                       goto errout;
+               }
+       }
+       if (data != NULL && data->length > 0) {
+               *ptr++ = CONTEXT | 0x02;
+               if (gssint_put_der_length(rspTokenSize, &ptr,
+                                         tlen - (int)(ptr - t)) < 0) {
+                       ret = GSS_S_DEFECTIVE_TOKEN;
+                       goto errout;
+               }
+               if (put_input_token(&ptr, data,
+                                   tlen - (int)(ptr - t)) < 0) {
+                       ret = GSS_S_DEFECTIVE_TOKEN;
+                       goto errout;
+               }
+       }
+       if (mechListMIC != NULL) {
+               *ptr++ = CONTEXT | 0x03;
+               if (gssint_put_der_length(micTokenSize, &ptr,
+                                         tlen - (int)(ptr - t)) < 0) {
+                       ret = GSS_S_DEFECTIVE_TOKEN;
+                       goto errout;
+               }
+               if (put_input_token(&ptr, mechListMIC,
+                                   tlen - (int)(ptr - t)) < 0) {
+                       ret = GSS_S_DEFECTIVE_TOKEN;
+                       goto errout;
+               }
+       }
+       ret = GSS_S_COMPLETE;
+errout:
+       if (ret != GSS_S_COMPLETE) {
+               if (t)
+                       free(t);
+       } else {
+               outbuf->length = ptr - t;
+               outbuf->value = (void *) t;
+       }
+
+       return (ret);
+}
+
+/* determine size of token */
+static int
+g_token_size(gss_OID_const mech, unsigned int body_size)
+{
+       int hdrsize;
+
+       /*
+        * Initialize the header size to the
+        * MECH_OID byte + the bytes needed to indicate the
+        * length of the OID + the OID itself.
+        *
+        * 0x06 [MECHLENFIELD] MECHDATA
+        */
+       hdrsize = 1 + gssint_der_length_size(mech->length) + mech->length;
+
+       /*
+        * Now add the bytes needed for the initial header
+        * token bytes:
+        * 0x60 + [DER_LEN] + HDRSIZE
+        */
+       hdrsize += 1 + gssint_der_length_size(body_size + hdrsize);
+
+       return (hdrsize + body_size);
+}
+
+/*
+ * generate token header.
+ *
+ * Use DER Definite Length method per RFC2478
+ * Use of indefinite length encoding will not be compatible
+ * with Microsoft or others that actually follow the spec.
+ */
+static int
+g_make_token_header(gss_OID_const mech,
+                   int body_size,
+                   unsigned char **buf,
+                   int totallen)
+{
+       int hdrsize, ret = 0;
+       unsigned char *p = *buf;
+
+       hdrsize = 1 + gssint_der_length_size(mech->length) + mech->length;
+
+       *(*buf)++ = HEADER_ID;
+       if ((ret = gssint_put_der_length(hdrsize + body_size, buf, totallen)))
+               return (ret);
+
+       *(*buf)++ = MECH_OID;
+       if ((ret = gssint_put_der_length(mech->length, buf,
+                           totallen - (int)(p - *buf))))
+               return (ret);
+       TWRITE_STR(*buf, mech->elements, ((int)mech->length));
+       return (0);
+}
+
+/*
+ * NOTE: This checks that the length returned by
+ * gssint_get_der_length() is not greater than the number of octets
+ * remaining, even though gssint_get_der_length() already checks, in
+ * theory.
+ */
+static int
+g_get_tag_and_length(unsigned char **buf, int tag, int buflen, int *outlen)
+{
+       unsigned char *ptr = *buf;
+       int ret = -1; /* pessimists, assume failure ! */
+       unsigned int encoded_len;
+
+       if (buflen > 1 && *ptr == tag) {
+               ptr++;
+               *outlen = gssint_get_der_length(&ptr, buflen - 1,
+                                               &encoded_len);
+               if (*outlen < 0) {
+                       ret = -1;
+               } else if (*outlen > buflen - (ptr - *buf)) {
+                       ret = -1;
+               } else
+                       ret = 0;
+       }
+
+       *buf = ptr;
+       return (ret);
+}
+
+static int
+g_verify_neg_token_init(unsigned char **buf_in, int cur_size)
+{
+       unsigned char *buf = *buf_in;
+       unsigned char *endptr = buf + cur_size;
+       int seqsize;
+       int ret = 0;
+       unsigned int bytes;
+
+       /*
+        * Verify this is a NegotiationToken type token
+        * - check for a0(context specific identifier)
+        * - get length and verify that enoughd ata exists
+        */
+       if (g_get_tag_and_length(&buf, CONTEXT, cur_size, &seqsize) < 0)
+               return (G_BAD_TOK_HEADER);
+
+       cur_size = seqsize; /* should indicate bytes remaining */
+
+       /*
+        * Verify the next piece, it should identify this as
+        * a strucure of type NegTokenInit.
+        */
+       if (*buf++ == SEQUENCE) {
+               if ((seqsize = gssint_get_der_length(&buf, cur_size, &bytes)) < 0)
+                       return (G_BAD_TOK_HEADER);
+               /*
+                * Make sure we have the entire buffer as described
+                */
+               if (buf + seqsize > endptr)
+                       return (G_BAD_TOK_HEADER);
+       } else {
+               return (G_BAD_TOK_HEADER);
+       }
+
+       cur_size = seqsize; /* should indicate bytes remaining */
+
+       /*
+        * Verify that the first blob is a sequence of mechTypes
+        */
+       if (*buf++ == CONTEXT) {
+               if ((seqsize = gssint_get_der_length(&buf, cur_size, &bytes)) < 0)
+                       return (G_BAD_TOK_HEADER);
+               /*
+                * Make sure we have the entire buffer as described
+                */
+               if (buf + bytes > endptr)
+                       return (G_BAD_TOK_HEADER);
+       } else {
+               return (G_BAD_TOK_HEADER);
+       }
+
+       /*
+        * At this point, *buf should be at the beginning of the
+        * DER encoded list of mech types that are to be negotiated.
+        */
+       *buf_in = buf;
+
+       return (ret);
+
+}
+
+/* verify token header. */
+static int
+g_verify_token_header(gss_OID_const mech,
+                   int *body_size,
+                   unsigned char **buf_in,
+                   int tok_type,
+                   int toksize)
+{
+       unsigned char *buf = *buf_in;
+       int seqsize;
+       gss_OID_desc toid;
+       int ret = 0;
+       unsigned int bytes;
+
+       if ((toksize -= 1) < 0)
+               return (G_BAD_TOK_HEADER);
+
+       if (*buf++ != HEADER_ID)
+               return (G_BAD_TOK_HEADER);
+
+       if ((seqsize = gssint_get_der_length(&buf, toksize, &bytes)) < 0)
+               return (G_BAD_TOK_HEADER);
+
+       if ((seqsize + bytes) != toksize)
+               return (G_BAD_TOK_HEADER);
+
+       if ((toksize -= 1) < 0)
+               return (G_BAD_TOK_HEADER);
+
+
+       if (*buf++ != MECH_OID)
+               return (G_BAD_TOK_HEADER);
+
+       if ((toksize -= 1) < 0)
+               return (G_BAD_TOK_HEADER);
+
+       toid.length = *buf++;
+
+       if ((toksize -= toid.length) < 0)
+               return (G_BAD_TOK_HEADER);
+
+       toid.elements = buf;
+       buf += toid.length;
+
+       if (!g_OID_equal(&toid, mech))
+               ret = G_WRONG_MECH;
+
+       /*
+        * G_WRONG_MECH is not returned immediately because it's more important
+        * to return G_BAD_TOK_HEADER if the token header is in fact bad
+        */
+       if ((toksize -= 2) < 0)
+               return (G_BAD_TOK_HEADER);
+
+       if (!ret) {
+               *buf_in = buf;
+               *body_size = toksize;
+       }
+
+       return (ret);
+}
index 7ddefe5e82649e7e0c15862d4dd4ef14d3188940..ec2410331f925845060da2042269b76470c1cf59 100644 (file)
@@ -972,7 +972,6 @@ void svcauth_gssapi_unset_names(void)
                    gss_release_cred(&minor_stat, &server_creds_list[i]);
          free(server_creds_list);
          server_creds_list = NULL;
-         server_creds_count = 0;
      }
 
      if (server_name_list) {
@@ -981,8 +980,8 @@ void svcauth_gssapi_unset_names(void)
                    gss_release_name(&minor_stat, &server_name_list[i]);
          free(server_name_list);
          server_name_list = NULL;
-         server_creds_count = 0;
      }
+     server_creds_count = 0;
 }
 
 
index 5c33ffde52e7a44e65da095648020498a7aad470..f5841011f85954e263298b8f73d24490eeaf731a 100644 (file)
@@ -12,7 +12,7 @@ proc expired {} {
 
     expect {
        -i $server_id
-       -re "rpc_test server: Authen.*failed: .* referenced credentials have expired" { pass "expired" }
+       -re "rpc_test server: Authen.*failed:.*credential.*expired" { pass "expired" }
        timeout { fail "expired: timeout waiting for expired creds error" }
     }
 
index e739e9bd98f248724ac6a88f7ae0013e6e62860a..6353dc41f137c2f2730e4ceefceaba20e75b574a 100644 (file)
@@ -249,7 +249,7 @@ proc v4ftp_test { } {
     expect -nocase -re "$localhostname.*ftp server .version \[0-9.\]*. ready."
     expect -re "Using authentication type GSSAPI; ADAT must follow"
     expect "GSSAPI accepted as authentication type"
-    expect "GSSAPI error major: Miscellaneous failure"
+    expect -re "GSSAPI error major: (Unspecified GSS|Miscellaneous) failure"
     expect {
        "GSSAPI error minor: Unsupported credentials cache format version number" {}
        "GSSAPI error minor: No credentials cache found" {}