interim commit
authorTom Yu <tlyu@mit.edu>
Thu, 26 Jan 2006 22:05:08 +0000 (22:05 +0000)
committerTom Yu <tlyu@mit.edu>
Thu, 26 Jan 2006 22:05:08 +0000 (22:05 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/users/tlyu/branches/mechglue@17628 dc483132-0cff-0310-8789-dd5450dbe970

50 files changed:
src/lib/gssapi/Makefile.in
src/lib/gssapi/configure.in
src/lib/gssapi/generic/Makefile.in
src/lib/gssapi/generic/gssapi.hin
src/lib/gssapi/generic/gssapi_err_generic.et
src/lib/gssapi/gss_libinit.c
src/lib/gssapi/krb5/Makefile.in
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/krb5_gss_glue.c
src/lib/gssapi/krb5/lucid_context.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_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

index c3d0be67c459ebb102383eef1fa7b6ab4c24c76b..2f7ed757a4c3309fdeed3e62585470527462bae8 100644 (file)
@@ -2,7 +2,7 @@ thisconfigdir=.
 myfulldir=lib/gssapi
 mydir=.
 BUILDTOP=$(REL)..$(S)..
-LOCAL_SUBDIRS= generic krb5
+LOCAL_SUBDIRS= generic mechglue krb5
 
 ##DOSLIBNAME=$(OUTPRE)gssapi.lib
 ##DOSOBJFILELIST=@$(OUTPRE)generic.lst @$(OUTPRE)krb5.lst @$(OUTPRE)gssapi.lst
@@ -13,7 +13,7 @@ LOCAL_SUBDIRS= generic krb5
 
 ##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
 
@@ -28,8 +28,8 @@ 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
+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)
index eccc62815d1e7717329631b6b322e6a0ddd32524..8c97868435f146f0546da1f4d0b65f12f2e244f5 100644 (file)
@@ -16,4 +16,4 @@ AC_CHECK_HEADER(xom.h,[
 AC_SUBST(include_xom)
 KRB5_BUILD_LIBOBJS
 KRB5_BUILD_LIBRARY_WITH_DEPS
-V5_AC_OUTPUT_MAKEFILE(. generic krb5)
+V5_AC_OUTPUT_MAKEFILE(. generic krb5 mechglue)
index 1306b7db402a309825f4f17fce26b03a6efbd14f..d80163a0866c46528df94571862082ca0e97e20f 100644 (file)
@@ -62,7 +62,6 @@ 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 \
@@ -77,7 +76,6 @@ 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) \
@@ -92,7 +90,6 @@ 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 \
index 83fe62bb1b56cff0e85b312e586fc3fa726f9cf2..d3b93548e7befbe40eddf4a53fc37135d522e380 100644 (file)
@@ -702,6 +702,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 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
index 5561b53986d3b42ab08732763ddcdad0c7066d52..1d9a2397a98c3ad610be0545c4bba40e2da6983a 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;
@@ -57,6 +62,7 @@ void gssint_lib_fini(void)
     k5_key_delete(K5_KEY_GSS_KRB5_CCACHE_NAME);
     k5_mutex_destroy(&kg_vdb.mutex);
     k5_mutex_destroy(&gssint_krb5_keytab_lock);
+    gssint_mechglue_fini();
 }
 
 OM_uint32 gssint_initialize_library (void)
index 3ef9b5b8496fdcb286d22b7ad63cbfdd960f3d85..a410d55f2000cc3516d61b6fb817bd1e2993efc9 100644 (file)
@@ -2,7 +2,7 @@ thisconfigdir=./..
 myfulldir=lib/gssapi/krb5
 mydir=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
 
 ##DOS##BUILDTOP = ..\..\..
 ##DOS##PREFIXDIR=krb5
index fd408d7fb60b0effc5e59ada76548b586f6fc321..38f1090549634256352da095acaf9c834942cd5f 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 7d7599c61016178a8aa137e73757a61220973823..c942c1868e0affbf6cf2b91716e2efc7f9ffa541 100644 (file)
@@ -74,6 +74,9 @@
 
 /** constants **/
 
+#define GSS_MECH_KRB5_OID_LENGTH 9
+#define GSS_MECH_KRB5_OID "\052\206\110\206\367\022\001\002\002"
+
 #define CKSUMTYPE_KG_CB                0x8003
 
 #define KG_TOK_CTX_AP_REQ      0x0100
@@ -631,4 +634,31 @@ 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);
+
+
 #endif /* _GSSAPIP_KRB5_H_ */
index c188e6e5a8a34e7241ebbbcd3812469ec006a20f..feb8499b280d6b2ab160b10321d23b86f82914de 100644 (file)
@@ -87,7 +87,7 @@
 
 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"},
+   {GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID},
    /* this is the unofficial, wrong OID */
    {5, "\053\005\001\005\002"},
    /* this is the v2 assigned OID */
index 583881d8e443cc5f1377d80f771b02715a127bdc..e4a9618ba342141bfec6034f5f313e60f8c4c92c 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_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
+
+struct gss_config krb5_mechanism = {
+    { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
+    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_release_oid,
+    k5glue_wrap_size_limit,
+    NULL,                      /* pname_to_uid */
+    NULL,                      /* userok */
+    k5glue_export_name,
+    NULL                       /* store_cred */
+};
+
+#ifdef KRB5_MECH_MODULE
+gss_mechanism
+gss_mech_initialize(const gss_OID oid)
+{
+    if (oid == NULL ||
+       !g_OID_equal(oid, &krb5_mechanism.mech_type)) {
+       return NULL;
+    }
+    return &krb5_mechanism;
+}
+#endif
+
+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 +410,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 +434,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 +459,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 +484,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 +495,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 +518,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 +530,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 +547,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 +559,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 +574,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 +609,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 +646,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 +667,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 +683,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 +701,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 +713,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 +737,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_release_oid(ctx, minor_status, oid)
+    void *ctx;
      OM_uint32  *minor_status;
      gss_OID    *oid;
 {
     return(krb5_gss_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 +806,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 +821,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 +838,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 +856,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 +867,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 +878,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 +897,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 +913,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 +934,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 +950,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 +963,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 +976,82 @@ 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))
+       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 = __gss_get_mechanism_cred(ucred, &krb5_mechanism.mech_type);
+    if (mcred == NULL)
+       return GSS_S_DEFECTIVE_CREDENTIAL;
+    return gss_krb5int_copy_ccache(minor_status, mcred, out_ccache);
+}
+
+/* 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))
+       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 = __gss_get_mechanism_cred(ucred, &krb5_mechanism.mech_type);
+    if (mcred == NULL)
+       return GSS_S_DEFECTIVE_CREDENTIAL;
+    return gss_krb5int_set_allowable_enctypes(minor_status, mcred,
+                                             num_ktypes, ktypes);
+}
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 88cae714a3a883a918c353945b170cbd62b29559..1ce6c4b9eb42df6d5f11fbc2940fc41848c69d6f 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 313e6715ad0cea010c6d5d974aec400dddcd4ceb..f7988b7e75feec45b177f4f35c8ea16f0f545b8b 100644 (file)
-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
 
 ##DOSBUILDTOP = ..\..\..
 ##DOSLIBNAME=..\$(OUTPRE)gssapi.$(LIBEXT)
 
 ##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::
@@ -123,3 +98,5 @@ install::
        done
 
 includes::
+
+# @libobj_frag@
index 8cc752fe7415060494a3f16404e63b3ec8e5d279..b2a21e6def5e10dc001c7569580108ef3b3cf6d2 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,6 +98,9 @@ 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);
        if (status)
@@ -90,34 +109,22 @@ gss_cred_id_t *            delegated_cred_handle;
        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;
     }
     
@@ -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) {
+           if (internal_name != NULL) {
                temp_status = __gss_convert_name_to_union_name(
-                      &temp_minor_status, mech, internal_name, src_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 = __gss_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..c0bfd3f5a305d76d657b7582fa797a4f32338469 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 = __gss_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);
     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 (__gss_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 (__gss_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,51 @@ 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 ((status = mech->gss_display_name(mech->context,
+                                            &temp_minor_status, internal_name,
+                                            &union_cred->auxinfo.name,
+                                            &union_cred->auxinfo.name_type)) !=
+           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 +361,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) __gss_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) {
+
+    if (cred != NULL && mech->gss_release_cred)
+       mech->gss_release_cred(mech->context,
+                              &temp_minor_status, &cred);
+
+    if (allocated_name)
        (void) __gss_release_internal_name(&temp_minor_status,
-                                          desired_mech, &internal_name);
+                                          &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..c786d4d
--- /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
+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 (__gss_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) __gss_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 =
+               __gss_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) __gss_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..9cd50d9debb0e79c644a8ab6c5fa6d4ff7ac5e1d 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;
@@ -82,12 +80,9 @@ int *                        name_equal;
        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,
@@ -146,7 +165,8 @@ int *                       name_equal;
                                              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);
index 6f08c9224eab2653cce3b3a602290a5c78ce0986..82262a06e1de5abcd66a7133d29c170b46d5120f 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,11 +42,16 @@ 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.
@@ -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..9678bd08377abe52e7637b3d203f0b480452b622 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,13 +46,18 @@ 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.
@@ -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..f90c8766958fc6c980338e2db636bcf77638f4d8 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;
 
@@ -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..51d552e56f586cb7940bb0394834f7a28971dbf6 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);
 
-    if (mech == NULL) 
+    if (mech && mech->gss_display_status) {
+       if (mech_type == GSS_C_NULL_OID)
+           mech_type = &mech->mech_type;
+
+       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..d850820
--- /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
+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 (__gss_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 = __gss_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) __gss_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..a9a2443667060fbfb2b20b6a173f97400e6e4169 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
@@ -66,7 +71,7 @@ gss_buffer_t          interprocess_token;
     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..6b5780c
--- /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
+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 __gss_export_internal_name(minor_status, union_name->mech_type,
+                                       union_name->mech_name, exported_name);
+}
index 6aecab7fb6d9489a13165507725392cbdb73bb9a..d807ff070d8e8572c700b6e64878d3ed97fb52be 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.
@@ -30,9 +30,7 @@
 #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;
 
@@ -41,29 +39,141 @@ extern gss_mechanism *__gss_mechs_array;
  */
 
 /*
- *  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
+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
+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
+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);
 }
 
 
@@ -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);
@@ -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,6 +279,123 @@ gss_name_t        *internal_name;
     return (GSS_S_BAD_MECH);
 }
 
+OM_uint32 __gss_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 = __gss_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 = 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 (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);
+} /*  __gss_export_internal_name */
+
 OM_uint32 __gss_display_internal_name (minor_status, mech_type, internal_name, 
                                 external_name, name_type)
 OM_uint32      *minor_status;
@@ -182,7 +417,7 @@ gss_OID             *name_type;
                                             external_name,
                                             name_type);
        else
-           status = GSS_S_BAD_BINDINGS;
+           status = GSS_S_UNAVAILABLE;
 
        return (status);
     }
@@ -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);
     }
@@ -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) __gss_release_internal_name(&tmp, &mech->mech_type,
+                                          &internal_name);
     return (major_status);
 }
 
@@ -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
+__gss_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);
+} /* ****** __gss_create_copy_buffer  ****** */
index e93b4c9acd980465f4d97c68c1049cd790d78274..e68b3e24ef25e38de68082a6c2867a86711e61a7 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,17 +52,18 @@ gss_name_t *                output_name;
 {
     gss_union_name_t   union_name;
     OM_uint32          tmp, major_status = GSS_S_FAILURE;
-    gss_OID            mech;
 
-    gss_initialize();
+    /* check output parameters */
+    if (!minor_status)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
-    if (minor_status)
-       *minor_status = 0;
+    *minor_status = 0;
 
-    /* if output_name is NULL, simply return */
+    if (GSS_EMPTY_BUFFER(input_name_buffer))
+       return (GSS_S_CALL_INACCESSIBLE_READ);
 
-    if(output_name == NULL)
-       return (GSS_S_COMPLETE);
+    if (output_name == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
     *output_name = 0;
 
@@ -70,12 +74,10 @@ gss_name_t *                output_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 = __gss_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) {
@@ -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 = 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 = __gss_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 __gss_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, __gss_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..fd3a3af4348e583591093d9a3f2a653be1da9dd2 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;
 
     /*
@@ -99,7 +110,7 @@ gss_ctx_id_t *               context_handle;
        goto error_out;
     }
     if (!mech->gss_import_sec_context) {
-       status = GSS_S_BAD_BINDINGS;
+       status = GSS_S_UNAVAILABLE;
        goto error_out;
     }
     
index 4ff47f89943da66304af65348642fc0361d2ad9d..78e0553d8afc574327e8820e4de34640d57281b1 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,20 +72,33 @@ 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;
+
+    /* 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
@@ -100,6 +109,9 @@ OM_uint32 *         time_rec;
     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;
 
@@ -108,15 +120,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 = __gss_import_internal_name(minor_status, mech_type,
+                                                union_name,
+                                                &internal_name)) != GSS_S_COMPLETE)
+           return (status);
     }
 
     /*
@@ -127,23 +138,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;
@@ -160,30 +170,40 @@ OM_uint32 *               time_rec;
      * 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) {
+    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) __gss_release_internal_name(&temp_minor_status,
                                           mech_type, &internal_name);
     }
index 09e14deed11fbdc9a4fcee5b2ca2de086d00c160..41bbb78aca9e360a01f72eb57184b3d0a57783df 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>
 
-#define g_OID_equal(o1,o2) \
-   (((o1)->length == (o2)->length) && \
-    (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0))
+#include "k5-thread.h"
 
 extern gss_mechanism krb5_gss_initialize();
 
@@ -58,113 +65,855 @@ static struct gss_config null_mech = {
 
 gss_mechanism *__gss_mechs_array = NULL;
 
+/* Local functions */
+static gss_mech_info searchMechList(const gss_OID);
+static void loadConfigFile(const char *);
+static void updateMechList(void);
+
+static void init_hardcoded(void);
+
 /*
- * This function will add a new mechanism to the mechs_array
+ * 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 OM_uint32
-add_mechanism (mech, replace)
-     gss_mechanism mech;
-     int replace;
+int
+gssint_mechglue_init(void)
 {
-    gss_mechanism *    temp_array;
-    gss_OID_set                mech_names;
-    OM_uint32          minor_status, major_status;
-    unsigned int       i;
-
-    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;
-
-       __gss_mechs_array[0] = &null_mech;
-    }
-
-    /* 
-     * 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;
+       return k5_mutex_finish_init(&g_mechListLock);
+}
+
+void
+gssint_mechglue_fini(void)
+{
+       k5_mutex_destroy(&g_mechListLock);
+}
+
 
-       /* We found a match.  Replace it? */
-       if (!replace)
-           return GSS_S_FAILURE;
+/*
+ * function used to reclaim the memory used by a gss_OID structure.
+ * This routine requires direct access to the mechList.
+ */
+OM_uint32
+gss_release_oid(minor_status, oid)
+OM_uint32 *minor_status;
+gss_OID *oid;
+{
+       OM_uint32 major;
+       gss_mech_info aMech = g_mechList;
+
+       if (minor_status == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+       *minor_status = 0;
+
+       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.
+                */
+
+               /*
+                * we can walk the mechanism list without a mutex, because we
+                * are only looking at fields which once read will never change.
+                * Mechanism entries are always added to the end, and as
+                * complete entries.
+                */
+               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)
+                               return (GSS_S_COMPLETE);
+               }
+               aMech = aMech->next;
+       } /* while */
+
+       return (generic_gss_release_oid(minor_status, oid));
+} /* gss_release_oid */
 
-       __gss_mechs_array[i] = mech;
-       return GSS_S_COMPLETE;
-    }
 
-    /* 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));
+/*
+ * 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.
+ */
+static time_t g_mechSetTime = (time_t)0;
+static gss_OID_set_desc g_mechSet = { 0, NULL };
+static k5_mutex_t g_mechSetLock;
 
-    if (temp_array == NULL)
-       return ENOMEM;
 
-    temp_array[i++] = mech;
-    temp_array[i] = &null_mech;
+OM_uint32
+gss_indicate_mechs(minorStatus, mechSet)
+OM_uint32 *minorStatus;
+gss_OID_set *mechSet;
+{
+       gss_mech_info mList;
+       char *fileName;
+       struct stat fileInfo;
+       int count, i, j;
+       gss_OID curItem;
+
+       if (!minorStatus)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+       *minorStatus = 0;
+
+
+       /* check output parameter */
+       if (mechSet == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+       fileName = MECH_CONF;
+
+       /*
+        * 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)) {
+               /*
+                * 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);
+
+               /*
+                * 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
+                * __gss_get_mechanism)
+                */
+               if (fileInfo.st_mtime > g_confFileModTime)
+               {
+                       g_confFileModTime = fileInfo.st_mtime;
+                       loadConfigFile(fileName);
+               }
+
+               /*
+                * 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;
+                       }
+               }
+
+               g_mechSetTime = fileInfo.st_mtime;
+               (void) k5_mutex_unlock(&g_mechSetLock);
+               (void) k5_mutex_unlock(&g_mechListLock);
+       } /* if g_mechSet is out of date or not initialized */
+
+       /*
+        * 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);
+       }
 
-    __gss_mechs_array = temp_array;
+       /*
+        * 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);
+       }
 
-    /*
-     * 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)
+       /* 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);
-    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);
+} /* gss_indicate_mechs */
 
-    return GSS_S_COMPLETE;
-}
+/*
+ * 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 *
+__gss_get_modOptions(oid)
+const gss_OID oid;
+{
+       gss_mech_info aMech;
+       char *modOptions = NULL;
+
+       /* make sure we have fresh data */
+       (void) k5_mutex_lock(&g_mechListLock);
+       updateMechList();
+       (void) k5_mutex_unlock(&g_mechListLock);
+
+       /* searching the list does not require a lock */
+       if ((aMech = searchMechList(oid)) == NULL ||
+               aMech->optionStr == NULL) {
+               return (NULL);
+       }
+
+       /*
+        * need to obtain a lock on this structure in case someone else
+        * will try to update it during the copy
+        */
+       (void) k5_mutex_lock(&g_mechListLock);
+       if (aMech->optionStr)
+               modOptions = strdup(aMech->optionStr);
+       (void) k5_mutex_unlock(&g_mechListLock);
+
+       return (modOptions);
+} /* __gss_get_modOptions */
 
-void gss_initialize ()
+/*
+ * given a mechanism string return the mechanism oid
+ */
+OM_uint32
+__gss_mech_to_oid(const char *mechStr, 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 == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
-#ifdef USE_SOLARIS_SHARED_LIBRARIES
-    solaris_initialize();
+       *oid = GSS_C_NULL_OID;
 
-#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 ((mechStr == NULL) || (strlen(mechStr) == 0) ||
+               (strcasecmp(mechStr, M_DEFAULT) == 0))
+               return (GSS_S_COMPLETE);
 
-    /* Initialize the krb5 mechanism */
-    mech = (gss_mechanism)krb5_gss_initialize();
-    if (mech)
-       add_mechanism (mech, 1);
+       /* ensure we have fresh data */
+       (void) k5_mutex_lock(&g_mechListLock);
+       updateMechList();
+       (void) k5_mutex_unlock(&g_mechListLock);
 
-#endif /* USE_SOLARIS_SHARED_LIBRARIES */
+       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);
+} /* __gss_mech_to_oid */
 
-    if (__gss_mechs_array == NULL) { /* this is very bad! */
-      fprintf(stderr,"gss_initialize fatal error: no mechanisms loaded!\n");
-      exit(-1);
-    }
 
-    return;
+/*
+ * Given the mechanism oid, return the readable mechanism name
+ * associated with that oid from the mech config file
+ * (/etc/gss/mech).
+ */
+const char *
+__gss_oid_to_mech(const gss_OID oid)
+{
+       gss_mech_info aMech;
+
+       if (oid == GSS_C_NULL_OID)
+               return (M_DEFAULT);
+
+       /* ensure we have fresh data */
+       (void) k5_mutex_lock(&g_mechListLock);
+       updateMechList();
+       (void) k5_mutex_unlock(&g_mechListLock);
+
+       if ((aMech = searchMechList(oid)) == NULL)
+               return (NULL);
+
+       return (aMech->mechNameStr);
+} /* __gss_oid_to_mech */
+
+
+/*
+ * return a list of mechanism strings supported
+ * upon return the array is terminated with a NULL entry
+ */
+OM_uint32
+__gss_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 */
+
+
+/*
+ * 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;
+
+       /* check if mechList needs updating */
+       if (stat(fileName, &fileInfo) == 0 &&
+               (fileInfo.st_mtime > g_confFileModTime)) {
+               loadConfigFile(fileName);
+               g_confFileModTime = fileInfo.st_mtime;
+       }
+} /* updateMechList */
+
+
+static void
+init_hardcoded(void)
+{
+       extern struct gss_config krb5_mechanism;
+       gss_mech_info cf;
+
+       if (g_mechList != NULL)
+               return;
+       cf = malloc(sizeof(*cf));
+       if (cf == NULL)
+               return;
+       memset(cf, 0, sizeof(*cf));
+       cf->uLibName = strdup("<hardcoded internal>");
+       cf->mechNameStr = "kerberos_v5";
+       cf->mech_type = &krb5_mechanism.mech_type;
+       cf->mech = &krb5_mechanism;
+       cf->next = NULL;
+       g_mechList = cf;
 }
 
+
+/*
+ * 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
+__gss_get_mechanism(oid)
+const gss_OID oid;
+{
+       gss_mech_info aMech;
+       gss_mechanism (*sym)(const gss_OID);
+       void *dl;
+
+       if (gssint_initialize_library())
+               return GSS_S_FAILURE;
+
+       /* check if the mechanism is already loaded */
+       if ((aMech = searchMechList(oid)) != NULL && aMech->mech) {
+               return (aMech->mech);
+       }
+
+       /*
+        * might need to re-read the configuration file before loading
+        * the mechanism to ensure we have the latest info.
+        */
+       (void) k5_mutex_lock(&g_mechListLock);
+       updateMechList();
+
+       aMech = searchMechList(oid);
+
+       /* is the mechanism present in the list ? */
+       if (aMech == NULL) {
+               (void) k5_mutex_unlock(&g_mechListLock);
+               return ((gss_mechanism)NULL);
+       }
+
+       /* has another thread loaded the mech */
+       if (aMech->mech) {
+               (void) k5_mutex_unlock(&g_mechListLock);
+               return (aMech->mech);
+       }
+
+       /* 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 (*)(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 */
+       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);
+} /* __gss_get_mechanism */
+
+gss_mechanism_ext
+__gss_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 (__gss_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
+               free(mech_ext); /* we raced and lost; don't leak */
+
+       (void) k5_mutex_unlock(&g_mechListLock);
+
+       return (aMech->mech_ext);
+
+} /* __gss_get_mechanism_ext */
+
+
+/*
+ * this routine is used for searching the list of mechanism data.
+ * it needs not be mutex protected because we only add new structures
+ * from the end and they are fully initialized before being added.
+ */
+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;
+               }
+
+               aMech = searchMechList(mechOid);
+               if (aMech && aMech->mech) {
+                       free(mechOid->elements);
+                       free(mechOid);
+                       continue;
+               }
+
+               /* 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 */
+
+
 #ifdef USE_SOLARIS_SHARED_LIBRARIES
 /* 
  * read the configuration file to find out what mechanisms to
index 3f28c484fca8f49170a0af9102d04c53cd5ff2ea..ec1ace62be14b52941ec951f7a325b64286b1fc7 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
@@ -75,19 +88,19 @@ int *               open;
     ctx = (gss_union_ctx_id_t) context_handle;
     mech = __gss_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);
@@ -100,33 +113,32 @@ int *             open;
 
     if (src_name) {
            status = __gss_convert_name_to_union_name(minor_status, mech,
-                                                     *src_name, src_name);
+                                                     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);
+                                                     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..812fd9dab5e343c1ee5af9ff0b3bfca3358b6c95 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) {
        /*
@@ -68,10 +77,10 @@ gss_OID_set *               mechanisms;
         */
 
        if ((mech = __gss_get_mechanism(GSS_C_NULL_OID)) == NULL)
-           return(GSS_S_NO_CRED);
+           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,
@@ -89,10 +98,12 @@ gss_OID_set *               mechanisms;
                                                      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,6 +213,9 @@ 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);
     if (!mech)
@@ -182,10 +225,31 @@ gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name,
      
     union_cred = (gss_union_cred_t) cred_handle;
     mech_cred = __gss_get_mechanism_cred(union_cred, mech_type);
+    if (mech_cred == NULL)
+       return (GSS_S_DEFECTIVE_CREDENTIAL);
+
+    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 = __gss_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..b1592bd4494e22ef8d04da74a00a549f6cb1841c 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,8 +42,13 @@ 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.
@@ -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
+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 = __gss_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 (__gss_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..a036d87630448b99dfd837746378568c3cfd2487 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
  *
 
 extern gss_mechanism *__gss_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..83687df3e5826026e3ad95ace529a9e129392f5c 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
@@ -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..e289f591c158c1a1ce52cdc17fde0a4c53faea64 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,8 +62,8 @@ 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;
     
@@ -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..ffa678c2624ffd32d9701b477a99f91b526bfa8a 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);
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..c68a6b0312ae691ab0cfb3f9b453f43418d1ffca 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.
@@ -28,7 +28,7 @@
 
 #include "mglueP.h"
 
-OM_uint32 KRB5_CALLCONV
+OM_uint32
 gss_seal (minor_status,
           context_handle,
           conf_req_flag,
@@ -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
@@ -75,15 +84,16 @@ 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
+OM_uint32
 gss_wrap (minor_status,
           context_handle,
           conf_req_flag,
@@ -101,15 +111,16 @@ 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);
 }
 
 /*
  * New for V2
  */
-OM_uint32 KRB5_CALLCONV
+OM_uint32
 gss_wrap_size_limit(minor_status, context_handle, conf_req_flag,
                    qop_req, req_output_size, max_input_size)
     OM_uint32          *minor_status;
@@ -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
@@ -137,13 +152,12 @@ gss_wrap_size_limit(minor_status, context_handle, conf_req_flag,
     mech = __gss_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..f1f883f52fb7e54ef8b29ef5834ff03dff48d393 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,11 +46,21 @@ 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.
@@ -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..7ccbfcd
--- /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 = __gss_get_mechanism(desired_mech);
+               if (mech == NULL)
+                       return (GSS_S_BAD_MECH);
+
+               if (mech->gss_store_cred == NULL)
+                       return (major_status);
+
+               mech_cred = __gss_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 = __gss_get_mechanism(dmech);
+               if (mech == NULL)
+                       continue;
+
+               if (mech->gss_store_cred == NULL)
+                       continue;
+
+               mech_cred = __gss_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..8e975827f6824bb2adbb2113c64ed6cb5c0b55b6 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
@@ -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..eaf376e
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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 <deflt.h>
+#include <mglueP.h>
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_ext.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
+__gss_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 = __gss_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->__gss_userok)
+               major = mech->__gss_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..875e159
--- /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>
+#include <gssapi/gssapi_ext.h>
+#include <synch.h>
+
+#define        Q_DEFAULT               "default"
+#define        BUFLEN                  256
+
+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 __gss_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
+__gss_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
+__gss_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 = __gss_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
+__gss_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 = __gss_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
+__gss_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 = __gss_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
+__gss_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 = __gss_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);
+}
index 7fc86b448b251d671dad297c8572caeb2ced8849..4f24155660cba0c5582884a5f20fc3c6faa61b95 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
@@ -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..036ae904f1be11e78d9bf58215365edc2bb5679c 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,8 +42,6 @@ uid_t * uid;
     int status;
     gss_mechanism      mech;
 
-    gss_initialize();
-
     /*
      * find the appropriate mechanism specific pname_to_uid procedure and
      * call it.
index c9a7d4ee3899b298ca851d56f54d9c32d066129c..20f5ea655a1033efe0424372db768cd0a14495bc 100644 (file)
 
 #include "mechglue.h"
 
+#define        g_OID_equal(o1, o2) \
+       (((o1)->length == (o2)->length) && \
+       (memcmp((o1)->elements, (o2)->elements, (o1)->length) == 0))
+
+#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 +63,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 +74,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 */
@@ -334,16 +360,74 @@ typedef struct gss_config {
                    gss_OID,            /* mech type */
                    uid_t *             /* uid */
                    );
-
+       OM_uint32               (*__gss_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 */
 
+int gssint_mechglue_init(void);
+void gssint_mechglue_fini(void);
+
 gss_mechanism __gss_get_mechanism (gss_OID);
+gss_mechanism_ext __gss_get_mechanism_ext(const gss_OID);
 OM_uint32 __gss_get_mech_type (gss_OID, gss_buffer_t);
+char *__gss_get_kmodName(const gss_OID);
+char *__gss_get_modOptions(const gss_OID);
 OM_uint32 __gss_import_internal_name (OM_uint32 *, gss_OID, gss_union_name_t,
                                      gss_name_t *);
+OM_uint32 __gss_export_internal_name(OM_uint32 *, const gss_OID,
+       const gss_name_t, gss_buffer_t);
 OM_uint32 __gss_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 *);
@@ -359,6 +443,12 @@ gss_cred_id_t __gss_get_mechanism_cred
           gss_OID              /* mech_type */
           );
 
+OM_uint32 __gss_create_copy_buffer(
+       const gss_buffer_t,     /* src buffer */
+       gss_buffer_t *,         /* destination buffer */
+       int                     /* NULL terminate buffer ? */
+);
+
 OM_uint32 generic_gss_release_oid
           (OM_uint32 *,        /* minor_status */
            gss_OID *           /* oid */
@@ -400,6 +490,11 @@ OM_uint32 generic_gss_str_to_oid
            gss_OID *           /* oid */
           );
 
+OM_uint32 gss_copy_oid_set(
+       OM_uint32 *,                    /* minor_status */
+       const gss_OID_set_desc *,       /* oid set */
+       gss_OID_set *                   /* new oid set */
+);
 
 gss_OID gss_find_mechanism_from_name_type (gss_OID); /* name_type */
 
@@ -409,4 +504,62 @@ OM_uint32 gss_add_mech_name_type
            gss_OID             /* mech */
               );
 
+/*
+ * Sun extensions to GSS-API v2
+ */
+
+OM_uint32
+__gss_mech_to_oid(
+       const char *mech,               /* mechanism string name */
+       gss_OID *oid                    /* mechanism oid */
+);
+
+const char *
+__gss_oid_to_mech(
+       const gss_OID oid               /* mechanism oid */
+);
+
+OM_uint32
+__gss_get_mechanisms(
+       char *mechArray[],              /* array to populate with mechs */
+       int arrayLen                    /* length of passed in array */
+);
+
+OM_uint32
+__gss_userok(
+       OM_uint32 *,            /* minor */
+       const gss_name_t,       /* name */
+       const char *,           /* user */
+       int *                   /* user_ok */
+);
+
+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
+get_der_length(
+       unsigned char **,       /* buf */
+       unsigned int,           /* buf_len */
+       unsigned int *          /* bytes */
+);
+
+unsigned int
+der_length_size(unsigned int /* len */);
+
+int
+put_der_length(
+       unsigned int,           /* length */
+       unsigned char **,       /* buf */
+       unsigned int            /* max_len */
+);
+
 #endif /* _GSS_MECHGLUEP_H */
index 8e9da8852c482d26c4aa4b021302c6c1694eed04..e13e6a4f52eaf2c28d71e45773e8d842c6be6d64 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);
@@ -77,6 +90,8 @@ generic_gss_copy_oid(minor_status, oid, new_oid)
 {
        gss_OID         p;
 
+       *minor_status = 0;
+
        p = (gss_OID) malloc(sizeof(gss_OID_desc));
        if (!p) {
                *minor_status = ENOMEM;
@@ -86,7 +101,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 +114,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 {
@@ -120,6 +135,12 @@ generic_gss_add_oid_set_member(minor_status, member_oid, 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) *
@@ -163,9 +184,17 @@ generic_gss_test_oid_set_member(minor_status, member, set, present)
     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 +206,6 @@ generic_gss_test_oid_set_member(minor_status, member, set, present)
        }
     }
     *present = result;
-    *minor_status = 0;
     return(GSS_S_COMPLETE);
 }
 
@@ -191,13 +219,21 @@ generic_gss_oid_to_str(minor_status, oid, oid_str)
     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 */
@@ -211,12 +247,11 @@ generic_gss_oid_to_str(minor_status, oid, oid_str)
     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)) {
+       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) {
@@ -233,7 +268,7 @@ 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];
+       number = (OM_uint32) cp[0];
        sprintf(numstr, "%ld ", number/40);
        strcat(bp, numstr);
        sprintf(numstr, "%ld ", number%40);
@@ -251,7 +286,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;
@@ -272,6 +306,14 @@ 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;
     cp = bp;
@@ -304,12 +346,12 @@ 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++;
     nbytes++;
     while (isdigit(*bp)) {
-       if (sscanf(bp, "%ld", &numbuf) != 1) {
-           *minor_status = EINVAL;
+       if (sscanf(bp, "%d", &numbuf) != 1) {
            return(GSS_S_FAILURE);
        }
        while (numbuf) {
@@ -318,11 +360,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 +372,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(bp, "%d", &numbuf);
            while (isdigit(*bp))
                bp++;
-           while (isspace(*bp))
+           while (isspace(*bp) || *bp == '.')
                bp++;
            onumbuf = 40*numbuf;
-           sscanf(bp, "%ld", &numbuf);
+           (void) sscanf(bp, "%d", &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(bp, "%d", &numbuf);
                nbytes = 0;
                /* Have to fill in the bytes msb-first */
                onumbuf = numbuf;
@@ -369,10 +411,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 +421,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
+gss_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);
+}