in respect of any properties, including, but not limited to, correctness
and fitness for purpose.
+--- The implementations of GSSAPI mechglue in GSSAPI-SPNEGO in
+ src/lib/gssapi, including the following files:
+
+lib/gssapi/generic/gssapi_err_generic.et
+lib/gssapi/mechglue/g_accept_sec_context.c
+lib/gssapi/mechglue/g_acquire_cred.c
+lib/gssapi/mechglue/g_canon_name.c
+lib/gssapi/mechglue/g_compare_name.c
+lib/gssapi/mechglue/g_context_time.c
+lib/gssapi/mechglue/g_delete_sec_context.c
+lib/gssapi/mechglue/g_dsp_name.c
+lib/gssapi/mechglue/g_dsp_status.c
+lib/gssapi/mechglue/g_dup_name.c
+lib/gssapi/mechglue/g_exp_sec_context.c
+lib/gssapi/mechglue/g_export_name.c
+lib/gssapi/mechglue/g_glue.c
+lib/gssapi/mechglue/g_imp_name.c
+lib/gssapi/mechglue/g_imp_sec_context.c
+lib/gssapi/mechglue/g_init_sec_context.c
+lib/gssapi/mechglue/g_initialize.c
+lib/gssapi/mechglue/g_inquire_context.c
+lib/gssapi/mechglue/g_inquire_cred.c
+lib/gssapi/mechglue/g_inquire_names.c
+lib/gssapi/mechglue/g_process_context.c
+lib/gssapi/mechglue/g_rel_buffer.c
+lib/gssapi/mechglue/g_rel_cred.c
+lib/gssapi/mechglue/g_rel_name.c
+lib/gssapi/mechglue/g_rel_oid_set.c
+lib/gssapi/mechglue/g_seal.c
+lib/gssapi/mechglue/g_sign.c
+lib/gssapi/mechglue/g_store_cred.c
+lib/gssapi/mechglue/g_unseal.c
+lib/gssapi/mechglue/g_userok.c
+lib/gssapi/mechglue/g_utils.c
+lib/gssapi/mechglue/g_verify.c
+lib/gssapi/mechglue/gssd_pname_to_uid.c
+lib/gssapi/mechglue/mglueP.h
+lib/gssapi/mechglue/oid_ops.c
+lib/gssapi/spnego/gssapiP_spnego.h
+lib/gssapi/spnego/spnego_mech.c
+
+are subject to the following license:
+
+Copyright (c) 2004 Sun Microsystems, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
Acknowledgements
----------------
+Thanks to Sun Microsystems for donating their implementations of
+mechglue and SPNEGO.
+
Thanks to the members of the Kerberos V5 development team at MIT, both
past and present: Danilo Almeida, Jeffrey Altman, Richard Basch, Jay
Berkenbilt, Mitch Berger, Andrew Boardman, Joe Calzaretta, John Carr,
lib/krb5/keytab lib/krb5/krb lib/krb5/rcache lib/krb5/os
lib/gssapi lib/gssapi/generic lib/gssapi/krb5
+ lib/gssapi/mechglue lib/gssapi/spnego
lib/rpc lib/rpc/unit-test
--- /dev/null
+#ifndef K5_PLUGIN_H_INCLUDED
+#define K5_PLUGIN_H_INCLUDED
+#include <krb5/krb5.h>
+
+enum locate_service_type {
+ locate_service_kdc = 1,
+ locate_service_master_kdc,
+ locate_service_kadmin,
+ locate_service_krb524,
+ locate_service_kpasswd
+};
+
+struct krb5plugin_service_locate_ftable {
+ int vmajor, vminor;
+ /* Per-context setup and teardown. Returned void* blob is
+ private to the plugin. */
+ krb5_error_code (*init)(krb5_context, void **);
+ void (*fini)(void *);
+ /* Callback function returns non-zero if the plugin function
+ should quit and return; this may be because of an error, or may
+ indicate we've already contacted the service, whatever. The
+ lookup function should only return an error if it detects a
+ problem, not if the callback function tells it to quit. */
+ krb5_error_code (*lookup)(void *,
+ enum locate_service_type svc, const char *realm,
+ int socktype, int family,
+ int (*cbfunc)(void *,int,struct sockaddr *),
+ void *cbdata);
+};
+#endif
--- /dev/null
+[ NOTE: MIT has only incorporated the mechglue and spnego change, and
+not the incremental propagation changes. The filenames are different
+between the Sun and MIT sources. The actual MIT filenames appear in
+the top-level README file. Original text of Sun's LICENSE file
+follows. ]
+
+Subject to the license set forth below, Sun Microsystems, Inc. donates
+the attached files to MIT for the purpose of including these
+modifications and additions in future versions of the Kerberos system.
+
+Many of the files attached are subject to licenses issued by other
+entities, including OpenVision, MIT, and FundsXpress. See the
+individual files, and/or related Readme files, for these licenses.
+
+In addition Sun requires that the license set forth below be
+incorporated into any future version of the Kerberos system which
+contains portions of the files attached. The following files must be
+listed, in the top level Readme file, as being provided subject to such
+license:
+
+cmd/krb5/iprop/iprop.x
+cmd/krb5/iprop/iprop_hdr.h
+cmd/krb5/kadmin/server/ipropd_svc.c
+cmd/krb5/kproplog/kproplog.c
+cmd/krb5/slave/kpropd_rpc.c
+lib/gss_mechs/mech_krb5/et/kdb5_err.c
+lib/gss_mechs/mech_spnego/mech/gssapiP_spnego.h
+lib/gss_mechs/mech_spnego/mech/spnego_mech.c
+lib/krb5/kadm5/kadm_host_srv_names.c
+lib/krb5/kdb/kdb_convert.c
+lib/krb5/kdb/kdb_hdr.h
+lib/krb5/kdb/kdb_log.c
+lib/krb5/kdb/kdb_log.h
+lib/libgss/g_accept_sec_context.c
+lib/libgss/g_acquire_cred.c
+lib/libgss/g_canon_name.c
+lib/libgss/g_compare_name.c
+lib/libgss/g_context_time.c
+lib/libgss/g_delete_sec_context.c
+lib/libgss/g_dsp_name.c
+lib/libgss/g_dsp_status.c
+lib/libgss/g_dup_name.c
+lib/libgss/g_exp_sec_context.c
+lib/libgss/g_export_name.c
+lib/libgss/g_glue.c
+lib/libgss/g_imp_name.c
+lib/libgss/g_imp_sec_context.c
+lib/libgss/g_init_sec_context.c
+lib/libgss/g_initialize.c
+lib/libgss/g_inquire_context.c
+lib/libgss/g_inquire_cred.c
+lib/libgss/g_inquire_names.c
+lib/libgss/g_process_context.c
+lib/libgss/g_rel_buffer.c
+lib/libgss/g_rel_cred.c
+lib/libgss/g_rel_name.c
+lib/libgss/g_rel_oid_set.c
+lib/libgss/g_seal.c
+lib/libgss/g_sign.c
+lib/libgss/g_store_cred.c
+lib/libgss/g_unseal.c
+lib/libgss/g_userok.c
+lib/libgss/g_utils.c
+lib/libgss/g_verify.c
+lib/libgss/gssd_pname_to_uid.c
+uts/common/gssapi/include/gssapi_err_generic.h
+uts/common/gssapi/include/mechglueP.h
+
+Sun's License is as follows:
+
+Copyright (c) 2004 Sun Microsystems, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
myfulldir=lib/gssapi
mydir=lib/gssapi
BUILDTOP=$(REL)..$(S)..
-LOCAL_SUBDIRS= generic krb5
+LOCAL_SUBDIRS= generic mechglue krb5 spnego
DEFS=
##DOSLIBNAME=$(OUTPRE)gssapi.lib
##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
LIBMINOR=2
LIBINITFUNC=gssint_lib_init
LIBFINIFUNC=gssint_lib_fini
-STOBJLISTS=OBJS.ST generic/OBJS.ST krb5/OBJS.ST
-SUBDIROBJLISTS=generic/OBJS.ST krb5/OBJS.ST
+STOBJLISTS=OBJS.ST generic/OBJS.ST mechglue/OBJS.ST krb5/OBJS.ST spnego/OBJS.ST
+SUBDIROBJLISTS=generic/OBJS.ST mechglue/OBJS.ST krb5/OBJS.ST
SHLIB_EXPDEPS=\
$(KRB5_DEPLIB) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB) $(COM_ERR_DEPLIB)
-SHLIB_EXPLIBS=-lkrb5 -lk5crypto -lcom_err $(SUPPORT_LIB) $(LIBS)
+SHLIB_EXPLIBS=-lkrb5 -lk5crypto -lcom_err $(SUPPORT_LIB) $(DL_LIB) $(LIBS)
SHLIB_DIRS=-L$(TOPLIBD)
SHLIB_RDIRS=$(KRB5_LIBDIR)
RELDIR=gssapi
$(srcdir)/disp_com_err_status.c \
$(srcdir)/disp_major_status.c \
$(srcdir)/gssapi_generic.c \
- $(srcdir)/oid_ops.c \
$(srcdir)/rel_buffer.c \
$(srcdir)/rel_oid_set.c \
$(srcdir)/util_buffer.c \
- $(srcdir)/util_oid.c \
$(srcdir)/util_ordering.c \
$(srcdir)/util_set.c \
$(srcdir)/util_token.c \
$(OUTPRE)disp_com_err_status.$(OBJEXT) \
$(OUTPRE)disp_major_status.$(OBJEXT) \
$(OUTPRE)gssapi_generic.$(OBJEXT) \
- $(OUTPRE)oid_ops.$(OBJEXT) \
$(OUTPRE)rel_buffer.$(OBJEXT) \
$(OUTPRE)rel_oid_set.$(OBJEXT) \
$(OUTPRE)util_buffer.$(OBJEXT) \
- $(OUTPRE)util_oid.$(OBJEXT) \
$(OUTPRE)util_ordering.$(OBJEXT) \
$(OUTPRE)util_set.$(OBJEXT) \
$(OUTPRE)util_token.$(OBJEXT) \
disp_com_err_status.o \
disp_major_status.o \
gssapi_generic.o \
- oid_ops.o \
rel_buffer.o \
rel_oid_set.o \
util_buffer.o \
- util_oid.o \
util_ordering.o \
util_set.o \
util_token.o \
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
/** helper macros **/
-#define g_OID_equal(o1,o2) \
- (((o1)->length == (o2)->length) && \
- (memcmp((o1)->elements,(o2)->elements,(unsigned int) (o1)->length) == 0))
+#define g_OID_equal(o1, o2) \
+ (((o1)->length == (o2)->length) && \
+ (memcmp((o1)->elements, (o2)->elements, (o1)->length) == 0))
/* this code knows that an int on the wire is 32 bits. The type of
num should be at least this big, or the extra shifts may do weird
#define g_delete_ctx_id gssint_g_delete_ctx_id
#define g_delete_lucidctx_id gssint_g_delete_lucidctx_id
#define g_make_string_buffer gssint_g_make_string_buffer
-#define g_copy_OID_set gssint_g_copy_OID_set
#define g_token_size gssint_g_token_size
#define g_make_token_header gssint_g_make_token_header
#define g_verify_token_header gssint_g_verify_token_header
int g_make_string_buffer (const char *str, gss_buffer_t buffer);
-int g_copy_OID_set (const gss_OID_set_desc * const in, gss_OID_set *out);
-
unsigned int g_token_size (const gss_OID_desc * mech, unsigned int body_size);
void g_make_token_header (const gss_OID_desc * mech, unsigned int body_size,
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
+++ /dev/null
-/*
- * lib/gssapi/generic/oid_ops.c
- *
- * Copyright 1995 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- */
-
-/*
- * oid_ops.c - GSS-API V2 interfaces to manipulate OIDs
- */
-
-#include "gssapiP_generic.h"
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-
-OM_uint32
-generic_gss_release_oid(minor_status, oid)
- OM_uint32 *minor_status;
- gss_OID *oid;
-{
- *minor_status = 0;
-
- if (*oid == GSS_C_NO_OID)
- return(GSS_S_COMPLETE);
-
- /*
- * The V2 API says the following!
- *
- * gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
- * and will silently ignore attempts to free these OIDs; for other OIDs
- * it will call the C free() routine for both the OID data and the
- * descriptor. This allows applications to freely mix their own heap-
- * allocated OID values with OIDs returned by GSS-API.
- */
- if ((*oid != gss_nt_user_name) &&
- (*oid != gss_nt_machine_uid_name) &&
- (*oid != gss_nt_string_uid_name) &&
- (*oid != gss_nt_service_name) &&
- (*oid != gss_nt_exported_name) &&
- (*oid != gss_nt_service_name_v2)) {
- free((*oid)->elements);
- free(*oid);
- }
- *oid = GSS_C_NO_OID;
- return(GSS_S_COMPLETE);
-}
-
-OM_uint32
-generic_gss_copy_oid(minor_status, oid, new_oid)
- OM_uint32 *minor_status;
- const gss_OID_desc * const oid;
- gss_OID *new_oid;
-{
- gss_OID p;
-
- p = (gss_OID) malloc(sizeof(gss_OID_desc));
- if (!p) {
- *minor_status = ENOMEM;
- return GSS_S_FAILURE;
- }
- p->length = oid->length;
- p->elements = malloc(p->length);
- if (!p->elements) {
- free(p);
- *minor_status = ENOMEM;
- return GSS_S_FAILURE;
- }
- memcpy(p->elements, oid->elements, p->length);
- *new_oid = p;
- return(GSS_S_COMPLETE);
-}
-
-
-OM_uint32
-generic_gss_create_empty_oid_set(minor_status, oid_set)
- OM_uint32 *minor_status;
- gss_OID_set *oid_set;
-{
- if ((*oid_set = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)))) {
- memset(*oid_set, 0, sizeof(gss_OID_set_desc));
- *minor_status = 0;
- return(GSS_S_COMPLETE);
- }
- else {
- *minor_status = ENOMEM;
- return(GSS_S_FAILURE);
- }
-}
-
-OM_uint32
-generic_gss_add_oid_set_member(minor_status, member_oid, oid_set)
- OM_uint32 *minor_status;
- const gss_OID_desc * const member_oid;
- gss_OID_set *oid_set;
-{
- gss_OID elist;
- gss_OID lastel;
-
- elist = (*oid_set)->elements;
- /* Get an enlarged copy of the array */
- if (((*oid_set)->elements = (gss_OID) malloc(((*oid_set)->count+1) *
- sizeof(gss_OID_desc)))) {
- /* Copy in the old junk */
- if (elist)
- memcpy((*oid_set)->elements,
- elist,
- ((*oid_set)->count * sizeof(gss_OID_desc)));
-
- /* Duplicate the input element */
- lastel = &(*oid_set)->elements[(*oid_set)->count];
- if ((lastel->elements =
- (void *) malloc((size_t) member_oid->length))) {
- /* Success - copy elements */
- memcpy(lastel->elements, member_oid->elements,
- (size_t) member_oid->length);
- /* Set length */
- lastel->length = member_oid->length;
-
- /* Update count */
- (*oid_set)->count++;
- if (elist)
- free(elist);
- *minor_status = 0;
- return(GSS_S_COMPLETE);
- }
- else
- free((*oid_set)->elements);
- }
- /* Failure - restore old contents of list */
- (*oid_set)->elements = elist;
- *minor_status = ENOMEM;
- return(GSS_S_FAILURE);
-}
-
-OM_uint32
-generic_gss_test_oid_set_member(minor_status, member, set, present)
- OM_uint32 *minor_status;
- const gss_OID_desc * const member;
- gss_OID_set set;
- int *present;
-{
- size_t i;
- int result;
-
- result = 0;
- for (i=0; i<set->count; i++) {
- if ((set->elements[i].length == member->length) &&
- !memcmp(set->elements[i].elements,
- member->elements,
- (size_t) member->length)) {
- result = 1;
- break;
- }
- }
- *present = result;
- *minor_status = 0;
- return(GSS_S_COMPLETE);
-}
-
-/*
- * OID<->string routines. These are uuuuugly.
- */
-OM_uint32
-generic_gss_oid_to_str(minor_status, oid, oid_str)
- OM_uint32 *minor_status;
- const gss_OID_desc * const oid;
- gss_buffer_t oid_str;
-{
- char numstr[128];
- unsigned long number;
- int numshift;
- size_t string_length;
- size_t i;
- unsigned char *cp;
- char *bp;
-
- /* Decoded according to krb5/gssapi_krb5.c */
-
- /* First determine the size of the string */
- string_length = 0;
- number = 0;
- numshift = 0;
- cp = (unsigned char *) oid->elements;
- number = (unsigned long) cp[0];
- sprintf(numstr, "%ld ", number/40);
- string_length += strlen(numstr);
- sprintf(numstr, "%ld ", number%40);
- string_length += strlen(numstr);
- for (i=1; i<oid->length; i++) {
- if ( (size_t) (numshift+7) < (sizeof(unsigned long)*8)) {
- number = (number << 7) | (cp[i] & 0x7f);
- numshift += 7;
- }
- else {
- *minor_status = EINVAL;
- return(GSS_S_FAILURE);
- }
- if ((cp[i] & 0x80) == 0) {
- sprintf(numstr, "%ld ", number);
- string_length += strlen(numstr);
- number = 0;
- numshift = 0;
- }
- }
- /*
- * If we get here, we've calculated the length of "n n n ... n ". Add 4
- * here for "{ " and "}\0".
- */
- string_length += 4;
- if ((bp = (char *) malloc(string_length))) {
- strcpy(bp, "{ ");
- number = (unsigned long) cp[0];
- sprintf(numstr, "%ld ", number/40);
- strcat(bp, numstr);
- sprintf(numstr, "%ld ", number%40);
- strcat(bp, numstr);
- number = 0;
- cp = (unsigned char *) oid->elements;
- for (i=1; i<oid->length; i++) {
- number = (number << 7) | (cp[i] & 0x7f);
- if ((cp[i] & 0x80) == 0) {
- sprintf(numstr, "%ld ", number);
- strcat(bp, numstr);
- number = 0;
- }
- }
- strcat(bp, "}");
- oid_str->length = strlen(bp)+1;
- oid_str->value = (void *) bp;
- *minor_status = 0;
- return(GSS_S_COMPLETE);
- }
- *minor_status = ENOMEM;
- return(GSS_S_FAILURE);
-}
-
-OM_uint32
-generic_gss_str_to_oid(minor_status, oid_str, oid)
- OM_uint32 *minor_status;
- gss_buffer_t oid_str;
- gss_OID *oid;
-{
- char *cp, *bp, *startp;
- int brace;
- long numbuf;
- long onumbuf;
- OM_uint32 nbytes;
- int idx;
- unsigned char *op;
-
- brace = 0;
- bp = (char *) oid_str->value;
- cp = bp;
- /* Skip over leading space */
- while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
- bp++;
- if (*bp == '{') {
- brace = 1;
- bp++;
- }
- while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
- bp++;
- startp = bp;
- nbytes = 0;
-
- /*
- * The first two numbers are chewed up by the first octet.
- */
- if (sscanf(bp, "%ld", &numbuf) != 1) {
- *minor_status = EINVAL;
- return(GSS_S_FAILURE);
- }
- while ((bp < &cp[oid_str->length]) && isdigit((int) *bp))
- bp++;
- while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
- bp++;
- if (sscanf(bp, "%ld", &numbuf) != 1) {
- *minor_status = EINVAL;
- return(GSS_S_FAILURE);
- }
- while ((bp < &cp[oid_str->length]) && isdigit((int) *bp))
- bp++;
- while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
- bp++;
- nbytes++;
- while (isdigit((int) *bp)) {
- if (sscanf(bp, "%ld", &numbuf) != 1) {
- *minor_status = EINVAL;
- return(GSS_S_FAILURE);
- }
- while (numbuf) {
- nbytes++;
- numbuf >>= 7;
- }
- while ((bp < &cp[oid_str->length]) && isdigit((int) *bp))
- bp++;
- while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
- bp++;
- }
- if (brace && (*bp != '}')) {
- *minor_status = EINVAL;
- return(GSS_S_FAILURE);
- }
-
- /*
- * Phew! We've come this far, so the syntax is good.
- */
- if ((*oid = (gss_OID) malloc(sizeof(gss_OID_desc)))) {
- if (((*oid)->elements = (void *) malloc((size_t) nbytes))) {
- (*oid)->length = nbytes;
- op = (unsigned char *) (*oid)->elements;
- bp = startp;
- sscanf(bp, "%ld", &numbuf);
- while (isdigit((int) *bp))
- bp++;
- while (isspace((int) *bp))
- bp++;
- onumbuf = 40*numbuf;
- sscanf(bp, "%ld", &numbuf);
- onumbuf += numbuf;
- *op = (unsigned char) onumbuf;
- op++;
- while (isdigit((int) *bp))
- bp++;
- while (isspace((int) *bp))
- bp++;
- while (isdigit((int) *bp)) {
- sscanf(bp, "%ld", &numbuf);
- nbytes = 0;
- /* Have to fill in the bytes msb-first */
- onumbuf = numbuf;
- while (numbuf) {
- nbytes++;
- numbuf >>= 7;
- }
- numbuf = onumbuf;
- op += nbytes;
- idx = -1;
- while (numbuf) {
- op[idx] = (unsigned char) numbuf & 0x7f;
- if (idx != -1)
- op[idx] |= 0x80;
- idx--;
- numbuf >>= 7;
- }
- while (isdigit((int) *bp))
- bp++;
- while (isspace((int) *bp))
- bp++;
- }
- *minor_status = 0;
- return(GSS_S_COMPLETE);
- }
- else {
- free(*oid);
- *oid = GSS_C_NO_OID;
- }
- }
- *minor_status = ENOMEM;
- return(GSS_S_FAILURE);
-}
-
+++ /dev/null
-/*
- * Copyright 1993 by OpenVision Technologies, Inc.
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without fee,
- * provided that the above copyright notice appears in all copies and
- * that both that copyright notice and this permission notice appear in
- * supporting documentation, and that the name of OpenVision not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. OpenVision makes no
- * representations about the suitability of this software for any
- * purpose. It is provided "as is" without express or implied warranty.
- *
- * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
- * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "gssapiP_generic.h"
-#include "string.h"
-
-/*
- * $Id$
- */
-
-int
-g_copy_OID_set(in, out)
- const gss_OID_set_desc * const in;
- gss_OID_set *out;
-{
- gss_OID_set copy;
- gss_OID new_oid;
- size_t i;
- size_t len;
-
- *out = NULL;
-
- if ((copy =
- (gss_OID_set_desc *) xmalloc(sizeof(gss_OID_set_desc))) == NULL)
- return(0);
-
- copy->count = in->count;
- len = sizeof(gss_OID_desc) * copy->count;
-
- if ((copy->elements =
- (gss_OID_desc *) xmalloc( len )) == NULL) {
- xfree(copy);
- return(0);
- }
-
- memset( copy->elements, 0, len );
-
- for (i=0; i<in->count; i++) {
- len = in->elements[i].length;
- new_oid = &(copy->elements[i]);
- new_oid->elements = xmalloc( len );
- if ( new_oid->elements == NULL ) {
- while( i>0 ) {
- i--;
- new_oid = &(copy->elements[i]);
- if ( new_oid->elements!=NULL )
- xfree( new_oid->elements );
- }
- xfree( copy->elements );
- xfree( copy );
- return( 0 );
- }
- memcpy( new_oid->elements, in->elements[i].elements, len );
- new_oid->length = len;
- }
-
- *out = copy;
- return(1);
-}
#include "gss_libinit.h"
#include "k5-platform.h"
+#include "mglueP.h"
+
/*
* Initialize the GSSAPI library.
*/
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;
k5_mutex_destroy(&kg_vdb.mutex);
k5_mutex_destroy(&kg_kdc_flag_mutex);
k5_mutex_destroy(&gssint_krb5_keytab_lock);
+ gssint_mechglue_fini();
}
OM_uint32 gssint_initialize_library (void)
myfulldir=lib/gssapi/krb5
mydir=lib/gssapi/krb5
BUILDTOP=$(REL)..$(S)..$(S)..
-LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic
+LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic -I../mechglue -I$(srcdir)/../mechglue
DEFS=
##DOS##BUILDTOP = ..\..\..
&ptr, KG_TOK_CTX_AP_REQ,
input_token->length, 1))) {
mech_used = gss_mech_krb5;
+ } else if ((code == G_WRONG_MECH)
+ &&!(code = g_verify_token_header((gss_OID) gss_mech_krb5_wrong,
+ &(ap_req.length),
+ &ptr, KG_TOK_CTX_AP_REQ,
+ input_token->length, 1))) {
+ mech_used = gss_mech_krb5_wrong;
} else if ((code == G_WRONG_MECH) &&
!(code = g_verify_token_header(gss_mech_krb5_old,
&(ap_req.length),
#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;
*/
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;
/** constants **/
+#define GSS_MECH_KRB5_OID_LENGTH 9
+#define GSS_MECH_KRB5_OID "\052\206\110\206\367\022\001\002\002"
+
+#define GSS_MECH_KRB5_OLD_OID_LENGTH 5
+#define GSS_MECH_KRB5_OLD_OID "\053\005\001\005\002"
+
+/* Incorrect krb5 mech OID emitted by MS. */
+#define GSS_MECH_KRB5_WRONG_OID_LENGTH 9
+#define GSS_MECH_KRB5_WRONG_OID "\052\206\110\202\367\022\001\002\002"
+
+
#define CKSUMTYPE_KG_CB 0x8003
#define KG_TOK_CTX_AP_REQ 0x0100
krb5_error_code krb5_gss_ser_init(krb5_context);
-OM_uint32 krb5_gss_release_oid
+OM_uint32 krb5_gss_internal_release_oid
(OM_uint32 *, /* minor_status */
gss_OID * /* oid */
);
int *conf_state, int *qop_state,
int toktype);
+/*
+ * These take unglued krb5-mech-specific contexts.
+ */
+
+OM_uint32 KRB5_CALLCONV gss_krb5int_get_tkt_flags
+ (OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ krb5_flags *ticket_flags);
+
+OM_uint32 KRB5_CALLCONV gss_krb5int_copy_ccache
+ (OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ krb5_ccache out_ccache);
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5int_set_allowable_enctypes(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ OM_uint32 num_ktypes,
+ krb5_enctype *ktypes);
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5int_export_lucid_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ OM_uint32 version,
+ void **kctx);
+
+
extern k5_mutex_t kg_kdc_flag_mutex;
krb5_error_code krb5_gss_init_context (krb5_context *ctxp);
const gss_OID_desc krb5_gss_oid_array[] = {
/* this is the official, rfc-specified OID */
- {9, "\052\206\110\206\367\022\001\002\002"},
- /* this is the unofficial, wrong OID */
- {5, "\053\005\001\005\002"},
+ {GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID},
+ /* this pre-RFC mech OID */
+ {GSS_MECH_KRB5_OLD_OID_LENGTH, GSS_MECH_KRB5_OLD_OID},
+ /* this is the unofficial, incorrect mech OID emitted by MS */
+ {GSS_MECH_KRB5_WRONG_OID_LENGTH, GSS_MECH_KRB5_WRONG_OID},
/* this is the v2 assigned OID */
{9, "\052\206\110\206\367\022\001\002\003"},
/* these two are name type OID's */
const gss_OID_desc * const gss_mech_krb5 = krb5_gss_oid_array+0;
const gss_OID_desc * const gss_mech_krb5_old = krb5_gss_oid_array+1;
-const gss_OID_desc * const gss_nt_krb5_name = krb5_gss_oid_array+3;
-const gss_OID_desc * const gss_nt_krb5_principal = krb5_gss_oid_array+4;
-const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME = krb5_gss_oid_array+3;
+const gss_OID_desc * const gss_mech_krb5_wrong = krb5_gss_oid_array+2;
+const gss_OID_desc * const gss_nt_krb5_name = krb5_gss_oid_array+4;
+const gss_OID_desc * const gss_nt_krb5_principal = krb5_gss_oid_array+5;
+const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME = krb5_gss_oid_array+4;
static const gss_OID_set_desc oidsets[] = {
{1, (gss_OID) krb5_gss_oid_array+0},
{1, (gss_OID) krb5_gss_oid_array+1},
- {2, (gss_OID) krb5_gss_oid_array+0},
+ {3, (gss_OID) krb5_gss_oid_array+0},
{1, (gss_OID) krb5_gss_oid_array+2},
{3, (gss_OID) krb5_gss_oid_array+0},
};
GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5;
GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5_old;
+GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5_wrong;
GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5;
GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5_old;
GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5_both;
*/
#include "gssapiP_krb5.h"
+#include "mglueP.h"
OM_uint32
krb5_gss_indicate_mechs(minor_status, mech_set)
{
*minor_status = 0;
- if (! g_copy_OID_set(gss_mech_set_krb5_both, mech_set)) {
+ if (! gssint_copy_oid_set(minor_status, gss_mech_set_krb5_both, mech_set)) {
*mech_set = GSS_C_NO_OID_SET;
*minor_status = ENOMEM;
return(GSS_S_FAILURE);
} else if (g_OID_equal(mech_type, gss_mech_krb5_old)) {
if (!cred->prerfc_mech)
err = 1;
+ } else if (g_OID_equal(mech_type, gss_mech_krb5_wrong)) {
+ if (!cred->rfc_mech)
+ err = 1;
} else {
err = 1;
}
*/
#include "gssapiP_krb5.h"
+#include "mglueP.h"
-OM_uint32 KRB5_CALLCONV
-gss_accept_sec_context(minor_status, context_handle, verifier_cred_handle,
+/** mechglue wrappers **/
+
+static OM_uint32 k5glue_acquire_cred
+(void *, OM_uint32*, /* minor_status */
+ gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t*, /* output_cred_handle */
+ gss_OID_set*, /* actual_mechs */
+ OM_uint32* /* time_rec */
+ );
+
+static OM_uint32 k5glue_release_cred
+(void *, OM_uint32*, /* minor_status */
+ gss_cred_id_t* /* cred_handle */
+ );
+
+static OM_uint32 k5glue_init_sec_context
+(void *, OM_uint32*, /* minor_status */
+ gss_cred_id_t, /* claimant_cred_handle */
+ gss_ctx_id_t*, /* context_handle */
+ gss_name_t, /* target_name */
+ gss_OID, /* mech_type */
+ OM_uint32, /* req_flags */
+ OM_uint32, /* time_req */
+ gss_channel_bindings_t,
+ /* input_chan_bindings */
+ gss_buffer_t, /* input_token */
+ gss_OID*, /* actual_mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32* /* time_rec */
+ );
+
+static OM_uint32 k5glue_accept_sec_context
+(void *, OM_uint32*, /* minor_status */
+ gss_ctx_id_t*, /* context_handle */
+ gss_cred_id_t, /* verifier_cred_handle */
+ gss_buffer_t, /* input_token_buffer */
+ gss_channel_bindings_t,
+ /* input_chan_bindings */
+ gss_name_t*, /* src_name */
+ gss_OID*, /* mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32*, /* time_rec */
+ gss_cred_id_t* /* delegated_cred_handle */
+ );
+
+static OM_uint32 k5glue_process_context_token
+(void *, OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t /* token_buffer */
+ );
+
+static OM_uint32 k5glue_delete_sec_context
+(void *, OM_uint32*, /* minor_status */
+ gss_ctx_id_t*, /* context_handle */
+ gss_buffer_t /* output_token */
+ );
+
+static OM_uint32 k5glue_context_time
+(void *, OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ OM_uint32* /* time_rec */
+ );
+
+static OM_uint32 k5glue_sign
+(void *, OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* qop_req */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t /* message_token */
+ );
+
+static OM_uint32 k5glue_verify
+(void *, OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t, /* token_buffer */
+ int* /* qop_state */
+ );
+
+static OM_uint32 k5glue_seal
+(void *, OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ int, /* qop_req */
+ gss_buffer_t, /* input_message_buffer */
+ int*, /* conf_state */
+ gss_buffer_t /* output_message_buffer */
+ );
+
+static OM_uint32 k5glue_unseal
+(void *, OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* input_message_buffer */
+ gss_buffer_t, /* output_message_buffer */
+ int*, /* conf_state */
+ int* /* qop_state */
+ );
+
+static OM_uint32 k5glue_display_status
+(void *, OM_uint32*, /* minor_status */
+ OM_uint32, /* status_value */
+ int, /* status_type */
+ gss_OID, /* mech_type */
+ OM_uint32*, /* message_context */
+ gss_buffer_t /* status_string */
+ );
+
+static OM_uint32 k5glue_indicate_mechs
+(void *, OM_uint32*, /* minor_status */
+ gss_OID_set* /* mech_set */
+ );
+
+static OM_uint32 k5glue_compare_name
+(void *, OM_uint32*, /* minor_status */
+ gss_name_t, /* name1 */
+ gss_name_t, /* name2 */
+ int* /* name_equal */
+ );
+
+static OM_uint32 k5glue_display_name
+(void *, OM_uint32*, /* minor_status */
+ gss_name_t, /* input_name */
+ gss_buffer_t, /* output_name_buffer */
+ gss_OID* /* output_name_type */
+ );
+
+static OM_uint32 k5glue_import_name
+(void *, OM_uint32*, /* minor_status */
+ gss_buffer_t, /* input_name_buffer */
+ gss_OID, /* input_name_type */
+ gss_name_t* /* output_name */
+ );
+
+static OM_uint32 k5glue_release_name
+(void *, OM_uint32*, /* minor_status */
+ gss_name_t* /* input_name */
+ );
+
+static OM_uint32 k5glue_inquire_cred
+(void *, OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* lifetime */
+ gss_cred_usage_t*,/* cred_usage */
+ gss_OID_set * /* mechanisms */
+ );
+
+static OM_uint32 k5glue_inquire_context
+(void *, OM_uint32*, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_name_t*, /* initiator_name */
+ gss_name_t*, /* acceptor_name */
+ OM_uint32*, /* lifetime_rec */
+ gss_OID*, /* mech_type */
+ OM_uint32*, /* ret_flags */
+ int*, /* locally_initiated */
+ int* /* open */
+ );
+
+#if 0
+/* New V2 entry points */
+static OM_uint32 k5glue_get_mic
+(void *, OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t /* message_token */
+ );
+
+static OM_uint32 k5glue_verify_mic
+(void *, OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* message_buffer */
+ gss_buffer_t, /* message_token */
+ gss_qop_t * /* qop_state */
+ );
+
+static OM_uint32 k5glue_wrap
+(void *, OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ gss_buffer_t, /* input_message_buffer */
+ int *, /* conf_state */
+ gss_buffer_t /* output_message_buffer */
+ );
+
+static OM_uint32 k5glue_unwrap
+(void *, OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ gss_buffer_t, /* input_message_buffer */
+ gss_buffer_t, /* output_message_buffer */
+ int *, /* conf_state */
+ gss_qop_t * /* qop_state */
+ );
+#endif
+
+static OM_uint32 k5glue_wrap_size_limit
+(void *, OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ OM_uint32, /* req_output_size */
+ OM_uint32 * /* max_input_size */
+ );
+
+#if 0
+static OM_uint32 k5glue_import_name_object
+(void *, OM_uint32 *, /* minor_status */
+ void *, /* input_name */
+ gss_OID, /* input_name_type */
+ gss_name_t * /* output_name */
+ );
+
+static OM_uint32 k5glue_export_name_object
+(void *, OM_uint32 *, /* minor_status */
+ gss_name_t, /* input_name */
+ gss_OID, /* desired_name_type */
+ void * * /* output_name */
+ );
+#endif
+
+static OM_uint32 k5glue_add_cred
+(void *, OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ gss_name_t, /* desired_name */
+ gss_OID, /* desired_mech */
+ gss_cred_usage_t, /* cred_usage */
+ OM_uint32, /* initiator_time_req */
+ OM_uint32, /* acceptor_time_req */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *, /* initiator_time_rec */
+ OM_uint32 * /* acceptor_time_rec */
+ );
+
+static OM_uint32 k5glue_inquire_cred_by_mech
+(void *, OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_OID, /* mech_type */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* initiator_lifetime */
+ OM_uint32 *, /* acceptor_lifetime */
+ gss_cred_usage_t * /* cred_usage */
+ );
+
+static OM_uint32 k5glue_export_sec_context
+(void *, OM_uint32 *, /* minor_status */
+ gss_ctx_id_t *, /* context_handle */
+ gss_buffer_t /* interprocess_token */
+ );
+
+static OM_uint32 k5glue_import_sec_context
+(void *, OM_uint32 *, /* minor_status */
+ gss_buffer_t, /* interprocess_token */
+ gss_ctx_id_t * /* context_handle */
+ );
+
+krb5_error_code k5glue_ser_init(krb5_context);
+
+static OM_uint32 k5glue_internal_release_oid
+(void *, OM_uint32 *, /* minor_status */
+ gss_OID * /* oid */
+ );
+
+static OM_uint32 k5glue_inquire_names_for_mech
+(void *, OM_uint32 *, /* minor_status */
+ gss_OID, /* mechanism */
+ gss_OID_set * /* name_types */
+ );
+
+#if 0
+static OM_uint32 k5glue_canonicalize_name
+(void *, OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ const gss_OID, /* mech_type */
+ gss_name_t * /* output_name */
+ );
+#endif
+
+static OM_uint32 k5glue_export_name
+(void *, OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_buffer_t /* exported_name */
+ );
+
+#if 0
+static OM_uint32 k5glue_duplicate_name
+(void *, OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_name_t * /* dest_name */
+ );
+#endif
+
+#if 0
+static OM_uint32 k5glue_validate_cred
+(void *, OM_uint32 *, /* minor_status */
+ gss_cred_id_t /* cred */
+ );
+#endif
+
+/*
+ * The krb5 mechanism provides two mech OIDs; use this initializer to
+ * ensure that both dispatch tables contain identical function
+ * pointers.
+ */
+#define KRB5_GSS_CONFIG_INIT \
+ NULL, \
+ k5glue_acquire_cred, \
+ k5glue_release_cred, \
+ k5glue_init_sec_context, \
+ k5glue_accept_sec_context, \
+ k5glue_process_context_token, \
+ k5glue_delete_sec_context, \
+ k5glue_context_time, \
+ k5glue_sign, \
+ k5glue_verify, \
+ k5glue_seal, \
+ k5glue_unseal, \
+ k5glue_display_status, \
+ k5glue_indicate_mechs, \
+ k5glue_compare_name, \
+ k5glue_display_name, \
+ k5glue_import_name, \
+ k5glue_release_name, \
+ k5glue_inquire_cred, \
+ k5glue_add_cred, \
+ k5glue_export_sec_context, \
+ k5glue_import_sec_context, \
+ k5glue_inquire_cred_by_mech, \
+ k5glue_inquire_names_for_mech, \
+ k5glue_inquire_context, \
+ k5glue_internal_release_oid, \
+ k5glue_wrap_size_limit, \
+ NULL, /* pname_to_uid */ \
+ NULL, /* userok */ \
+ k5glue_export_name, \
+ NULL /* store_cred */
+
+static struct gss_config krb5_mechanism = {
+ 100, "kerberos_v5",
+ { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
+ KRB5_GSS_CONFIG_INIT
+};
+
+static struct gss_config krb5_mechanism_old = {
+ 200, "kerberos_v5 (pre-RFC OID)",
+ { GSS_MECH_KRB5_OLD_OID_LENGTH, GSS_MECH_KRB5_OLD_OID },
+ KRB5_GSS_CONFIG_INIT
+};
+
+static struct gss_config krb5_mechanism_wrong = {
+ 300, "kerberos_v5 (wrong OID)",
+ { GSS_MECH_KRB5_WRONG_OID_LENGTH, GSS_MECH_KRB5_WRONG_OID },
+ KRB5_GSS_CONFIG_INIT
+};
+
+static gss_mechanism krb5_mech_configs[] = {
+ &krb5_mechanism, &krb5_mechanism_old, &krb5_mechanism_wrong, NULL
+};
+
+#ifdef MS_BUG_TEST
+static gss_mechanism krb5_mech_configs_hack[] = {
+ &krb5_mechanism, &krb5_mechanism_old, NULL
+}
+#endif
+
+#if 1
+#define gssint_get_mech_configs krb5_gss_get_mech_configs
+#endif
+
+gss_mechanism *
+gssint_get_mech_configs(void)
+{
+#ifdef MS_BUG_TEST
+ char *envstr = getenv("MS_FORCE_NO_MSOID");
+
+ if (envstr != NULL && strcmp(envstr, "1") == 0) {
+ return krb5_mech_configs_hack;
+ }
+#endif
+ return krb5_mech_configs;
+}
+
+static OM_uint32
+k5glue_accept_sec_context(ctx, minor_status, context_handle, verifier_cred_handle,
input_token, input_chan_bindings, src_name, mech_type,
output_token, ret_flags, time_rec, delegated_cred_handle)
+ void *ctx;
OM_uint32 *minor_status;
gss_ctx_id_t *context_handle;
gss_cred_id_t verifier_cred_handle;
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;
}
/* 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;
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;
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;
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;
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;
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;
}
/* 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;
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;
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;
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;
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;
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;
}
/* 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;
}
/* 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;
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;
context_handle, token_buffer));
}
-OM_uint32 KRB5_CALLCONV
-gss_release_cred(minor_status, cred_handle)
+static OM_uint32
+k5glue_release_cred(ctx, minor_status, cred_handle)
+ void *ctx;
OM_uint32 *minor_status;
gss_cred_id_t *cred_handle;
{
return(krb5_gss_release_cred(minor_status, cred_handle));
}
-OM_uint32 KRB5_CALLCONV
-gss_release_name(minor_status, input_name)
+static OM_uint32
+k5glue_release_name(ctx, minor_status, input_name)
+ void *ctx;
OM_uint32 *minor_status;
gss_name_t *input_name;
{
return(krb5_gss_release_name(minor_status, input_name));
}
-OM_uint32 KRB5_CALLCONV
-gss_release_buffer(minor_status, buffer)
+#if 0
+static OM_uint32
+k5glue_release_buffer(ctx, minor_status, buffer)
+ void *ctx;
OM_uint32 *minor_status;
gss_buffer_t buffer;
{
return(generic_gss_release_buffer(minor_status,
buffer));
}
+#endif
/* V2 */
-OM_uint32 KRB5_CALLCONV
-gss_release_oid(minor_status, oid)
+static OM_uint32
+k5glue_internal_release_oid(ctx, minor_status, oid)
+ void *ctx;
OM_uint32 *minor_status;
gss_OID *oid;
{
- return(krb5_gss_release_oid(minor_status, oid));
+ return(krb5_gss_internal_release_oid(minor_status, oid));
}
-OM_uint32 KRB5_CALLCONV
-gss_release_oid_set(minor_status, set)
+#if 0
+static OM_uint32
+k5glue_release_oid_set(ctx, minor_status, set)
+ void *ctx;
OM_uint32 * minor_status;
gss_OID_set *set;
{
return(generic_gss_release_oid_set(minor_status, set));
}
+#endif
/* V1 only */
-OM_uint32 KRB5_CALLCONV
-gss_seal(minor_status, context_handle, conf_req_flag, qop_req,
+static OM_uint32
+k5glue_seal(ctx, minor_status, context_handle, conf_req_flag, qop_req,
input_message_buffer, conf_state, output_message_buffer)
+ void *ctx;
OM_uint32 *minor_status;
gss_ctx_id_t context_handle;
int conf_req_flag;
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;
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;
}
/* 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;
}
/* 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;
}
/* 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;
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;
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;
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;
}
/* 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;
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;
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;
return krb5_gss_export_name(minor_status, input_name, exported_name);
}
+#if 0
/* V2 interface */
-OM_uint32 KRB5_CALLCONV
-gss_duplicate_name(minor_status, input_name, dest_name)
+static OM_uint32
+k5glue_duplicate_name(ctx, minor_status, input_name, dest_name)
+ void *ctx;
OM_uint32 *minor_status;
const gss_name_t input_name;
gss_name_t *dest_name;
{
return krb5_gss_duplicate_name(minor_status, input_name, dest_name);
}
+#endif
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_get_tkt_flags(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ krb5_flags *ticket_flags)
+{
+ gss_union_ctx_id_t uctx;
+
+ uctx = (gss_union_ctx_id_t)context_handle;
+ if (!g_OID_equal(uctx->mech_type, &krb5_mechanism.mech_type) &&
+ !g_OID_equal(uctx->mech_type, &krb5_mechanism_old.mech_type))
+ return GSS_S_BAD_MECH;
+ return gss_krb5int_get_tkt_flags(minor_status, uctx->internal_ctx_id,
+ ticket_flags);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_copy_ccache(
+ OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ krb5_ccache out_ccache)
+{
+ gss_union_cred_t ucred;
+ gss_cred_id_t mcred;
+
+ ucred = (gss_union_cred_t)cred_handle;
+
+ mcred = gssint_get_mechanism_cred(ucred, &krb5_mechanism.mech_type);
+ if (mcred != GSS_C_NO_CREDENTIAL)
+ return gss_krb5int_copy_ccache(minor_status, mcred, out_ccache);
+
+ mcred = gssint_get_mechanism_cred(ucred, &krb5_mechanism_old.mech_type);
+ if (mcred != GSS_C_NO_CREDENTIAL)
+ return gss_krb5int_copy_ccache(minor_status, mcred, out_ccache);
+
+ return GSS_S_DEFECTIVE_CREDENTIAL;
+}
+
+/* XXX need to delete mechglue ctx too */
+OM_uint32 KRB5_CALLCONV
+gss_krb5_export_lucid_sec_context(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ OM_uint32 version,
+ void **kctx)
+{
+ gss_union_ctx_id_t uctx;
+
+ uctx = (gss_union_ctx_id_t)*context_handle;
+ if (!g_OID_equal(uctx->mech_type, &krb5_mechanism.mech_type) &&
+ !g_OID_equal(uctx->mech_type, &krb5_mechanism_old.mech_type))
+ return GSS_S_BAD_MECH;
+ return gss_krb5int_export_lucid_sec_context(minor_status,
+ &uctx->internal_ctx_id,
+ version, kctx);
+}
+OM_uint32 KRB5_CALLCONV
+gss_krb5_set_allowable_enctypes(
+ OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ OM_uint32 num_ktypes,
+ krb5_enctype *ktypes)
+{
+ gss_union_cred_t ucred;
+ gss_cred_id_t mcred;
+
+ ucred = (gss_union_cred_t)cred;
+ mcred = gssint_get_mechanism_cred(ucred, &krb5_mechanism.mech_type);
+ if (mcred != GSS_C_NO_CREDENTIAL)
+ return gss_krb5int_set_allowable_enctypes(minor_status, mcred,
+ num_ktypes, ktypes);
+ mcred = gssint_get_mechanism_cred(ucred, &krb5_mechanism_old.mech_type);
+ if (mcred != GSS_C_NO_CREDENTIAL)
+ return gss_krb5int_set_allowable_enctypes(minor_status, mcred,
+ num_ktypes, ktypes);
+ return GSS_S_DEFECTIVE_CREDENTIAL;
+}
*/
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,
*/
#include "gssapiP_krb5.h"
-static OM_uint32 krb5_gss_internal_release_oid (OM_uint32 *, /* minor_status */
- gss_OID * /* oid */
+OM_uint32 krb5_gss_internal_release_oid (OM_uint32 *, /* minor_status */
+ gss_OID * /* oid */
);
+#if 0
OM_uint32
krb5_gss_release_oid(minor_status, oid)
OM_uint32 *minor_status;
return(GSS_S_COMPLETE);
}
}
+#endif
-static OM_uint32
+OM_uint32
krb5_gss_internal_release_oid(minor_status, oid)
OM_uint32 *minor_status;
gss_OID *oid;
if ((*oid != gss_mech_krb5) &&
(*oid != gss_mech_krb5_old) &&
+ (*oid != gss_mech_krb5_wrong) &&
(*oid != gss_nt_krb5_name) &&
(*oid != gss_nt_krb5_principal)) {
/* We don't know about this OID */
#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;
-thisconfigdir=..
+thisconfigdir=../../..
myfulldir=lib/gssapi/mechglue
-mydir=.
+mydir=mechglue
BUILDTOP=$(REL)..$(S)..$(S)..
-LOCALINCLUDES = -I. -I$(srcdir)
+LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic
DEFS=
##DOSBUILDTOP = ..\..\..
##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::
done
includes::
+
+# @libobj_frag@
-/* #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.
output_token,
ret_flags,
time_rec,
- delegated_cred_handle)
+ d_cred)
OM_uint32 * minor_status;
gss_ctx_id_t * context_handle;
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
if(*context_handle == GSS_C_NO_CONTEXT) {
+ if (GSS_EMPTY_BUFFER(input_token_buffer))
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
/* Get the token mech type */
- status = __gss_get_mech_type(token_mech_type, input_token_buffer);
+ status = gssint_get_mech_type(token_mech_type, input_token_buffer);
if (status)
return status;
status = GSS_S_FAILURE;
union_ctx_id = (gss_union_ctx_id_t)
malloc(sizeof(gss_union_ctx_id_desc));
- if (!union_ctx_id) {
- *minor_status = ENOMEM;
- goto error_out;
- }
+ if (!union_ctx_id)
+ return (GSS_S_FAILURE);
- union_ctx_id->mech_type = (gss_OID) malloc(sizeof(gss_OID_desc));
- if (!union_ctx_id->mech_type) {
- *minor_status = ENOMEM;
- goto error_out;
+ union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT;
+ status = generic_gss_copy_oid(&temp_minor_status,
+ token_mech_type,
+ &union_ctx_id->mech_type);
+ if (status != GSS_S_COMPLETE) {
+ free(union_ctx_id);
+ return (status);
}
-
- union_ctx_id->mech_type->elements = (void *)
- malloc(token_mech_type->length);
- if (!union_ctx_id->mech_type->elements) {
- *minor_status = ENOMEM;
- goto error_out;
- }
-
- union_ctx_id->mech_type->length = token_mech_type->length;
- memcpy(union_ctx_id->mech_type->elements,
- token_mech_type->elements,
- token_mech_type->length);
- /* copy the supplied context handle */
-
- union_ctx_id->internal_ctx_id = *context_handle;
+ /* set the new context handle to caller's data */
+ *context_handle = (gss_ctx_id_t)union_ctx_id;
} else {
- union_ctx_id = *context_handle;
+ union_ctx_id = (gss_union_ctx_id_t)*context_handle;
token_mech_type = union_ctx_id->mech_type;
}
* use the default credential.
*/
union_cred = (gss_union_cred_t) verifier_cred_handle;
- input_cred_handle = __gss_get_mechanism_cred(union_cred, token_mech_type);
+ input_cred_handle = gssint_get_mechanism_cred(union_cred, token_mech_type);
/*
* now select the approprate underlying mechanism routine and
* call it.
*/
- mech = __gss_get_mechanism (token_mech_type);
+ mech = gssint_get_mechanism (token_mech_type);
if (mech && mech->gss_accept_sec_context) {
status = mech->gss_accept_sec_context(
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)
* then call gss_import_name() to create
* the union name struct cast to src_name
*/
- if (src_name != NULL && status == GSS_S_COMPLETE) {
- temp_status = __gss_convert_name_to_union_name(
- &temp_minor_status, mech, internal_name, src_name);
+ if (internal_name != NULL) {
+ temp_status = gssint_convert_name_to_union_name(
+ &temp_minor_status, mech,
+ internal_name, &tmp_src_name);
if (temp_status != GSS_S_COMPLETE) {
- if (minor_status)
- *minor_status = temp_minor_status;
- gss_release_buffer(&temp_minor_status, output_token);
- __gss_release_internal_name(&temp_minor_status,
- &mech->mech_type, &internal_name);
+ *minor_status = temp_minor_status;
+ if (output_token->length)
+ (void) gss_release_buffer(&temp_minor_status,
+ output_token);
+ if (internal_name != GSS_C_NO_NAME)
+ mech->gss_release_name(
+ mech->context,
+ &temp_minor_status,
+ &internal_name);
return (temp_status);
}
+ if (src_name != NULL) {
+ *src_name = tmp_src_name;
+ }
+ } else if (src_name != NULL) {
+ *src_name = GSS_C_NO_NAME;
+ }
+
+ /* Ensure we're returning correct creds format */
+ if ((ret_flags && GSS_C_DELEG_FLAG) &&
+ tmp_d_cred != GSS_C_NO_CREDENTIAL) {
+ gss_union_cred_t d_u_cred = NULL;
+
+ d_u_cred = malloc(sizeof (gss_union_cred_desc));
+ if (d_u_cred == NULL) {
+ status = GSS_S_FAILURE;
+ goto error_out;
+ }
+ (void) memset(d_u_cred, 0,
+ sizeof (gss_union_cred_desc));
+
+ d_u_cred->count = 1;
+
+ status = generic_gss_copy_oid(&temp_minor_status,
+ token_mech_type,
+ &d_u_cred->mechs_array);
+
+ if (status != GSS_S_COMPLETE) {
+ free(d_u_cred);
+ goto error_out;
+ }
+
+ d_u_cred->cred_array = malloc(sizeof (gss_cred_id_t));
+ if (d_u_cred->cred_array != NULL) {
+ d_u_cred->cred_array[0] = tmp_d_cred;
+ } else {
+ free(d_u_cred);
+ status = GSS_S_FAILURE;
+ goto error_out;
+ }
+
+ if (status != GSS_S_COMPLETE) {
+ free(d_u_cred->cred_array);
+ free(d_u_cred);
+ goto error_out;
+ }
+
+ internal_name = GSS_C_NO_NAME;
+
+ d_u_cred->auxinfo.creation_time = time(0);
+ d_u_cred->auxinfo.time_rec = 0;
+
+ if (mech->gss_inquire_cred) {
+ status = mech->gss_inquire_cred(mech->context,
+ minor_status,
+ tmp_d_cred,
+ &internal_name,
+ &d_u_cred->auxinfo.time_rec,
+ &d_u_cred->auxinfo.cred_usage,
+ NULL);
+ }
+
+ if (internal_name != NULL) {
+ temp_status = gssint_convert_name_to_union_name(
+ &temp_minor_status, mech,
+ internal_name, &tmp_src_name);
+ if (temp_status != GSS_S_COMPLETE) {
+ *minor_status = temp_minor_status;
+ if (output_token->length)
+ (void) gss_release_buffer(
+ &temp_minor_status,
+ output_token);
+ free(d_u_cred->cred_array);
+ free(d_u_cred);
+ return (temp_status);
+ }
+ }
+
+ if (tmp_src_name != NULL) {
+ status = gss_display_name(
+ &temp_minor_status,
+ tmp_src_name,
+ &d_u_cred->auxinfo.name,
+ &d_u_cred->auxinfo.name_type);
+ }
+
+ *d_cred = (gss_cred_id_t)d_u_cred;
}
- if(*context_handle == GSS_C_NO_CONTEXT)
- *context_handle = (gss_ctx_id_t *) union_ctx_id;
+ if (src_name == NULL && tmp_src_name != NULL)
+ (void) gss_release_name(&temp_minor_status,
+ &tmp_src_name);
+ return (status);
+ } else {
- return(status);
+ status = GSS_S_BAD_MECH;
}
- return(GSS_S_BAD_MECH);
-
error_out:
if (union_ctx_id) {
if (union_ctx_id->mech_type) {
if (union_ctx_id->mech_type->elements)
free(union_ctx_id->mech_type->elements);
free(union_ctx_id->mech_type);
+ *context_handle = GSS_C_NO_CONTEXT;
}
free(union_ctx_id);
}
+
+ if (output_token->length)
+ (void) gss_release_buffer(&temp_minor_status, output_token);
+
+ if (src_name)
+ *src_name = GSS_C_NO_NAME;
+
+ if (tmp_src_name != GSS_C_NO_NAME)
+ (void) gss_release_buffer(&temp_minor_status,
+ (gss_buffer_t)tmp_src_name);
+
return (status);
}
-/* #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;
OM_uint32 * time_rec;
{
- OM_uint32 status, temp_minor_status, temp_time_rec = ~0;
- unsigned int i, j, creds_acquired = 0;
- int k;
- gss_union_name_t union_name;
- gss_name_t internal_name;
- gss_union_cred_t creds;
- gss_OID_set_desc default_OID_set;
- gss_OID_desc default_OID;
- gss_OID specific_mech_type = 0;
- gss_mechanism mech;
-
- /*
- * This struct is used to keep track of which mech_types are
- * actually available and to store the credentials returned
- * from them by each mechanism specific gss_acquire_cred() call.
- * The results are used to construct the final union_cred
- * structure returned by the glue layer gss_acquire_cred() call
- * and the actual_mechs gss_OID_set returned.
- */
-
- struct creds_returned {
- unsigned char available;
- gss_cred_id_t cred;
- } *creds_returned;
+ OM_uint32 major = GSS_S_FAILURE;
+ OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
+ gss_OID_set_desc default_OID_set;
+ gss_OID_set mechs;
+ gss_OID_desc default_OID;
+ gss_mechanism mech;
+ int i;
+ gss_union_cred_t creds;
+
+ /* start by checking parameters */
+ if (!minor_status)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *minor_status = 0;
- gss_initialize();
+ if (!output_cred_handle)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
- /* Set this to NULL for now */
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+ /* Set output parameters to NULL for now */
if (actual_mechs)
*actual_mechs = GSS_C_NULL_OID_SET;
- if (minor_status)
- *minor_status = 0;
-
- /* No need to continue if we don't have a place to store the creds */
- if (output_cred_handle == NULL)
- return GSS_S_COMPLETE;
-
- /* get desired_name cast as a union_name type */
-
- union_name = (gss_union_name_t) desired_name;
+ if (time_rec)
+ *time_rec = 0;
- if (union_name)
- specific_mech_type = union_name->mech_type;
-
/*
* if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
- * appropriate default.
+ * appropriate default. We use the first mechanism in the
+ * mechansim list as the default. This set is created with
+ * statics thus needs not be freed
*/
if(desired_mechs == GSS_C_NULL_OID_SET) {
- /*
- * If union_name->mech_type is NULL then we get the default
- * mechanism; otherwise, we get the mechanism for the
- * mechanism-specific name.
- */
- mech = __gss_get_mechanism(specific_mech_type);
+ mech = gssint_get_mechanism(NULL);
if (mech == NULL)
return (GSS_S_BAD_MECH);
-
- desired_mechs = &default_OID_set;
- default_OID_set.count = 1 ;
+
+ mechs = &default_OID_set;
+ default_OID_set.count = 1;
default_OID_set.elements = &default_OID;
default_OID.length = mech->mech_type.length;
default_OID.elements = mech->mech_type.elements;
- }
-
- /*
- * Now allocate the creds returned array. There is one element
- * for each member of the desired_mechs argument.
- */
-
- creds_returned = (struct creds_returned *)
- malloc(sizeof(struct creds_returned) * desired_mechs->count);
-
- /*
- * For each requested mechanism in desired_mechs, determine if it
- * is supported. If so, mark the corresponding element in
- * creds_returned->available as 1 and call the mechanism
- * specific gss_acquire_cred(), placing the returned cred in
- * creds_returned->cred. If not, mark creds_returned->available as
- * 0.
- */
- status = GSS_S_BAD_MECH;
- for (j=0; j < desired_mechs->count; j++) {
- creds_returned[j].available = 0;
-
- mech = __gss_get_mechanism (&desired_mechs->elements[j]);
- if (!mech || !mech->gss_acquire_cred)
- continue;
- /*
- * If this is a mechanism-specific name, then only use the
- * mechanism of the name.
- */
- if (specific_mech_type && !g_OID_equal(specific_mech_type,
- &mech->mech_type))
- continue;
- /*
- * If this is not a mechanism-specific name, then we need to
- * do an import the external name in union_name first.
- */
- if (union_name == 0)
- internal_name = (gss_name_t) 0;
- else if (!union_name->mech_type) {
- if (__gss_import_internal_name(&temp_minor_status,
- &mech->mech_type,
- union_name, &internal_name)) {
- continue;
+ } else
+ mechs = desired_mechs;
+
+ if (mechs->count == 0)
+ return (GSS_S_BAD_MECH);
+
+ /* allocate the output credential structure */
+ creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
+ if (creds == NULL)
+ return (GSS_S_FAILURE);
+
+ /* initialize to 0s */
+ (void) memset(creds, 0, sizeof (gss_union_cred_desc));
+
+ /* for each requested mech attempt to obtain a credential */
+ for (i = 0; i < mechs->count; i++) {
+ major = gss_add_cred(minor_status, (gss_cred_id_t)creds,
+ desired_name,
+ &mechs->elements[i],
+ cred_usage, time_req, time_req, NULL,
+ NULL, &initTimeOut, &acceptTimeOut);
+ if (major == GSS_S_COMPLETE) {
+ /* update the credential's time */
+ if (cred_usage == GSS_C_ACCEPT) {
+ if (outTime > acceptTimeOut)
+ outTime = acceptTimeOut;
+ } else if (cred_usage == GSS_C_INITIATE) {
+ if (outTime > initTimeOut)
+ outTime = initTimeOut;
+ } else {
+ /*
+ * time_rec is the lesser of the
+ * init/accept times
+ */
+ if (initTimeOut > acceptTimeOut)
+ outTime = (outTime > acceptTimeOut) ?
+ acceptTimeOut : outTime;
+ else
+ outTime = (outTime > initTimeOut) ?
+ initTimeOut : outTime;
}
- } else
- internal_name = union_name->mech_name;
-
- status = mech->gss_acquire_cred(mech->context, minor_status,
- internal_name, time_req,
- desired_mechs, cred_usage,
- &creds_returned[j].cred,
- NULL, &temp_time_rec);
-
- /* Release the internal name, if allocated above */
- if (union_name && !union_name->mech_type) {
- (void) __gss_release_internal_name(&temp_minor_status,
- &mech->mech_type,
- &internal_name);
}
+ } /* for */
- if (status != GSS_S_COMPLETE)
- continue;
-
- /*
- * Add this into the creds_returned structure, if we got
- * a good credential for this mechanism.
- */
- if (time_rec) {
- *time_rec = *time_rec > temp_time_rec ? temp_time_rec : *time_rec;
- temp_time_rec = *time_rec;
- }
-
- creds_returned[j].available = 1;
- creds_acquired++;
-
- /*
- * If union_name is set, then we're done. Continue, and
- * declare success. Otherwise, if do an inquire credentials
- * from the first mechanism that succeeds and use that as the
- * union name.
- */
- if (union_name)
- continue;
-
- status = mech->gss_inquire_cred(mech->context, &temp_minor_status,
- creds_returned[j].cred,
- &internal_name, 0, 0, 0);
- if (status) {
- /* Should never happen */
- creds_returned[j].available = 0;
- creds_acquired--;
- if (mech->gss_release_cred)
- mech->gss_release_cred(mech->context, minor_status,
- &creds_returned[j].cred);
- continue;
- }
-
- status = __gss_convert_name_to_union_name(&temp_minor_status, mech,
- internal_name,
- (gss_name_t *) &union_name);
+ /* ensure that we have at least one credential element */
+ if (creds->count < 1) {
+ free(creds);
+ return (major);
}
-
- /*
- * Now allocate the creds struct, which will be cast as a gss_cred_id_t
- * and returned in the output_cred_handle argument. If there were
- * no credentials found, return an error. Also, allocate the
- * actual_mechs data.
- */
- if (creds_acquired == 0) {
- free (creds_returned);
- return (status);
- }
-
- creds = (gss_union_cred_t) malloc(sizeof(gss_union_cred_desc));
-
- creds->count = creds_acquired;
-
- creds->mechs_array = (gss_OID)
- malloc(sizeof(gss_OID_desc) * creds_acquired);
-
- creds->cred_array = (gss_cred_id_t *)
- malloc(sizeof(gss_cred_id_t) * creds_acquired);
-
- if(actual_mechs != NULL) {
- *actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc));
-
- (*actual_mechs)->count = creds_acquired;
- (*actual_mechs)->elements = (gss_OID)
- malloc(sizeof(gss_OID_desc) * creds_acquired);
- }
-
- /*
- * copy the mechanisms found and their allocated credentials into the
- * creds structure. At the same time, build up the actual_mechs
- * data.
- */
-
- j = 0;
-
- for (i=0; i<desired_mechs->count; i++) {
- if(creds_returned[i].available) {
-
- creds->mechs_array[j].length =
- desired_mechs->elements[i].length;
- creds->mechs_array[j].elements = (void *)
- malloc(desired_mechs->elements[i].length);
- memcpy(creds->mechs_array[j].elements,
- desired_mechs->elements[i].elements,
- desired_mechs->elements[i].length);
- creds->cred_array[j] = creds_returned[i].cred;
- if (actual_mechs) {
- (*actual_mechs)->elements[j].length =
- desired_mechs->elements[i].length;
- (*actual_mechs)->elements[j].elements = (void *)
- malloc(desired_mechs->elements[i].length);
- memcpy((*actual_mechs)->elements[j].elements,
- desired_mechs->elements[i].elements,
- desired_mechs->elements[i].length);
- }
- j++;
- }
- }
-
- /* free the creds_returned struct, since we are done with it. */
-
- free(creds_returned);
-
- /* record the information needed for gss_inquire_cred() */
-
- creds->auxinfo.creation_time = time(0);
- creds->auxinfo.time_rec = temp_time_rec;
- creds->auxinfo.cred_usage = cred_usage;
-
/*
- * we can't just record the internal name, desired_name, since
- * it may be destroyed between now and the time gss_inquire_cred()
- * is called. So we must record the printable name in a
- * gss_buffer_t, calling gss_display_name() to fill it in. When
- * gss_inquire_name() is called, we must then call gss_import_name()
- * to get the internal name that is required at that point.
+ * fill in output parameters
+ * setup the actual mechs output parameter
*/
- if (desired_name) {
- status = gss_display_name(&temp_minor_status, desired_name,
- &creds->auxinfo.name,
- &creds->auxinfo.name_type);
- if (status) {
- status = GSS_S_BAD_NAME;
- goto error_out;
+ if (actual_mechs != NULL) {
+ if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
+ creds->count)) == NULL) {
+ (void) gss_release_cred(minor_status,
+ (gss_cred_id_t *)&creds);
+ *minor_status = 0;
+ return (GSS_S_FAILURE);
}
- } else {
- status = gss_display_name(&temp_minor_status, union_name,
- &creds->auxinfo.name,
- &creds->auxinfo.name_type);
- if (status) {
- status = GSS_S_BAD_NAME;
- goto error_out;
- }
- }
-
- *output_cred_handle = (gss_cred_id_t) creds;
- return(GSS_S_COMPLETE);
-
-error_out:
- for (k=0; k < creds->count; k++) {
- free(creds->mechs_array[k].elements);
- if (actual_mechs)
- free((*actual_mechs)->elements[k].elements);
}
-
- if (actual_mechs) {
- free((*actual_mechs)->elements);
- free(*actual_mechs);
- *actual_mechs = GSS_C_NULL_OID_SET;
- }
- free(creds->cred_array);
- free(creds->mechs_array);
- free(creds);
-
- return(status);
+
+ if (time_rec)
+ *time_rec = outTime;
+
+
+ *output_cred_handle = (gss_cred_id_t)creds;
+ return (GSS_S_COMPLETE);
}
/* V2 KRB5_CALLCONV */
OM_uint32 time_req, time_rec;
gss_union_name_t union_name;
gss_union_cred_t new_union_cred, union_cred;
- gss_name_t internal_name;
+ gss_name_t internal_name = GSS_C_NO_NAME;
+ gss_name_t allocated_name = GSS_C_NO_NAME;
gss_mechanism mech;
- gss_cred_id_t cred;
- gss_OID new_mechs_array;
- gss_cred_id_t * new_cred_array;
+ gss_cred_id_t cred = NULL;
+ gss_OID new_mechs_array = NULL;
+ gss_cred_id_t * new_cred_array = NULL;
+
+ /* check input parameters */
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *minor_status = 0;
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
+ output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
+
+ if (output_cred_handle)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
- if (input_cred_handle == GSS_C_NO_CREDENTIAL)
- return GSS_S_NO_CRED;
+ if (actual_mechs)
+ *actual_mechs = NULL;
+
+ if (acceptor_time_rec)
+ *acceptor_time_rec = 0;
- union_cred = (gss_union_cred_t) input_cred_handle;
+ if (initiator_time_rec)
+ *initiator_time_rec = 0;
- mech = __gss_get_mechanism(desired_mech);
+ mech = gssint_get_mechanism(desired_mech);
if (!mech)
return GSS_S_BAD_MECH;
+ else if (!mech->gss_acquire_cred)
+ return (GSS_S_UNAVAILABLE);
- if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
- GSS_C_NO_CREDENTIAL)
- return GSS_S_DUPLICATE_ELEMENT;
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+ union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (union_cred == NULL)
+ return (GSS_S_FAILURE);
- union_name = (gss_union_name_t) desired_name;
- if (union_name->mech_type) {
- if (!g_OID_equal(desired_mech, union_name->mech_type))
- return GSS_S_BAD_NAMETYPE;
- internal_name = union_name->mech_name;
+ (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
+
+ /* for default credentials we will use GSS_C_NO_NAME */
+ internal_name = GSS_C_NO_NAME;
} else {
- if (__gss_import_internal_name(minor_status, desired_mech,
- union_name, &internal_name))
- return (GSS_S_BAD_NAME);
+ union_cred = (gss_union_cred_t)input_cred_handle;
+ if (gssint_get_mechanism_cred(union_cred, desired_mech) !=
+ GSS_C_NO_CREDENTIAL)
+ return (GSS_S_DUPLICATE_ELEMENT);
+
+ /* may need to create a mechanism specific name */
+ if (desired_name) {
+ union_name = (gss_union_name_t)desired_name;
+ if (union_name->mech_type &&
+ g_OID_equal(union_name->mech_type,
+ &mech->mech_type))
+ internal_name = union_name->mech_name;
+ else {
+ if (gssint_import_internal_name(minor_status,
+ &mech->mech_type, union_name,
+ &allocated_name) != GSS_S_COMPLETE)
+ return (GSS_S_BAD_NAME);
+ internal_name = allocated_name;
+ }
+ }
}
+
if (cred_usage == GSS_C_ACCEPT)
time_req = acceptor_time_req;
else if (cred_usage == GSS_C_INITIATE)
internal_name, time_req,
GSS_C_NULL_OID_SET, cred_usage,
&cred, NULL, &time_rec);
+
if (status != GSS_S_COMPLETE)
goto errout;
+ /* may need to set credential auxinfo strucutre */
+ if (union_cred->auxinfo.creation_time == 0) {
+ union_cred->auxinfo.creation_time = time(NULL);
+ union_cred->auxinfo.time_rec = time_rec;
+ union_cred->auxinfo.cred_usage = cred_usage;
+
+ /*
+ * we must set the name; if name is not supplied
+ * we must do inquire cred to get it
+ */
+ if (internal_name == NULL) {
+ if (mech->gss_inquire_cred == NULL ||
+ ((status = mech->gss_inquire_cred(
+ mech->context,
+ &temp_minor_status, cred,
+ &allocated_name, NULL, NULL,
+ NULL)) != GSS_S_COMPLETE))
+ goto errout;
+ internal_name = allocated_name;
+ }
+
+ if (internal_name != GSS_C_NO_NAME) {
+ status = mech->gss_display_name(mech->context,
+ &temp_minor_status, internal_name,
+ &union_cred->auxinfo.name,
+ &union_cred->auxinfo.name_type);
+
+ if (status != GSS_S_COMPLETE)
+ goto errout;
+ }
+ }
+
+ /* now add the new credential elements */
new_mechs_array = (gss_OID)
- malloc(sizeof(gss_OID_desc) * (union_cred->count+1));
-
+ malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
+
new_cred_array = (gss_cred_id_t *)
- malloc(sizeof(gss_cred_id_t) * (union_cred->count+1));
+ malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
if (!new_mechs_array || !new_cred_array) {
- *minor_status = ENOMEM;
status = GSS_S_FAILURE;
goto errout;
}
-
if (acceptor_time_rec)
if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
*acceptor_time_rec = time_rec;
*initiator_time_rec = time_rec;
/*
- * OK, expand the mechanism array in the union credentials
- * (Look for the union label...)
+ * OK, expand the mechanism array and the credential array
*/
- memcpy(new_mechs_array, union_cred->mechs_array,
- sizeof(gss_OID_desc) * union_cred->count);
- memcpy(new_cred_array, union_cred->cred_array,
- sizeof(gss_cred_id_t) * union_cred->count);
-
+ (void) memcpy(new_mechs_array, union_cred->mechs_array,
+ sizeof (gss_OID_desc) * union_cred->count);
+ (void) memcpy(new_cred_array, union_cred->cred_array,
+ sizeof (gss_cred_id_t) * union_cred->count);
+
new_cred_array[union_cred->count] = cred;
- new_mechs_array[union_cred->count].length = desired_mech->length;
- new_mechs_array[union_cred->count].elements = malloc(desired_mech->length);
- if (!new_mechs_array[union_cred->count].elements) {
- *minor_status = ENOMEM;
+ if ((new_mechs_array[union_cred->count].elements =
+ malloc(mech->mech_type.length)) == NULL)
goto errout;
+
+ g_OID_copy(&new_mechs_array[union_cred->count],
+ &mech->mech_type);
+
+ if (actual_mechs) {
+ *actual_mechs = create_actual_mechs(new_mechs_array,
+ union_cred->count + 1);
+ if (*actual_mechs == NULL) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
}
- memcpy(new_mechs_array[union_cred->count].elements, desired_mech->elements,
- desired_mech->length);
if (output_cred_handle == NULL) {
free(union_cred->mechs_array);
free(union_cred->cred_array);
new_union_cred = union_cred;
} else {
- new_union_cred = malloc(sizeof(gss_union_cred_desc));
+ new_union_cred = malloc(sizeof (gss_union_cred_desc));
if (new_union_cred == NULL) {
- *minor_status = ENOMEM;
+ free(new_mechs_array[union_cred->count].elements);
goto errout;
}
*new_union_cred = *union_cred;
- *output_cred_handle = new_union_cred;
+ *output_cred_handle = (gss_cred_id_t)new_union_cred;
}
+
new_union_cred->mechs_array = new_mechs_array;
new_union_cred->cred_array = new_cred_array;
new_union_cred->count++;
- new_mechs_array = 0;
- new_cred_array = 0;
- if (actual_mechs)
- *actual_mechs = create_actual_mechs(new_union_cred);
-
- status = GSS_S_COMPLETE;
-
+ /* We're done with the internal name. Free it if we allocated it. */
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ &mech->mech_type,
+ &allocated_name);
+
+ return (GSS_S_COMPLETE);
+
errout:
if (new_mechs_array)
free(new_mechs_array);
if (new_cred_array)
free(new_cred_array);
- if (!union_name->mech_type) {
- (void) __gss_release_internal_name(&temp_minor_status,
- desired_mech, &internal_name);
+
+ if (cred != NULL && mech->gss_release_cred)
+ mech->gss_release_cred(mech->context,
+ &temp_minor_status, &cred);
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ &mech->mech_type,
+ &allocated_name);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
+ if (union_cred->auxinfo.name.value)
+ free(union_cred->auxinfo.name.value);
+ free(union_cred);
}
- return(status);
+ return (status);
}
--- /dev/null
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident "@(#)g_canon_name.c 1.15 04/02/23 SMI" */
+
+/*
+ * routine gss_canonicalize_name
+ *
+ * This routine is used to produce a mechanism specific
+ * representation of name that has been previously
+ * imported with gss_import_name. The routine uses the mechanism
+ * specific implementation of gss_import_name to implement this
+ * function.
+ *
+ * We allow a NULL output_name, in which case we modify the
+ * input_name to include the mechanism specific name.
+ */
+
+#include <mglueP.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_canonicalize_name(minor_status,
+ input_name,
+ mech_type,
+ output_name)
+OM_uint32 *minor_status;
+const gss_name_t input_name;
+const gss_OID mech_type;
+gss_name_t *output_name;
+{
+ gss_union_name_t in_union, out_union = NULL, dest_union = NULL;
+ OM_uint32 major_status = GSS_S_FAILURE;
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *minor_status = 0;
+
+ if (output_name)
+ *output_name = 0;
+
+ /* check the input parameters */
+ if (input_name == NULL || mech_type == GSS_C_NULL_OID)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ in_union = (gss_union_name_t)input_name;
+ /*
+ * If the caller wants to reuse the name, and the name has already
+ * been converted, then there is nothing for us to do.
+ */
+ if (!output_name && in_union->mech_type &&
+ g_OID_equal(in_union->mech_type, mech_type))
+ return (GSS_S_COMPLETE);
+
+ /* ok, then we need to do something - start by creating data struct */
+ if (output_name) {
+ out_union =
+ (gss_union_name_t)malloc(sizeof (gss_union_name_desc));
+ if (!out_union)
+ goto allocation_failure;
+
+ out_union->mech_type = 0;
+ out_union->mech_name = 0;
+ out_union->name_type = 0;
+ out_union->external_name = 0;
+
+ /* Allocate the buffer for the user specified representation */
+ if (gssint_create_copy_buffer(in_union->external_name,
+ &out_union->external_name, 1))
+ goto allocation_failure;
+
+ if (in_union->name_type != GSS_C_NULL_OID) {
+ if ((major_status = generic_gss_copy_oid(minor_status,
+ in_union->name_type, &out_union->name_type)))
+ goto allocation_failure;
+ }
+
+ }
+
+ /*
+ * might need to delete any old mechanism names if we are
+ * reusing the buffer.
+ */
+ if (!output_name) {
+ if (in_union->mech_type) {
+ (void) gssint_release_internal_name(minor_status,
+ in_union->mech_type,
+ &in_union->mech_name);
+ (void) gss_release_oid(minor_status,
+ &in_union->mech_type);
+ in_union->mech_type = 0;
+ }
+ dest_union = in_union;
+ } else
+ dest_union = out_union;
+
+ /* now let's create the new mech name */
+ if (major_status = generic_gss_copy_oid(minor_status, mech_type,
+ &dest_union->mech_type))
+ goto allocation_failure;
+
+ if (major_status =
+ gssint_import_internal_name(minor_status, mech_type,
+ dest_union,
+ &dest_union->mech_name))
+ goto allocation_failure;
+
+ if (output_name)
+ *output_name = (gss_name_t)dest_union;
+
+ return (GSS_S_COMPLETE);
+
+allocation_failure:
+ /* do not delete the src name external name format */
+ if (output_name) {
+ if (out_union->external_name) {
+ if (out_union->external_name->value)
+ free(out_union->external_name->value);
+ free(out_union->external_name);
+ }
+ if (out_union->name_type)
+ (void) gss_release_oid(minor_status,
+ &out_union->name_type);
+
+ dest_union = out_union;
+ } else
+ dest_union = in_union;
+
+ /*
+ * delete the partially created mech specific name
+ * applies for both src and dest which ever is being used for output
+ */
+
+ if (dest_union->mech_name) {
+ (void) gssint_release_internal_name(minor_status,
+ dest_union->mech_type,
+ &dest_union->mech_name);
+ }
+
+ if (dest_union->mech_type)
+ (void) gss_release_oid(minor_status, &dest_union->mech_type);
+
+
+ if (output_name)
+ free(out_union);
+
+ return (major_status);
+} /********** gss_canonicalize_name ********/
-/* #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,
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;
* information.
*/
if (union_name1->mech_type) {
- mech = __gss_get_mechanism (union_name1->mech_type);
+ mech = gssint_get_mechanism (union_name1->mech_type);
if (!mech)
return (GSS_S_BAD_MECH);
if (!mech->gss_compare_name)
- return (GSS_S_BAD_BINDINGS);
+ return (GSS_S_UNAVAILABLE);
}
- if (name_equal == NULL)
- return GSS_S_COMPLETE;
-
*name_equal = 0; /* Default to *not* equal.... */
/*
* 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,
union_name1 = (gss_union_name_t) name2;
union_name2 = (gss_union_name_t) name1;
}
- major_status = __gss_import_internal_name(minor_status,
+ major_status = gssint_import_internal_name(minor_status,
union_name1->mech_type,
union_name2,
&internal_name);
if (major_status != GSS_S_COMPLETE)
- return (GSS_S_COMPLETE);
+ return (GSS_S_COMPLETE); /* return complete, but not equal */
+
major_status = mech->gss_compare_name(mech->context, minor_status,
union_name1->mech_name,
internal_name, name_equal);
- __gss_release_internal_name(&temp_minor, union_name1->mech_type,
+ gssint_release_internal_name(&temp_minor, union_name1->mech_type,
&internal_name);
return (major_status);
-/* #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.
gss_union_ctx_id_t ctx;
gss_mechanism mech;
- gss_initialize();
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *minor_status = 0;
+
+ if (time_rec == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
if (context_handle == GSS_C_NO_CONTEXT)
- return GSS_S_NO_CONTEXT;
-
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
/*
* select the approprate underlying mechanism routine and
* call it.
*/
ctx = (gss_union_ctx_id_t) context_handle;
- mech = __gss_get_mechanism (ctx->mech_type);
+ mech = gssint_get_mechanism (ctx->mech_type);
if (mech) {
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);
}
-/* #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.
gss_union_ctx_id_t ctx;
gss_mechanism mech;
- gss_initialize();
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (output_token != GSS_C_NO_BUFFER) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
/* if the context_handle is Null, return NO_CONTEXT error */
-
if(context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
- return(GSS_S_NO_CONTEXT);
-
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
/*
* select the approprate underlying mechanism routine and
* call it.
*/
ctx = (gss_union_ctx_id_t) *context_handle;
- mech = __gss_get_mechanism (ctx->mech_type);
+ mech = gssint_get_mechanism (ctx->mech_type);
if (mech) {
&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);
return(status);
}
-
- return(GSS_S_NO_CONTEXT);
+
+ return (GSS_S_BAD_MECH);
}
-/* #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.
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;
/*
* OK, we have a mechanism-specific name; let's use it!
*/
- return (__gss_display_internal_name(minor_status,
+ return (gssint_display_internal_name(minor_status,
union_name->mech_type,
union_name->mech_name,
output_name_buffer,
* 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);
}
-/* #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,
gss_buffer_t status_string;
{
- OM_uint32 status;
gss_OID mech_type = (gss_OID) req_mech_type;
gss_mechanism mech;
- gss_initialize();
+ /* check the input parameters */
+ if (!minor_status)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *minor_status = 0;
+
+ if (!message_context || status_string == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ status_string->length = 0;
+ status_string->value = NULL;
+
+ /* we handle major status codes, and the mechs do the minor */
+ if (status_type == GSS_C_GSS_CODE)
+ return (displayMajor(status_value, message_context,
+ status_string));
/*
- * select the approprate underlying mechanism routine and
+ * must be the minor status - let mechs do the work
+ * select the appropriate underlying mechanism routine and
* call it.
*/
- mech = __gss_get_mechanism (mech_type);
+ mech = gssint_get_mechanism (mech_type);
+
+ if (mech && mech->gss_display_status) {
+ if (mech_type == GSS_C_NULL_OID)
+ mech_type = &mech->mech_type;
- if (mech == NULL)
+ return (mech->gss_display_status(mech->context, minor_status,
+ status_value, status_type, mech_type,
+ message_context, status_string));
+ }
+
+ if (!mech)
return (GSS_S_BAD_MECH);
- if (mech_type == GSS_C_NULL_OID)
- mech_type = &mech->mech_type;
-
- if (mech->gss_display_status)
- status = mech->gss_display_status(
- mech->context,
- minor_status,
- status_value,
- status_type,
- mech_type,
- message_context,
- status_string);
- else
- status = GSS_S_BAD_BINDINGS;
-
- return(status);
+ return (GSS_S_UNAVAILABLE);
}
+
+/*
+ * function to map the major error codes
+ * it uses case statements so that the strings could be wrapped by gettext
+ * msgCtxt is interpreted as:
+ * 0 - first call
+ * 1 - routine error
+ * >= 2 - the supplementary error code bit shifted by 1
+ */
+static OM_uint32
+displayMajor(status, msgCtxt, outStr)
+OM_uint32 status;
+OM_uint32 *msgCtxt;
+gss_buffer_t outStr;
+{
+ OM_uint32 oneVal, mask = 0x1, currErr;
+ char *errStr = NULL;
+ int i, haveErr = 0;
+
+ /* take care of the success value first */
+ if (status == GSS_S_COMPLETE)
+ errStr = "The routine completed successfully";
+ else if (*msgCtxt == 0 && (oneVal = GSS_CALLING_ERROR(status))) {
+ switch (oneVal) {
+ case GSS_S_CALL_INACCESSIBLE_READ:
+ errStr = "A required input parameter"
+ " could not be read";
+ break;
+
+ case GSS_S_CALL_INACCESSIBLE_WRITE:
+ errStr = "A required output parameter"
+ " could not be written";
+ break;
+
+ case GSS_S_CALL_BAD_STRUCTURE:
+ errStr = "A parameter was malformed";
+ break;
+
+ default:
+ errStr = "An invalid status code was supplied";
+ break;
+ }
+
+ /* we now need to determine new value of msgCtxt */
+ if (GSS_ROUTINE_ERROR(status))
+ *msgCtxt = 1;
+ else if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
+ *msgCtxt = (OM_uint32)(oneVal << 1);
+ else
+ *msgCtxt = 0;
+
+ } else if ((*msgCtxt == 0 || *msgCtxt == 1) &&
+ (oneVal = GSS_ROUTINE_ERROR(status))) {
+ switch (oneVal) {
+ case GSS_S_BAD_MECH:
+ errStr = "An unsupported mechanism"
+ " was requested";
+ break;
+
+ case GSS_S_BAD_NAME:
+ errStr = "An invalid name was supplied";
+ break;
+
+ case GSS_S_BAD_NAMETYPE:
+ errStr = "A supplied name was of an"
+ " unsupported type";
+ break;
+
+ case GSS_S_BAD_BINDINGS:
+ errStr = "Incorrect channel bindings"
+ " were supplied";
+ break;
+
+ case GSS_S_BAD_SIG: /* same as GSS_S_BAD_MIC: */
+ errStr = "A token had an invalid Message"
+ " Integrity Check (MIC)";
+ break;
+
+ case GSS_S_NO_CRED:
+ errStr = "No credentials were supplied, or the"
+ " credentials were unavailable or"
+ " inaccessible";
+ break;
+
+ case GSS_S_NO_CONTEXT:
+ errStr = "No context has been established";
+ break;
+
+ case GSS_S_DEFECTIVE_TOKEN:
+ errStr = "Invalid token was supplied";
+ break;
+
+ case GSS_S_DEFECTIVE_CREDENTIAL:
+ errStr = "Invalid credential was supplied";
+ break;
+
+ case GSS_S_CREDENTIALS_EXPIRED:
+ errStr = "The referenced credential has"
+ " expired";
+ break;
+
+ case GSS_S_CONTEXT_EXPIRED:
+ errStr = "The referenced context has expired";
+ break;
+
+ case GSS_S_FAILURE:
+ errStr = "Unspecified GSS failure. Minor code"
+ " may provide more information";
+ break;
+
+ case GSS_S_BAD_QOP:
+ errStr = "The quality-of-protection (QOP) "
+ "requested could not be provided";
+ break;
+
+ case GSS_S_UNAUTHORIZED:
+ errStr = "The operation is forbidden by local"
+ " security policy";
+ break;
+
+ case GSS_S_UNAVAILABLE:
+ errStr = "The operation or option is not"
+ " available or unsupported";
+ break;
+
+ case GSS_S_DUPLICATE_ELEMENT:
+ errStr = "The requested credential element"
+ " already exists";
+ break;
+
+ case GSS_S_NAME_NOT_MN:
+ errStr = "The provided name was not mechanism"
+ " specific (MN)";
+ break;
+
+ case GSS_S_BAD_STATUS:
+ default:
+ errStr = "An invalid status code was supplied";
+ }
+
+ /* we must determine if the caller should call us again */
+ if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
+ *msgCtxt = (OM_uint32)(oneVal << 1);
+ else
+ *msgCtxt = 0;
+
+ } else if ((*msgCtxt == 0 || *msgCtxt >= 2) &&
+ (oneVal = GSS_SUPPLEMENTARY_INFO(status))) {
+ /*
+ * if msgCtxt is not 0, then it should encode
+ * the supplementary error code we should be printing
+ */
+ if (*msgCtxt >= 2)
+ oneVal = (OM_uint32) (*msgCtxt) >> 1;
+ else
+ oneVal = GSS_SUPPLEMENTARY_INFO(status);
+
+ /* we display the errors LSB first */
+ for (i = 0; i < 16; i++) {
+ if (oneVal & mask) {
+ haveErr = 1;
+ break;
+ }
+ mask <<= 1;
+ }
+
+ /* isolate the bit or if not found set to illegal value */
+ if (haveErr)
+ currErr = oneVal & mask;
+ else
+ currErr = 1 << 17; /* illegal value */
+
+ switch (currErr) {
+ case GSS_S_CONTINUE_NEEDED:
+ errStr = "The routine must be called again to"
+ " complete its function";
+ break;
+
+ case GSS_S_DUPLICATE_TOKEN:
+ errStr = "The token was a duplicate of an"
+ " earlier token";
+ break;
+
+ case GSS_S_OLD_TOKEN:
+ errStr = "The token's validity period"
+ " has expired";
+ break;
+
+ case GSS_S_UNSEQ_TOKEN:
+ errStr = "A later token has already been"
+ " processed";
+ break;
+
+ case GSS_S_GAP_TOKEN:
+ errStr = "An expected per-message token was"
+ " not received";
+ break;
+
+ default:
+ errStr = "An invalid status code was supplied";
+ }
+
+ /*
+ * we must check if there is any other supplementary errors
+ * if found, then turn off current bit, and store next value
+ * in msgCtxt shifted by 1 bit
+ */
+ if (!haveErr)
+ *msgCtxt = 0;
+ else if (GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask)
+ *msgCtxt = (OM_uint32)
+ ((GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) << 1);
+ else
+ *msgCtxt = 0;
+ }
+
+ if (errStr == NULL)
+ errStr = "An invalid status code was supplied";
+
+ /* now copy the status code and return to caller */
+ outStr->length = strlen(errStr);
+ outStr->value = malloc((size_t)outStr->length+1);
+ if (outStr->value == NULL) {
+ outStr->length = 0;
+ return (GSS_S_FAILURE);
+ }
+
+ (void) strcpy((char *)outStr->value, errStr);
+ return (GSS_S_COMPLETE);
+} /* displayMajor */
--- /dev/null
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident "@(#)g_dup_name.c 1.14 04/02/23 SMI" */
+
+/*
+ * routine gss_duplicate_name
+ *
+ * This routine does not rely on mechanism implementation of this
+ * name, but instead uses mechanism specific gss_import_name routine.
+ */
+
+#include <mglueP.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_duplicate_name(minor_status,
+ src_name,
+ dest_name)
+OM_uint32 *minor_status;
+const gss_name_t src_name;
+gss_name_t *dest_name;
+{
+ gss_union_name_t src_union, dest_union;
+ OM_uint32 major_status = GSS_S_FAILURE;
+
+
+ if (!minor_status)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *minor_status = 0;
+
+ /* if output_name is NULL, simply return */
+ if (dest_name == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_BAD_NAME);
+
+ *dest_name = 0;
+
+ if (src_name == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ src_union = (gss_union_name_t)src_name;
+
+ /*
+ * First create the union name struct that will hold the external
+ * name and the name type.
+ */
+ dest_union = (gss_union_name_t)malloc(sizeof (gss_union_name_desc));
+ if (!dest_union)
+ goto allocation_failure;
+
+ dest_union->mech_type = 0;
+ dest_union->mech_name = 0;
+ dest_union->name_type = 0;
+ dest_union->external_name = 0;
+
+ /* Now copy the external representaion */
+ if (gssint_create_copy_buffer(src_union->external_name,
+ &dest_union->external_name, 0))
+ goto allocation_failure;
+
+ if (src_union->name_type != GSS_C_NULL_OID) {
+ major_status = generic_gss_copy_oid(minor_status,
+ src_union->name_type,
+ &dest_union->name_type);
+ if (major_status != GSS_S_COMPLETE)
+ goto allocation_failure;
+ }
+
+ /*
+ * See if source name is mechanim specific, if so then need to import it
+ */
+ if (src_union->mech_type) {
+ major_status = generic_gss_copy_oid(minor_status,
+ src_union->mech_type,
+ &dest_union->mech_type);
+ if (major_status != GSS_S_COMPLETE)
+ goto allocation_failure;
+
+ major_status = gssint_import_internal_name(minor_status,
+ dest_union->mech_type,
+ dest_union,
+ &dest_union->mech_name);
+ if (major_status != GSS_S_COMPLETE)
+ goto allocation_failure;
+ }
+
+
+ *dest_name = (gss_name_t)dest_union;
+ return (GSS_S_COMPLETE);
+
+allocation_failure:
+ if (dest_union) {
+ if (dest_union->external_name) {
+ if (dest_union->external_name->value)
+ free(dest_union->external_name->value);
+ free(dest_union->external_name);
+ }
+ if (dest_union->name_type)
+ (void) generic_gss_release_oid(minor_status,
+ &dest_union->name_type);
+ if (dest_union->mech_name)
+ (void) gssint_release_internal_name(minor_status,
+ dest_union->mech_type,
+ &dest_union->mech_name);
+ if (dest_union->mech_type)
+ (void) generic_gss_release_oid(minor_status,
+ &dest_union->mech_type);
+ free(dest_union);
+ }
+ return (major_status);
+} /* gss_duplicate_name */
-/* #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.
{
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
*/
ctx = (gss_union_ctx_id_t) *context_handle;
- mech = __gss_get_mechanism (ctx->mech_type);
+ mech = gssint_get_mechanism (ctx->mech_type);
if (!mech)
return GSS_S_BAD_MECH;
if (!mech->gss_export_sec_context)
- return GSS_S_BAD_BINDINGS;
+ return (GSS_S_UNAVAILABLE);
status = mech->gss_export_sec_context(mech->context, minor_status,
&ctx->internal_ctx_id, &token);
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;
--- /dev/null
+/*
+ * Copyright (c) 1996,1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* #pragma ident "@(#)g_export_name.c 1.11 00/07/17 SMI" */
+
+/*
+ * glue routine gss_export_name
+ *
+ * Will either call the mechanism defined gss_export_name, or if one is
+ * not defined will call a generic_gss_export_name routine.
+ */
+
+#include <mglueP.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_export_name(minor_status,
+ input_name,
+ exported_name)
+OM_uint32 * minor_status;
+const gss_name_t input_name;
+gss_buffer_t exported_name;
+{
+ gss_union_name_t union_name;
+
+
+ if (minor_status)
+ *minor_status = 0;
+
+ /* check out parameter */
+ if (!exported_name)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ exported_name->value = NULL;
+ exported_name->length = 0;
+
+ /* check input parameter */
+ if (!input_name)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ union_name = (gss_union_name_t)input_name;
+
+ /* the name must be in mechanism specific format */
+ if (!union_name->mech_type)
+ return (GSS_S_NAME_NOT_MN);
+
+ return gssint_export_internal_name(minor_status, union_name->mech_type,
+ union_name->mech_name, exported_name);
+}
-/* #ident "@(#)g_glue.c 1.1 96/02/06 SMI" */
+/* #pragma ident "@(#)g_glue.c 1.25 04/02/23 SMI" */
/*
* Copyright 1996 by Sun Microsystems, Inc.
#include <string.h>
#include <errno.h>
-#define g_OID_equal(o1,o2) \
- (((o1)->length == (o2)->length) && \
- (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0))
+#define MSO_BIT (8*(sizeof (int) - 1)) /* Most significant octet bit */
-extern gss_mechanism *__gss_mechs_array;
+extern gss_mechanism *gssint_mechs_array;
/*
* This file contains the support routines for the glue layer.
*/
/*
- * given the mechs_array and a mechanism OID, return the
- * pointer to the mechanism, or NULL if that mechanism is
- * not supported. If the requested OID is NULL, then return
- * the first mechanism.
+ * get_der_length: Givin a pointer to a buffer that contains a DER encoded
+ * length, decode the length updating the buffer to point to the character
+ * after the DER encoding. The parameter bytes will point to the number of
+ * bytes that made up the DER encoding of the length originally pointed to
+ * by the buffer. Note we return -1 on error.
*/
+int
+gssint_get_der_length(unsigned char **buf, unsigned int buf_len, unsigned int *bytes)
+{
+ /* p points to the beginning of the buffer */
+ unsigned char *p = *buf;
+ int length, new_length;
+ int octets;
+
+ if (buf_len < 1)
+ return (-1);
+
+ /* We should have at least one byte */
+ *bytes = 1;
+
+ /*
+ * If the High order bit is not set then the length is just the value
+ * of *p.
+ */
+ if (*p < 128) {
+ *buf = p+1; /* Advance the buffer */
+ return (*p); /* return the length */
+ }
+
+ /*
+ * if the High order bit is set, then the low order bits represent
+ * the number of bytes that contain the DER encoding of the length.
+ */
+
+ octets = *p++ & 0x7f;
+ *bytes += octets;
-gss_mechanism __gss_get_mechanism (type)
- gss_OID type;
+ /* See if the supplied buffer contains enough bytes for the length. */
+ if (octets > buf_len - 1)
+ return (-1);
+
+ /*
+ * Calculate a multibyte length. The length is encoded as an
+ * unsigned integer base 256.
+ */
+ for (length = 0; octets; octets--) {
+ new_length = (length << 8) + *p++;
+ if (new_length < length) /* overflow */
+ return (-1);
+ length = new_length;
+ }
+
+ *buf = p; /* Advance the buffer */
+
+ return (length);
+}
+
+/*
+ * der_length_size: Return the number of bytes to encode a given length.
+ */
+unsigned int
+gssint_der_length_size(unsigned int len)
{
- int i;
+ int i;
- if (type == GSS_C_NULL_OID)
- return (__gss_mechs_array[0]);
+ if (len < 128)
+ return (1);
- for (i=0; __gss_mechs_array[i]->mech_type.length != 0; i++) {
- if ((__gss_mechs_array[i]->mech_type.length == type->length) &&
- (memcmp (__gss_mechs_array[i]->mech_type.elements, type->elements,
- type->length) == 0)) {
+ for (i = 0; len; i++) {
+ len >>= 8;
+ }
+
+ return (i+1);
+}
+
+/*
+ * put_der_length: Encode the supplied length into the buffer pointed to
+ * by buf. max_length represents the maximum length of the buffer pointed
+ * to by buff. We will advance buf to point to the character after the newly
+ * DER encoded length. We return 0 on success or -l it the length cannot
+ * be encoded in max_len characters.
+ */
+int
+gssint_put_der_length(unsigned int length, unsigned char **buf, unsigned int max_len)
+{
+ unsigned char *s = *buf, *p;
+ unsigned int buf_len = 0;
+ int i, first;
+
+ /* Oops */
+ if (buf == 0 || max_len < 1)
+ return (-1);
+
+ /* Single byte is the length */
+ if (length < 128) {
+ *s++ = length;
+ *buf = s;
+ return (0);
+ }
+
+ /* First byte contains the number of octets */
+ p = s + 1;
+
+ /* Running total of the DER encoding length */
+ buf_len = 0;
- return (__gss_mechs_array[i]);
+ /*
+ * Encode MSB first. We do the encoding by setting a shift
+ * factor to MSO_BIT (24 for 32 bit words) and then shifting the length
+ * by the factor. We then encode the resulting low order byte.
+ * We subtract 8 from the shift factor and repeat to ecnode the next
+ * byte. We stop when the shift factor is zero or we've run out of
+ * buffer to encode into.
+ */
+ first = 0;
+ for (i = MSO_BIT; i >= 0 && buf_len <= max_len; i -= 8) {
+ unsigned int v;
+ v = (length >> i) & 0xff;
+ if ((v) || first) {
+ buf_len += 1;
+ *p++ = v;
+ first = 1;
}
}
- return NULL;
+ if (i >= 0) /* buffer overflow */
+ return (-1);
+
+ /*
+ * We go back now and set the first byte to be the length with
+ * the high order bit set.
+ */
+ *s = buf_len | 0x80;
+ *buf = p;
+
+ return (0);
}
*
*/
-OM_uint32 __gss_get_mech_type(OID, token)
+OM_uint32 gssint_get_mech_type(OID, token)
gss_OID OID;
gss_buffer_t 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 */
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);
#include "mglueP.h"
-OM_uint32 __gss_import_internal_name (minor_status, mech_type, union_name,
+OM_uint32 gssint_import_internal_name (minor_status, mech_type, union_name,
internal_name)
OM_uint32 *minor_status;
gss_OID mech_type;
OM_uint32 status;
gss_mechanism mech;
- mech = __gss_get_mechanism (mech_type);
+ mech = gssint_get_mechanism (mech_type);
if (mech) {
if (mech->gss_import_name)
status = mech->gss_import_name (
union_name->name_type,
internal_name);
else
- status = GSS_S_BAD_BINDINGS;
+ status = GSS_S_UNAVAILABLE;
return (status);
}
return (GSS_S_BAD_MECH);
}
-OM_uint32 __gss_display_internal_name (minor_status, mech_type, internal_name,
+OM_uint32 gssint_export_internal_name(minor_status, mech_type,
+ internal_name, name_buf)
+ OM_uint32 *minor_status;
+ const gss_OID mech_type;
+ const gss_name_t internal_name;
+ gss_buffer_t name_buf;
+{
+ OM_uint32 status;
+ gss_mechanism mech;
+ gss_buffer_desc dispName;
+ gss_OID nameOid;
+ unsigned char *buf = NULL;
+ const unsigned char tokId[] = "\x04\x01";
+ const unsigned int tokIdLen = 2;
+ const int mechOidLenLen = 2, mechOidTagLen = 1, nameLenLen = 4;
+ int mechOidDERLen = 0;
+ int mechOidLen = 0;
+
+ mech = gssint_get_mechanism(mech_type);
+ if (!mech)
+ return (GSS_S_BAD_MECH);
+
+ if (mech->gss_export_name)
+ return (mech->gss_export_name(mech->context,
+ minor_status,
+ internal_name,
+ name_buf));
+
+ /*
+ * if we are here it is because the mechanism does not provide
+ * a gss_export_name so we will use our implementation. We
+ * do required that the mechanism define a gss_display_name.
+ */
+ if (!mech->gss_display_name)
+ return (GSS_S_UNAVAILABLE);
+
+ /*
+ * NOTE: RFC2743 (section 3.2) governs the format of the outer
+ * wrapper of exported names; the mechanisms' specs govern
+ * the format of the inner portion of the exported name
+ * and, for some (e.g., RFC1964, the Kerberos V mech), a
+ * generic default as implemented here will do.
+ *
+ * The outer wrapper of an exported MN is: 2-octet tok Id
+ * (0x0401) + 2-octet network-byte order mech OID length + mech
+ * oid (in DER format, including DER tag and DER length) +
+ * 4-octet network-byte order length of inner portion + inner
+ * portion.
+ *
+ * For the Kerberos V mechanism the inner portion of an exported
+ * MN is the display name string and ignores the name type OID
+ * altogether. And we hope this will be so for any future
+ * mechanisms also, so that factoring name export/import out of
+ * the mech and into libgss pays off.
+ */
+ if ((status = mech->gss_display_name(mech->context,
+ minor_status,
+ internal_name,
+ &dispName,
+ &nameOid))
+ != GSS_S_COMPLETE)
+ return (status);
+
+ /* determine the size of the buffer needed */
+ mechOidDERLen = gssint_der_length_size(mech_type->length);
+ name_buf->length = tokIdLen + mechOidLenLen +
+ mechOidTagLen + mechOidDERLen +
+ mech_type->length +
+ nameLenLen + dispName.length;
+ if ((name_buf->value = (void*)malloc(name_buf->length)) ==
+ (void*)NULL) {
+ name_buf->length = 0;
+ (void) gss_release_buffer(&status, &dispName);
+ return (GSS_S_FAILURE);
+ }
+
+ /* now create the name ..... */
+ buf = (unsigned char *)name_buf->value;
+ (void) memset(name_buf->value, 0, name_buf->length);
+ (void) memcpy(buf, tokId, tokIdLen);
+ buf += tokIdLen;
+
+ /* spec allows only 2 bytes for the mech oid length */
+ mechOidLen = mechOidDERLen + mechOidTagLen + mech_type->length;
+ *buf++ = (mechOidLen & 0xFF00) >> 8;
+ *buf++ = (mechOidLen & 0x00FF);
+
+ /*
+ * DER Encoding of mech OID contains OID Tag (0x06), length and
+ * mech OID value
+ */
+ *buf++ = 0x06;
+ if (gssint_put_der_length(mech_type->length, &buf,
+ (name_buf->length - tokIdLen -2)) != 0) {
+ name_buf->length = 0;
+ free(name_buf->value);
+ (void) gss_release_buffer(&status, &dispName);
+ return (GSS_S_FAILURE);
+ }
+
+ (void) memcpy(buf, mech_type->elements, mech_type->length);
+ buf += mech_type->length;
+
+ /* spec designates the next 4 bytes for the name length */
+ *buf++ = (dispName.length & 0xFF000000) >> 24;
+ *buf++ = (dispName.length & 0x00FF0000) >> 16;
+ *buf++ = (dispName.length & 0x0000FF00) >> 8;
+ *buf++ = (dispName.length & 0X000000FF);
+
+ /* for the final ingredient - add the name from gss_display_name */
+ (void) memcpy(buf, dispName.value, dispName.length);
+
+ /* release the buffer obtained from gss_display_name */
+ (void) gss_release_buffer(minor_status, &dispName);
+ return (GSS_S_COMPLETE);
+} /* gssint_export_internal_name */
+
+OM_uint32 gssint_display_internal_name (minor_status, mech_type, internal_name,
external_name, name_type)
OM_uint32 *minor_status;
gss_OID mech_type;
OM_uint32 status;
gss_mechanism mech;
- mech = __gss_get_mechanism (mech_type);
+ mech = gssint_get_mechanism (mech_type);
if (mech) {
if (mech->gss_display_name)
status = mech->gss_display_name (
external_name,
name_type);
else
- status = GSS_S_BAD_BINDINGS;
+ status = GSS_S_UNAVAILABLE;
return (status);
}
return (GSS_S_BAD_MECH);
}
-OM_uint32 __gss_release_internal_name (minor_status, mech_type, internal_name)
+OM_uint32 gssint_release_internal_name (minor_status, mech_type, internal_name)
OM_uint32 *minor_status;
gss_OID mech_type;
gss_name_t *internal_name;
OM_uint32 status;
gss_mechanism mech;
- mech = __gss_get_mechanism (mech_type);
+ mech = gssint_get_mechanism (mech_type);
if (mech) {
if (mech->gss_release_name)
status = mech->gss_release_name (
minor_status,
internal_name);
else
- status = GSS_S_BAD_BINDINGS;
+ status = GSS_S_UNAVAILABLE;
return (status);
}
* name. Note that internal_name should be considered "consumed" by
* this call, whether or not we return an error.
*/
-OM_uint32 __gss_convert_name_to_union_name(minor_status, mech,
+OM_uint32 gssint_convert_name_to_union_name(minor_status, mech,
internal_name, external_name)
OM_uint32 *minor_status;
gss_mechanism mech;
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;
union_name->external_name =
(gss_buffer_t) malloc(sizeof(gss_buffer_desc));
if (!union_name->external_name) {
- *minor_status = ENOMEM;
goto allocation_failure;
}
}
if (union_name->name_type)
gss_release_oid(&tmp, &union_name->name_type);
- if (union_name->mech_name)
- __gss_release_internal_name(minor_status, union_name->mech_type,
- &union_name->mech_name);
if (union_name->mech_type)
gss_release_oid(&tmp, &union_name->mech_type);
free(union_name);
}
+ /*
+ * do as the top comment says - since we are now owners of
+ * internal_name, we must clean it up
+ */
+ if (internal_name)
+ (void) gssint_release_internal_name(&tmp, &mech->mech_type,
+ &internal_name);
return (major_status);
}
* external union credential.
*/
gss_cred_id_t
-__gss_get_mechanism_cred(union_cred, mech_type)
+gssint_get_mechanism_cred(union_cred, mech_type)
gss_union_cred_t union_cred;
gss_OID mech_type;
{
return GSS_C_NO_CREDENTIAL;
}
-
+/*
+ * Routine to create and copy the gss_buffer_desc structure.
+ * Both space for the structure and the data is allocated.
+ */
+OM_uint32
+gssint_create_copy_buffer(srcBuf, destBuf, addNullChar)
+ const gss_buffer_t srcBuf;
+ gss_buffer_t *destBuf;
+ int addNullChar;
+{
+ gss_buffer_t aBuf;
+ unsigned int len;
+
+ if (destBuf == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *destBuf = 0;
+
+ aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
+ if (!aBuf)
+ return (GSS_S_FAILURE);
+
+ if (addNullChar)
+ len = srcBuf->length + 1;
+ else
+ len = srcBuf->length;
+
+ if (!(aBuf->value = (void*)malloc(len))) {
+ free(aBuf);
+ return (GSS_S_FAILURE);
+ }
+
+
+ (void) memcpy(aBuf->value, srcBuf->value, srcBuf->length);
+ aBuf->length = srcBuf->length;
+ *destBuf = aBuf;
+
+ /* optionally add a NULL character */
+ if (addNullChar)
+ ((char *)aBuf->value)[aBuf->length] = '\0';
+
+ return (GSS_S_COMPLETE);
+} /* ****** gssint_create_copy_buffer ****** */
-/* #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.
#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,
{
gss_union_name_t union_name;
OM_uint32 tmp, major_status = GSS_S_FAILURE;
- gss_OID mech;
-
- gss_initialize();
- if (minor_status)
- *minor_status = 0;
+ /* check output parameters */
+ if (!minor_status)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
- /* if output_name is NULL, simply return */
+ *minor_status = 0;
- if(output_name == NULL)
- return (GSS_S_COMPLETE);
+ if (output_name == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
*output_name = 0;
if (input_name_buffer == GSS_C_NO_BUFFER)
return (GSS_S_BAD_NAME);
+ if (GSS_EMPTY_BUFFER(input_name_buffer))
+ return (GSS_S_BAD_NAME);
+
/*
* First create the union name struct that will hold the external
* name and the name type.
*/
-
union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));
- if (!union_name) {
- *minor_status = ENOMEM;
- goto allocation_failure;
- }
+ if (!union_name)
+ return (GSS_S_FAILURE);
+
union_name->mech_type = 0;
union_name->mech_name = 0;
union_name->name_type = 0;
/*
* All we do here is record the external name and name_type.
* When the name is actually used, the underlying gss_import_name()
- * is called for the appropriate mechanism. Note that the name type
- * is assumed to be constant, so only a pointer to it is stored in
- * union_name
+ * is called for the appropriate mechanism. The exception to this
+ * rule is when the name of GSS_C_NT_EXPORT_NAME type. If that is
+ * the case, then we make it MN in this call.
*/
- union_name->external_name =
- (gss_buffer_t) malloc(sizeof(gss_buffer_desc));
- if (!union_name->external_name) {
- *minor_status = ENOMEM;
- goto allocation_failure;
- }
-
- union_name->external_name->length = input_name_buffer->length;
- /* we malloc length+1 to stick a NULL on the end, just in case */
- /* Note that this NULL is not included in ->length for a reason! */
- union_name->external_name->value =
- (void *) malloc(input_name_buffer->length+1);
- if (!union_name->external_name->value) {
- *minor_status = ENOMEM;
- goto allocation_failure;
+ major_status = gssint_create_copy_buffer(input_name_buffer,
+ &union_name->external_name, 0);
+ if (major_status != GSS_S_COMPLETE) {
+ free(union_name);
+ return (major_status);
}
-
- memcpy(union_name->external_name->value, input_name_buffer->value,
- input_name_buffer->length);
-
- /* add NULL to end of external_name->value, just in case... */
- ((char *)union_name->external_name->value)
- [input_name_buffer->length] = '\0';
- major_status = generic_gss_copy_oid(minor_status, input_name_type,
- &union_name->name_type);
- if (major_status != GSS_S_COMPLETE)
- goto allocation_failure;
+ if (input_name_type != GSS_C_NULL_OID) {
+ major_status = generic_gss_copy_oid(minor_status,
+ input_name_type,
+ &union_name->name_type);
+ if (major_status != GSS_S_COMPLETE)
+ goto allocation_failure;
+ }
/*
- * See if this is a mechanism-specific name. If so, let's import
- * it now so we can get any error messages, and to avoid trouble
- * later...
+ * In MIT Distribution the mechanism is determined from the nametype;
+ * This is not a good idea - first mechanism that supports a given
+ * name type is picked up; later on the caller can request a
+ * different mechanism. So we don't determine the mechanism here. Now
+ * the user level and kernel level import_name routine looks similar
+ * except the kernel routine makes a copy of the nametype structure. We
+ * do however make this an MN for names of GSS_C_NT_EXPORT_NAME type.
*/
- mech = gss_find_mechanism_from_name_type(input_name_type);
- if (mech) {
- major_status = generic_gss_copy_oid(minor_status, mech,
- &union_name->mech_type);
+ if (input_name_type != GSS_C_NULL_OID &&
+ g_OID_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) {
+ major_status = importExportName(minor_status, union_name);
if (major_status != GSS_S_COMPLETE)
goto allocation_failure;
-
- major_status = __gss_import_internal_name(minor_status, mech,
- union_name,
- &union_name->mech_name);
- if (major_status)
- goto allocation_failure;
}
- *output_name = (gss_name_t) union_name;
-
- return(GSS_S_COMPLETE);
+ *output_name = (gss_name_t)union_name;
+ return (GSS_S_COMPLETE);
allocation_failure:
if (union_name) {
if (union_name->name_type)
generic_gss_release_oid(&tmp, &union_name->name_type);
if (union_name->mech_name)
- __gss_release_internal_name(minor_status, union_name->mech_type,
+ gssint_release_internal_name(minor_status, union_name->mech_type,
&union_name->mech_name);
if (union_name->mech_type)
generic_gss_release_oid(&tmp, &union_name->mech_type);
}
return (major_status);
}
+
+/*
+ * GSS export name constants
+ */
+static const char *expNameTokId = "\x04\x01";
+static const unsigned int expNameTokIdLen = 2;
+static const unsigned int mechOidLenLen = 2;
+static const unsigned int nameTypeLenLen = 2;
+
+static OM_uint32
+importExportName(minor, unionName)
+ OM_uint32 *minor;
+ gss_union_name_t unionName;
+{
+ gss_OID_desc mechOid;
+ gss_buffer_desc expName;
+ unsigned char *buf;
+ gss_mechanism mech;
+ OM_uint32 major, mechOidLen, nameLen, curLength;
+ unsigned int bytes;
+
+ expName.value = unionName->external_name->value;
+ expName.length = unionName->external_name->length;
+
+ curLength = expNameTokIdLen + mechOidLenLen;
+ if (expName.length < curLength)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ buf = (unsigned char *)expName.value;
+ if (memcmp(expNameTokId, buf, expNameTokIdLen) != 0)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ buf += expNameTokIdLen;
+
+ /* extract the mechanism oid length */
+ mechOidLen = (*buf++ << 8);
+ mechOidLen |= (*buf++);
+ curLength += mechOidLen;
+ if (expName.length < curLength)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ /*
+ * The mechOid itself is encoded in DER format, OID Tag (0x06)
+ * length and the value of mech_OID
+ */
+ if (*buf++ != 0x06)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ /*
+ * mechoid Length is encoded twice; once in 2 bytes as
+ * explained in RFC2743 (under mechanism independent exported
+ * name object format) and once using DER encoding
+ *
+ * We verify both lengths.
+ */
+
+ mechOid.length = gssint_get_der_length(&buf,
+ (expName.length - curLength), &bytes);
+ mechOid.elements = (void *)buf;
+
+ /*
+ * 'bytes' is the length of the DER length, '1' is for the DER
+ * tag for OID
+ */
+ if ((bytes + mechOid.length + 1) != mechOidLen)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ buf += mechOid.length;
+ if ((mech = gssint_get_mechanism(&mechOid)) == NULL)
+ return (GSS_S_BAD_MECH);
+
+ if (mech->gss_import_name == NULL)
+ return (GSS_S_UNAVAILABLE);
+
+ /*
+ * we must now determine if we should unwrap the name ourselves
+ * or make the mechanism do it - we should only unwrap it
+ * if we create it; so if mech->gss_export_name == NULL, we must
+ * have created it.
+ */
+ if (mech->gss_export_name) {
+ if ((major = mech->gss_import_name(mech->context, minor,
+ &expName, (gss_OID)GSS_C_NT_EXPORT_NAME,
+ &unionName->mech_name)) != GSS_S_COMPLETE ||
+ (major = generic_gss_copy_oid(minor, &mechOid,
+ &unionName->mech_type)) !=
+ GSS_S_COMPLETE) {
+ return (major);
+ }
+ return (major);
+ }
+ /*
+ * we must have exported the name - so we now need to reconstruct it
+ * and call the mechanism to create it
+ *
+ * WARNING: Older versions of gssint_export_internal_name() did
+ * not export names correctly, but now it does. In
+ * order to stay compatible with existing exported
+ * names we must support names exported the broken
+ * way.
+ *
+ * Specifically, gssint_export_internal_name() used to include
+ * the name type OID in the encoding of the exported MN.
+ * Additionally, the Kerberos V mech used to make display names
+ * that included a null terminator which was counted in the
+ * display name gss_buffer_desc.
+ */
+ curLength += 4; /* 4 bytes for name len */
+ if (expName.length < curLength)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ /* next 4 bytes in the name are the name length */
+ nameLen = (*buf++) << 24;
+ nameLen |= (*buf++ << 16);
+ nameLen |= (*buf++ << 8);
+ nameLen |= (*buf++);
+
+ /*
+ * we use < here because bad code in rpcsec_gss rounds up exported
+ * name token lengths and pads with nulls, otherwise != would be
+ * appropriate
+ */
+ curLength += nameLen; /* this is the total length */
+ if (expName.length < curLength)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ /*
+ * We detect broken exported names here: they always start with
+ * a two-octet network-byte order OID length, which is always
+ * less than 256 bytes, so the first octet of the length is
+ * always '\0', which is not allowed in GSS-API display names
+ * (or never occurs in them anyways). Of course, the OID
+ * shouldn't be there, but it is. After the OID (sans DER tag
+ * and length) there's the name itself, though null-terminated;
+ * this null terminator should also not be there, but it is.
+ */
+ if (nameLen > 0 && *buf == '\0') {
+ OM_uint32 nameTypeLen;
+ /* next two bytes are the name oid */
+ if (nameLen < nameTypeLenLen)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ nameLen -= nameTypeLenLen;
+
+ nameTypeLen = (*buf++) << 8;
+ nameTypeLen |= (*buf++);
+
+ if (nameLen < nameTypeLen)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ buf += nameTypeLen;
+ nameLen -= nameTypeLen;
+
+ /*
+ * adjust for expected null terminator that should
+ * really not be there
+ */
+ if (nameLen > 0 && *(buf + nameLen - 1) == '\0')
+ nameLen--;
+ }
+
+ /*
+ * Can a name be null? Let the mech decide.
+ *
+ * NOTE: We use GSS_C_NULL_OID as the name type when importing
+ * the unwrapped name. Presumably the exported name had,
+ * prior to being exported been obtained in such a way
+ * that it has been properly perpared ("canonicalized," in
+ * GSS-API terms) accroding to some name type; we cannot
+ * tell what that name type was now, but the name should
+ * need no further preparation other than the lowest
+ * common denominator afforded by the mech to names
+ * imported with GSS_C_NULL_OID. For the Kerberos V mech
+ * this means doing less busywork too (particularly once
+ * IDN is thrown in with Kerberos V extensions).
+ */
+ expName.length = nameLen;
+ expName.value = nameLen ? (void *)buf : NULL;
+ major = mech->gss_import_name(mech->context, minor, &expName,
+ GSS_C_NULL_OID, &unionName->mech_name);
+ if (major != GSS_S_COMPLETE)
+ return (major);
+
+ return (generic_gss_copy_oid(minor, &mechOid, &unionName->mech_type));
+} /* importExportName */
-/* #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.
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;
/*
* call it.
*/
- mech = __gss_get_mechanism (ctx->mech_type);
+ mech = gssint_get_mechanism (ctx->mech_type);
if (!mech) {
status = GSS_S_BAD_MECH;
goto error_out;
}
if (!mech->gss_import_sec_context) {
- status = GSS_S_BAD_BINDINGS;
+ status = GSS_S_UNAVAILABLE;
goto error_out;
}
#endif
#include <string.h>
-extern gss_mechanism *__gss_mechs_array;
+extern gss_mechanism *gssint_mechs_array;
static gss_OID_set_desc supported_mechs_desc;
static gss_OID_set supported_mechs = NULL;
/* Build the mech_set from the OIDs in mechs_array. */
- for(i=0; __gss_mechs_array[i]->mech_type.length != 0; i++)
+ for(i=0; gssint_mechs_array[i]->mech_type.length != 0; i++)
supported_mechs->count++;
supported_mechs->elements =
for(i=0; i < supported_mechs->count; i++) {
supported_mechs->elements[i].length =
- __gss_mechs_array[i]->mech_type.length;
+ gssint_mechs_array[i]->mech_type.length;
supported_mechs->elements[i].elements = (void *)
- malloc(__gss_mechs_array[i]->mech_type.length);
+ malloc(gssint_mechs_array[i]->mech_type.length);
memcpy(supported_mechs->elements[i].elements,
- __gss_mechs_array[i]->mech_type.elements,
- __gss_mechs_array[i]->mech_type.length);
+ gssint_mechs_array[i]->mech_type.elements,
+ gssint_mechs_array[i]->mech_type.length);
}
}
-/* #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,
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;
gss_mechanism mech;
gss_cred_id_t input_cred_handle;
- gss_initialize();
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *minor_status = 0;
output_token->length = 0;
output_token->value = NULL;
+ /* clear output values */
+ if (actual_mech_type)
+ *actual_mech_type = NULL;
+
if (context_handle == NULL)
- return GSS_S_NO_CONTEXT;
+ return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CONTEXT);
union_name = (gss_union_name_t) target_name;
- /*
- * If mech_type is NULL, and the target_name is
- * mechanism-specific, then set it to the mech_type of
- * target_name.
- */
- if ((mech_type == GSS_C_NULL_OID) && union_name->mech_type)
- mech_type = union_name->mech_type;
+ if (target_name == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ if (output_token == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ output_token->value = NULL;
+ output_token->length = 0;
+
+
+ if (req_mech_type)
+ mech_type = (gss_OID)req_mech_type;
+
+ union_name = (gss_union_name_t)target_name;
/*
* obtain the gss mechanism information for the requested
* mechanism. If mech_type is NULL, set it to the resultant
* mechanism
*/
- mech = __gss_get_mechanism (mech_type);
+ mech = gssint_get_mechanism (mech_type);
if (mech == NULL)
return (GSS_S_BAD_MECH);
+ if (mech->gss_init_sec_context == NULL)
+ return (GSS_S_UNAVAILABLE);
+
if (mech_type == GSS_C_NULL_OID)
mech_type = &mech->mech_type;
* mech_type that we're about to use. Otherwise, do an import on
* the external_name form of the target name.
*/
- if (union_name->mech_type) {
- if (!g_OID_equal(union_name->mech_type, mech_type))
- return (GSS_S_BAD_MECH);
+ if (union_name->mech_type &&
+ g_OID_equal(union_name->mech_type, mech_type)) {
internal_name = union_name->mech_name;
} else {
- if ((temp_status = __gss_import_internal_name(minor_status, mech_type,
- union_name,
- &internal_name)))
- return (GSS_S_BAD_NAME);
+ if ((status = gssint_import_internal_name(minor_status, mech_type,
+ union_name,
+ &internal_name)) != GSS_S_COMPLETE)
+ return (status);
}
/*
*/
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;
* use the default credential.
*/
union_cred = (gss_union_cred_t) claimant_cred_handle;
- input_cred_handle = __gss_get_mechanism_cred(union_cred, mech_type);
+ input_cred_handle = gssint_get_mechanism_cred(union_cred, mech_type);
/*
* now call the approprate underlying mechanism routine
*/
- if (mech->gss_init_sec_context) {
- status = mech->gss_init_sec_context(
- mech->context,
- minor_status,
- input_cred_handle,
- &union_ctx_id->internal_ctx_id,
- internal_name,
- mech_type,
- req_flags,
- time_req,
- input_chan_bindings,
- input_token,
- actual_mech_type,
- output_token,
- ret_flags,
- time_rec);
-
- if (*context_handle == GSS_C_NO_CONTEXT)
- *context_handle = (gss_ctx_id_t) union_ctx_id;
-
- } else
- status = GSS_S_BAD_BINDINGS;
-
- if (!union_name->mech_type) {
- (void) __gss_release_internal_name(&temp_minor_status,
+ status = mech->gss_init_sec_context(
+ mech->context,
+ minor_status,
+ input_cred_handle,
+ &union_ctx_id->internal_ctx_id,
+ internal_name,
+ mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec);
+
+ if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) {
+ /*
+ * the spec says (the preferred) method is to delete all
+ * context info on the first call to init, and on all
+ * subsequent calls make the caller responsible for
+ * calling gss_delete_sec_context
+ */
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ free(union_ctx_id->mech_type->elements);
+ free(union_ctx_id->mech_type);
+ free(union_ctx_id);
+ }
+ } else if (*context_handle == GSS_C_NO_CONTEXT)
+ *context_handle = (gss_ctx_id_t)union_ctx_id;
+
+end:
+ if (union_name->mech_name == NULL ||
+ union_name->mech_name != internal_name) {
+ (void) gssint_release_internal_name(&temp_minor_status,
mech_type, &internal_name);
}
-/* #ident "@(#)g_initialize.c 1.2 96/02/06 SMI" */
+/* #pragma ident "@(#)g_initialize.c 1.36 05/02/02 SMI" */
/*
* Copyright 1996 by Sun Microsystems, Inc.
#include <ctype.h>
#include <errno.h>
-#ifdef USE_SOLARIS_SHARED_LIBRARIES
#include <dlfcn.h>
-#define MECH_CONF "/etc/mech.conf"
+#define MECH_CONF "/etc/gss/mech"
+
+#define MECH_LIB_PREFIX1 "/usr/lib/"
+
+#define MECH_LIB_PREFIX2 ""
+
+#define MECH_LIB_DIR "gss/"
+
+#define MECH_LIB_PREFIX MECH_LIB_PREFIX1 MECH_LIB_PREFIX2 MECH_LIB_DIR
+
#define MECH_SYM "gss_mech_initialize"
-static void solaris_initialize (void);
-#endif /* USE_SOLARIS_SHARED_LIBRARIES */
+#define M_DEFAULT "default"
+
+#include <sys/stat.h>
+
+#include "k5-thread.h"
+
+/* Local functions */
+static gss_mech_info searchMechList(const gss_OID);
+static void loadConfigFile(const char *);
+static void updateMechList(void);
+static void register_mech(gss_mechanism, const char *, void *);
+
+static OM_uint32 build_mechSet(void);
+static void init_hardcoded(void);
+
+/*
+ * list of mechanism libraries and their entry points.
+ * the list also maintains state of the mech libraries (loaded or not).
+ */
+static gss_mech_info g_mechList = NULL;
+static gss_mech_info g_mechListTail = NULL;
+static k5_mutex_t g_mechListLock = K5_MUTEX_PARTIAL_INITIALIZER;
+static time_t g_confFileModTime = (time_t)0;
+
+static time_t g_mechSetTime = (time_t)0;
+static gss_OID_set_desc g_mechSet = { 0, NULL };
+static k5_mutex_t g_mechSetLock = K5_MUTEX_PARTIAL_INITIALIZER;
+
+int
+gssint_mechglue_init(void)
+{
+ int err;
-#define g_OID_equal(o1,o2) \
- (((o1)->length == (o2)->length) && \
- (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0))
+ err = k5_mutex_finish_init(&g_mechSetLock);
+ return k5_mutex_finish_init(&g_mechListLock);
+}
-extern gss_mechanism krb5_gss_initialize();
+void
+gssint_mechglue_fini(void)
+{
+ k5_mutex_destroy(&g_mechSetLock);
+ k5_mutex_destroy(&g_mechListLock);
+}
-static int _gss_initialized = 0;
-static struct gss_config null_mech = {
- {0,NULL}};
+/*
+ * function used to reclaim the memory used by a gss_OID structure.
+ * This routine requires direct access to the mechList.
+ */
+OM_uint32 KRB5_CALLCONV
+gss_release_oid(minor_status, oid)
+OM_uint32 *minor_status;
+gss_OID *oid;
+{
+ OM_uint32 major;
+ gss_mech_info aMech;
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *minor_status = 0;
+
+ k5_mutex_lock(&g_mechListLock);
+ aMech = g_mechList;
+ while (aMech != NULL) {
+
+ /*
+ * look through the loaded mechanism libraries for
+ * gss_internal_release_oid until one returns success.
+ * gss_internal_release_oid will only return success when
+ * the OID was recognized as an internal mechanism OID. if no
+ * mechanisms recognize the OID, then call the generic version.
+ */
+ if (aMech->mech && aMech->mech->gss_internal_release_oid) {
+ major = aMech->mech->gss_internal_release_oid(
+ aMech->mech->context,
+ minor_status, oid);
+ if (major == GSS_S_COMPLETE) {
+ k5_mutex_unlock(&g_mechListLock);
+ return (GSS_S_COMPLETE);
+ }
+ }
+ aMech = aMech->next;
+ } /* while */
+ k5_mutex_unlock(&g_mechListLock);
+
+ return (generic_gss_release_oid(minor_status, oid));
+} /* gss_release_oid */
-gss_mechanism *__gss_mechs_array = NULL;
/*
- * This function will add a new mechanism to the mechs_array
+ * this function will return an oid set indicating available mechanisms.
+ * The set returned is based on configuration file entries and
+ * NOT on the loaded mechanisms. This function does not check if any
+ * of these can actually be loaded.
+ * This routine needs direct access to the mechanism list.
+ * To avoid reading the configuration file each call, we will save a
+ * a mech oid set, and only update it once the file has changed.
*/
+OM_uint32 KRB5_CALLCONV
+gss_indicate_mechs(minorStatus, mechSet)
+OM_uint32 *minorStatus;
+gss_OID_set *mechSet;
+{
+ char *fileName;
+ struct stat fileInfo;
+ int i, j;
+ gss_OID curItem;
+
+ if (!minorStatus)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ if (gssint_initialize_library())
+ return GSS_S_FAILURE;
+
+ *minorStatus = 0;
+
+
+ /* check output parameter */
+ if (mechSet == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ fileName = MECH_CONF;
+
+#if 0
+ /*
+ * If we have already computed the mechanisms supported and if it
+ * is still valid; make a copy and return to caller,
+ * otherwise build it first.
+ */
+ if ((stat(fileName, &fileInfo) == 0 &&
+ fileInfo.st_mtime > g_mechSetTime)) {
+ } /* if g_mechSet is out of date or not initialized */
+#endif
+ if (build_mechSet())
+ return GSS_S_FAILURE;
+
+ /*
+ * the mech set is created and it is up to date
+ * so just copy it to caller
+ */
+ if ((*mechSet =
+ (gss_OID_set) malloc(sizeof (gss_OID_set_desc))) == NULL)
+ {
+ return (GSS_S_FAILURE);
+ }
+
+ /*
+ * need to lock the g_mechSet in case someone tries to update it while
+ * I'm copying it.
+ */
+ (void) k5_mutex_lock(&g_mechSetLock);
+
+ /* allocate space for the oid structures */
+ if (((*mechSet)->elements =
+ (void*) calloc(g_mechSet.count, sizeof (gss_OID_desc)))
+ == NULL)
+ {
+ (void) k5_mutex_unlock(&g_mechSetLock);
+ free(*mechSet);
+ *mechSet = NULL;
+ return (GSS_S_FAILURE);
+ }
+
+ /* now copy the oid structures */
+ (void) memcpy((*mechSet)->elements, g_mechSet.elements,
+ g_mechSet.count * sizeof (gss_OID_desc));
+
+ (*mechSet)->count = g_mechSet.count;
+
+ /* still need to copy each of the oid elements arrays */
+ for (i = 0; i < (*mechSet)->count; i++) {
+ curItem = &((*mechSet)->elements[i]);
+ curItem->elements =
+ (void *) malloc(g_mechSet.elements[i].length);
+ if (curItem->elements == NULL) {
+ (void) k5_mutex_unlock(&g_mechSetLock);
+ /*
+ * must still free the allocated elements for
+ * each allocated gss_OID_desc
+ */
+ for (j = 0; j < i; j++) {
+ free((*mechSet)->elements[j].elements);
+ }
+ free((*mechSet)->elements);
+ free(mechSet);
+ *mechSet = NULL;
+ return (GSS_S_FAILURE);
+ }
+ g_OID_copy(curItem, &g_mechSet.elements[i]);
+ }
+ (void) k5_mutex_unlock(&g_mechSetLock);
+ return (GSS_S_COMPLETE);
+} /* gss_indicate_mechs */
+
static OM_uint32
-add_mechanism (mech, replace)
- gss_mechanism mech;
- int replace;
+build_mechSet(void)
{
- gss_mechanism * temp_array;
- gss_OID_set mech_names;
- OM_uint32 minor_status, major_status;
- unsigned int i;
+ gss_mech_info mList;
+ int i, count;
+ gss_OID curItem;
+
+ /*
+ * lock the mutex since we will be updating
+ * the mechList structure
+ * we need to keep the lock while we build the mechanism list
+ * since we are accessing parts of the mechList which could be
+ * modified.
+ */
+ (void) k5_mutex_lock(&g_mechListLock);
+
+#if 0
+ /*
+ * this checks for the case when we need to re-construct the
+ * g_mechSet structure, but the mechanism list is upto date
+ * (because it has been read by someone calling
+ * gssint_get_mechanism)
+ */
+ if (fileInfo.st_mtime > g_confFileModTime)
+ {
+ g_confFileModTime = fileInfo.st_mtime;
+ loadConfigFile(fileName);
+ }
+#endif
+
+ updateMechList();
+
+ /*
+ * we need to lock the mech set so that no one else will
+ * try to read it as we are re-creating it
+ */
+ (void) k5_mutex_lock(&g_mechSetLock);
+
+ /* if the oid list already exists we must free it first */
+ if (g_mechSet.count != 0) {
+ for (i = 0; i < g_mechSet.count; i++)
+ free(g_mechSet.elements[i].elements);
+ free(g_mechSet.elements);
+ g_mechSet.elements = NULL;
+ g_mechSet.count = 0;
+ }
+
+ /* determine how many elements to have in the list */
+ mList = g_mechList;
+ count = 0;
+ while (mList != NULL) {
+ count++;
+ mList = mList->next;
+ }
+
+ /* this should always be true, but.... */
+ if (count > 0) {
+ g_mechSet.elements =
+ (gss_OID) calloc(count, sizeof (gss_OID_desc));
+ if (g_mechSet.elements == NULL) {
+ (void) k5_mutex_unlock(&g_mechSetLock);
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return (GSS_S_FAILURE);
+ }
+
+ (void) memset(g_mechSet.elements, 0,
+ count * sizeof (gss_OID_desc));
+
+ /* now copy each oid element */
+ g_mechSet.count = count;
+ count = 0;
+ mList = g_mechList;
+ while (mList != NULL) {
+ curItem = &(g_mechSet.elements[count]);
+ curItem->elements = (void*)
+ malloc(mList->mech_type->length);
+ if (curItem->elements == NULL) {
+ /*
+ * this is nasty - we must delete the
+ * part of the array already copied
+ */
+ for (i = 0; i < count; i++) {
+ free(g_mechSet.elements[i].
+ elements);
+ }
+ free(g_mechSet.elements);
+ g_mechSet.count = 0;
+ g_mechSet.elements = NULL;
+ (void) k5_mutex_unlock(&g_mechSetLock);
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return (GSS_S_FAILURE);
+ }
+ g_OID_copy(curItem, mList->mech_type);
+ count++;
+ mList = mList->next;
+ }
+ }
+
+#if 0
+ g_mechSetTime = fileInfo.st_mtime;
+#endif
+ (void) k5_mutex_unlock(&g_mechSetLock);
+ (void) k5_mutex_unlock(&g_mechListLock);
- if (mech == NULL)
return GSS_S_COMPLETE;
+}
- /* initialize the mechs_array if it hasn't already been initialized */
- if (__gss_mechs_array == NULL) {
- __gss_mechs_array = (gss_mechanism *) malloc (sizeof(gss_mechanism));
- if (__gss_mechs_array == NULL)
- return ENOMEM;
+/*
+ * this function has been added for use by modules that need to
+ * know what (if any) optional parameters are supplied in the
+ * config file (MECH_CONF).
+ * It will return the option string for a specified mechanism.
+ * caller is responsible for freeing the memory
+ */
+char *
+gssint_get_modOptions(oid)
+const gss_OID oid;
+{
+ gss_mech_info aMech;
+ char *modOptions = NULL;
- __gss_mechs_array[0] = &null_mech;
- }
+ /* make sure we have fresh data */
+ (void) k5_mutex_lock(&g_mechListLock);
+ updateMechList();
- /*
- * Find the length of __gss_mechs_array, and look for an existing
- * entry for this OID
- */
- for (i=0; __gss_mechs_array[i]->mech_type.length != 0; i++) {
- if (!g_OID_equal(&__gss_mechs_array[i]->mech_type,
- &mech->mech_type))
- continue;
+ if ((aMech = searchMechList(oid)) == NULL ||
+ aMech->optionStr == NULL) {
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return (NULL);
+ }
- /* We found a match. Replace it? */
- if (!replace)
- return GSS_S_FAILURE;
+ if (aMech->optionStr)
+ modOptions = strdup(aMech->optionStr);
+ (void) k5_mutex_unlock(&g_mechListLock);
- __gss_mechs_array[i] = mech;
- return GSS_S_COMPLETE;
- }
+ return (modOptions);
+} /* gssint_get_modOptions */
- /* we didn't find it -- add it to the end of the __gss_mechs_array */
- temp_array = (gss_mechanism *) realloc(__gss_mechs_array,
- (i+2)*sizeof(gss_mechanism));
+/*
+ * given a mechanism string return the mechanism oid
+ */
+OM_uint32
+gssint_mech_to_oid(const char *mechStr, gss_OID* oid)
+{
+ gss_mech_info aMech;
- if (temp_array == NULL)
- return ENOMEM;
+ if (oid == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
- temp_array[i++] = mech;
- temp_array[i] = &null_mech;
+ *oid = GSS_C_NULL_OID;
- __gss_mechs_array = temp_array;
+ if ((mechStr == NULL) || (strlen(mechStr) == 0) ||
+ (strcasecmp(mechStr, M_DEFAULT) == 0))
+ return (GSS_S_COMPLETE);
- /*
- * OK, now let's register all of the name types this mechanism
- * knows how to deal with.
- */
- major_status = gss_inquire_names_for_mech(&minor_status, &mech->mech_type,
- &mech_names);
- if (major_status != GSS_S_COMPLETE)
- return (GSS_S_COMPLETE);
- for (i=0; i < mech_names->count; i++) {
- gss_add_mech_name_type(&minor_status, &mech_names->elements[i],
- &mech->mech_type);
- }
- (void) gss_release_oid_set(&minor_status, &mech_names);
+ /* ensure we have fresh data */
+ (void) k5_mutex_lock(&g_mechListLock);
+ updateMechList();
+ (void) k5_mutex_unlock(&g_mechListLock);
+
+ aMech = g_mechList;
+
+ /* no lock required - only looking at fields that are not updated */
+ while (aMech != NULL) {
+ if ((aMech->mechNameStr) &&
+ strcmp(aMech->mechNameStr, mechStr) == 0) {
+ *oid = aMech->mech_type;
+ return (GSS_S_COMPLETE);
+ }
+ aMech = aMech->next;
+ }
+ return (GSS_S_FAILURE);
+} /* gssint_mech_to_oid */
- return GSS_S_COMPLETE;
-}
-void gss_initialize ()
+/*
+ * Given the mechanism oid, return the readable mechanism name
+ * associated with that oid from the mech config file
+ * (/etc/gss/mech).
+ */
+const char *
+gssint_oid_to_mech(const gss_OID oid)
{
- gss_mechanism mech;
+ gss_mech_info aMech;
- /* Make sure we've not run already */
- if (_gss_initialized)
- return;
- _gss_initialized = 1;
+ if (oid == GSS_C_NULL_OID)
+ return (M_DEFAULT);
-#ifdef USE_SOLARIS_SHARED_LIBRARIES
- solaris_initialize();
+ /* ensure we have fresh data */
+ (void) k5_mutex_lock(&g_mechListLock);
+ updateMechList();
+ aMech = searchMechList(oid);
+ (void) k5_mutex_unlock(&g_mechListLock);
-#else
- /*
- * Use hard-coded in mechanisms... I need to know what mechanisms
- * are supported... As more mechanisms become supported, they
- * should be added here, unless shared libraries are used.
- */
+ if (aMech == NULL)
+ return (NULL);
- /* Initialize the krb5 mechanism */
- mech = (gss_mechanism)krb5_gss_initialize();
- if (mech)
- add_mechanism (mech, 1);
+ return (aMech->mechNameStr);
+} /* gssint_oid_to_mech */
-#endif /* USE_SOLARIS_SHARED_LIBRARIES */
- if (__gss_mechs_array == NULL) { /* this is very bad! */
- fprintf(stderr,"gss_initialize fatal error: no mechanisms loaded!\n");
- exit(-1);
- }
+/*
+ * return a list of mechanism strings supported
+ * upon return the array is terminated with a NULL entry
+ */
+OM_uint32
+gssint_get_mechanisms(char *mechArray[], int arrayLen)
+{
+ gss_mech_info aMech;
+ int i;
+
+ if (gssint_initialize_library())
+ return GSS_S_FAILURE;
+ if (mechArray == NULL || arrayLen < 1)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ /* ensure we have fresh data */
+ (void) k5_mutex_lock(&g_mechListLock);
+ updateMechList();
+ (void) k5_mutex_unlock(&g_mechListLock);
+
+ aMech = g_mechList;
+
+ /* no lock required - only looking at fields that are not updated */
+ for (i = 1; i < arrayLen; i++) {
+ if (aMech != NULL) {
+ *mechArray = aMech->mechNameStr;
+ mechArray++;
+ aMech = aMech->next;
+ } else
+ break;
+ }
+ *mechArray = NULL;
+ return (GSS_S_COMPLETE);
+} /* gss_get_mechanisms */
- return;
+
+/*
+ * determines if the mechList needs to be updated from file
+ * and performs the update.
+ * this functions must be called with a lock of g_mechListLock
+ */
+static void
+updateMechList(void)
+{
+ char *fileName;
+ struct stat fileInfo;
+
+ init_hardcoded();
+ fileName = MECH_CONF;
+
+#if 0
+ /* check if mechList needs updating */
+ if (stat(fileName, &fileInfo) == 0 &&
+ (fileInfo.st_mtime > g_confFileModTime)) {
+ loadConfigFile(fileName);
+ g_confFileModTime = fileInfo.st_mtime;
+ }
+#endif
+} /* updateMechList */
+
+/*
+ * Register a mechanism. Called with g_mechListLock held.
+ */
+static void
+register_mech(gss_mechanism mech, const char *namestr, void *dl_handle)
+{
+ gss_mech_info cf, new_cf;
+
+ new_cf = malloc(sizeof(*new_cf));
+ if (new_cf == NULL)
+ return;
+
+ memset(new_cf, 0, sizeof(*new_cf));
+ new_cf->kmodName = NULL;
+ new_cf->uLibName = strdup(namestr);
+ new_cf->mechNameStr = strdup(mech->mechNameStr);
+ new_cf->mech_type = &mech->mech_type;
+ new_cf->mech = mech;
+ new_cf->next = NULL;
+
+ if (g_mechList == NULL) {
+ g_mechList = new_cf;
+ g_mechListTail = new_cf;
+ return;
+ } else if (mech->priority < g_mechList->mech->priority) {
+ new_cf->next = g_mechList;
+ g_mechList = new_cf;
+ return;
+ }
+ for (cf = g_mechList; cf != NULL; cf = cf->next) {
+ if (cf->next == NULL ||
+ mech->priority < cf->next->mech->priority) {
+ new_cf->next = cf->next;
+ cf->next = new_cf;
+ if (g_mechListTail == cf) {
+ g_mechListTail = new_cf;
+ }
+ break;
+ }
+ }
}
-#ifdef USE_SOLARIS_SHARED_LIBRARIES
-/*
- * read the configuration file to find out what mechanisms to
- * load, load them, and then load the mechanism defitions in
- * and add the mechanisms
+/*
+ * Initialize the hardcoded mechanisms. This function is called with
+ * g_mechListLock held.
*/
-static void solaris_initialize ()
+static void
+init_hardcoded(void)
{
- char buffer[BUFSIZ], *filename, *symname, *endp;
- FILE *conffile;
- void *dl;
- gss_mechanism (*sym)(void), mech;
+ extern gss_mechanism *krb5_gss_get_mech_configs(void);
+ extern gss_mechanism *spnego_gss_get_mech_configs(void);
+ gss_mechanism *cflist;
+ static int inited;
+ gss_mech_info cf;
+
+ if (inited)
+ return;
+
+ cflist = krb5_gss_get_mech_configs();
+ if (cflist == NULL)
+ return;
+ for ( ; *cflist != NULL; cflist++) {
+ register_mech(*cflist, "<builtin krb5>", NULL);
+ }
+ cflist = spnego_gss_get_mech_configs();
+ if (cflist == NULL)
+ return;
+ for ( ; *cflist != NULL; cflist++) {
+ register_mech(*cflist, "<builtin spnego>", NULL);
+ }
+ inited = 1;
+}
- if ((filename = getenv("GSSAPI_MECH_CONF")) == NULL)
- filename = MECH_CONF;
- if ((conffile = fopen(filename, "r")) == NULL)
- return;
+/*
+ * given the mechanism type, return the mechanism structure
+ * containing the mechanism library entry points.
+ * will return NULL if mech type is not found
+ * This function will also trigger the loading of the mechanism
+ * module if it has not been already loaded.
+ */
+gss_mechanism
+gssint_get_mechanism(oid)
+const gss_OID oid;
+{
+ gss_mech_info aMech;
+ gss_mechanism (*sym)(const gss_OID);
+ void *dl;
+
+ if (gssint_initialize_library())
+ return NULL;
+
+ (void) k5_mutex_lock(&g_mechListLock);
+ /* check if the mechanism is already loaded */
+ if ((aMech = searchMechList(oid)) != NULL && aMech->mech) {
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return (aMech->mech);
+ }
- while (fgets (buffer, BUFSIZ, conffile) != NULL) {
- /* ignore lines beginning with # */
- if (*buffer == '#')
- continue;
+ /*
+ * might need to re-read the configuration file before loading
+ * the mechanism to ensure we have the latest info.
+ */
+ updateMechList();
- /* find the first white-space character after the filename */
- for (symname = buffer; *symname && !isspace(*symname); symname++);
+ aMech = searchMechList(oid);
- /* Now find the first non-white-space character */
- if (*symname) {
- *symname = '\0';
- symname++;
- while (*symname && isspace(*symname))
- symname++;
+ /* is the mechanism present in the list ? */
+ if (aMech == NULL) {
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return ((gss_mechanism)NULL);
}
- if (! *symname)
- symname = MECH_SYM;
- else {
- /* Find the end of the symname and make sure it is NULL-terminated */
- for (endp = symname; *endp && !isspace(*endp); endp++);
- if (*endp)
- *endp = '\0';
+ /* has another thread loaded the mech */
+ if (aMech->mech) {
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return (aMech->mech);
}
- if ((dl = dlopen(buffer, RTLD_NOW)) == NULL) {
- /* for debugging only */
- fprintf(stderr,"can't open %s: %s\n",buffer, dlerror());
- continue;
+ /* we found the mechanism, but it is not loaded */
+ if ((dl = dlopen(aMech->uLibName, RTLD_NOW)) == NULL) {
+#if 0
+ (void) syslog(LOG_INFO, "libgss dlopen(%s): %s\n",
+ aMech->uLibName, dlerror());
+#endif
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return ((gss_mechanism)NULL);
}
- if ((sym = (gss_mechanism (*)(void))dlsym(dl, symname)) == NULL) {
- dlclose(dl);
- continue;
+ if ((sym = (gss_mechanism (*)(const gss_OID))dlsym(dl, MECH_SYM))
+ == NULL) {
+ (void) dlclose(dl);
+#if 0
+ (void) syslog(LOG_INFO, "unable to initialize mechanism"
+ " library [%s]\n", aMech->uLibName);
+#endif
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return ((gss_mechanism)NULL);
}
/* Call the symbol to get the mechanism table */
- mech = sym();
+ aMech->mech = (*sym)(aMech->mech_type);
+
+ if (aMech->mech == NULL) {
+ (void) dlclose(dl);
+#if 0
+ (void) syslog(LOG_INFO, "unable to initialize mechanism"
+ " library [%s]\n", aMech->uLibName);
+#endif
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return ((gss_mechanism)NULL);
+ }
+
+ aMech->dl_handle = dl;
+
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return (aMech->mech);
+} /* gssint_get_mechanism */
- /* And add the mechanism (or close the shared library) */
- if (mech)
- add_mechanism (mech, 1);
+gss_mechanism_ext
+gssint_get_mechanism_ext(oid)
+const gss_OID oid;
+{
+ gss_mech_info aMech;
+ gss_mechanism_ext mech_ext;
+
+ /* check if the mechanism is already loaded */
+ if ((aMech = searchMechList(oid)) != NULL && aMech->mech_ext != NULL)
+ return (aMech->mech_ext);
+
+ if (gssint_get_mechanism(oid) == NULL)
+ return (NULL);
+
+ if (aMech->dl_handle == NULL)
+ return (NULL);
+
+ /* Load the gss_config_ext struct for this mech */
+
+ mech_ext = (gss_mechanism_ext)malloc(sizeof (struct gss_config_ext));
+
+ if (mech_ext == NULL)
+ return (NULL);
+
+ /*
+ * dlsym() the mech's 'method' functions for the extended APIs
+ *
+ * NOTE: Until the void *context argument is removed from the
+ * SPI method functions' signatures it will be necessary to have
+ * different function pointer typedefs and function names for
+ * the SPI methods than for the API. When this argument is
+ * removed it will be possible to rename gss_*_sfct to gss_*_fct
+ * and and gssspi_* to gss_*.
+ */
+ mech_ext->gss_acquire_cred_with_password =
+ (gss_acquire_cred_with_password_sfct)dlsym(aMech->dl_handle,
+ "gssspi_acquire_cred_with_password");
+
+ /* Set aMech->mech_ext */
+ (void) k5_mutex_lock(&g_mechListLock);
+
+ if (aMech->mech_ext == NULL)
+ aMech->mech_ext = mech_ext;
else
- dlclose(dl);
+ free(mech_ext); /* we raced and lost; don't leak */
- } /* while */
+ (void) k5_mutex_unlock(&g_mechListLock);
- return;
-}
-#endif /* USE_SOLARIS_SHARED_LIBRARIES */
+ return (aMech->mech_ext);
+
+} /* gssint_get_mechanism_ext */
+
+
+/*
+ * this routine is used for searching the list of mechanism data.
+ *
+ * this needs to be called with g_mechListLock held.
+ */
+static gss_mech_info searchMechList(oid)
+const gss_OID oid;
+{
+ gss_mech_info aMech = g_mechList;
+
+ /* if oid is null -> then get default which is the first in the list */
+ if (oid == GSS_C_NULL_OID)
+ return (aMech);
+
+ while (aMech != NULL) {
+ if (g_OID_equal(aMech->mech_type, oid))
+ return (aMech);
+ aMech = aMech->next;
+ }
+
+ /* none found */
+ return ((gss_mech_info) NULL);
+} /* searchMechList */
+
+
+/*
+ * loads the configuration file
+ * this is called while having a mutex lock on the mechanism list
+ * entries for libraries that have been loaded can't be modified
+ * mechNameStr and mech_type fields are not updated during updates
+ */
+static void loadConfigFile(fileName)
+const char *fileName;
+{
+ char buffer[BUFSIZ], *oidStr, *oid, *sharedLib, *kernMod, *endp;
+ char *modOptions;
+ char sharedPath[sizeof (MECH_LIB_PREFIX) + BUFSIZ];
+ char *tmpStr;
+ FILE *confFile;
+ gss_OID mechOid;
+ gss_mech_info aMech, tmp;
+ OM_uint32 minor;
+ gss_buffer_desc oidBuf;
+
+ if ((confFile = fopen(fileName, "r")) == NULL) {
+ return;
+ }
+
+ (void) memset(buffer, 0, sizeof (buffer));
+ while (fgets(buffer, BUFSIZ, confFile) != NULL) {
+
+ /* ignore lines beginning with # */
+ if (*buffer == '#')
+ continue;
+
+ /*
+ * find the first white-space character after
+ * the mechanism name
+ */
+ oidStr = buffer;
+ for (oid = buffer; *oid && !isspace(*oid); oid++);
+
+ /* Now find the first non-white-space character */
+ if (*oid) {
+ *oid = '\0';
+ oid++;
+ while (*oid && isspace(*oid))
+ oid++;
+ }
+
+ /*
+ * If that's all, then this is a corrupt entry. Skip it.
+ */
+ if (! *oid)
+ continue;
+
+ /* Find the end of the oid and make sure it is NULL-ended */
+ for (endp = oid; *endp && !isspace(*endp); endp++)
+ ;
+
+ if (*endp) {
+ *endp = '\0';
+ }
+
+ /*
+ * check if an entry for this oid already exists
+ * if it does, and the library is already loaded then
+ * we can't modify it, so skip it
+ */
+ oidBuf.value = (void *)oid;
+ oidBuf.length = strlen(oid);
+ if (generic_gss_str_to_oid(&minor, &oidBuf, &mechOid)
+ != GSS_S_COMPLETE) {
+#if 0
+ (void) syslog(LOG_INFO, "invalid mechanism oid"
+ " [%s] in configuration file", oid);
+#endif
+ continue;
+ }
+
+ k5_mutex_lock(&g_mechListLock);
+ aMech = searchMechList(mechOid);
+ if (aMech && aMech->mech) {
+ free(mechOid->elements);
+ free(mechOid);
+ k5_mutex_unlock(&g_mechListLock);
+ continue;
+ }
+ k5_mutex_unlock(&g_mechListLock);
+
+ /* Find the start of the shared lib name */
+ for (sharedLib = endp+1; *sharedLib && isspace(*sharedLib);
+ sharedLib++)
+ ;
+
+ /*
+ * If that's all, then this is a corrupt entry. Skip it.
+ */
+ if (! *sharedLib) {
+ free(mechOid->elements);
+ free(mechOid);
+ continue;
+ }
+
+ /*
+ * Find the end of the shared lib name and make sure it is
+ * NULL-terminated.
+ */
+ for (endp = sharedLib; *endp && !isspace(*endp); endp++)
+ ;
+
+ if (*endp) {
+ *endp = '\0';
+ }
+
+ /* Find the start of the optional kernel module lib name */
+ for (kernMod = endp+1; *kernMod && isspace(*kernMod);
+ kernMod++)
+ ;
+
+ /*
+ * If this item starts with a bracket "[", then
+ * it is not a kernel module, but is a list of
+ * options for the user module to parse later.
+ */
+ if (*kernMod && *kernMod != '[') {
+ /*
+ * Find the end of the shared lib name and make sure
+ * it is NULL-terminated.
+ */
+ for (endp = kernMod; *endp && !isspace(*endp); endp++)
+ ;
+
+ if (*endp) {
+ *endp = '\0';
+ }
+ } else
+ kernMod = NULL;
+
+ /* Find the start of the optional module options list */
+ for (modOptions = endp+1; *modOptions && isspace(*modOptions);
+ modOptions++);
+
+ if (*modOptions == '[') {
+ /* move past the opening bracket */
+ for (modOptions = modOptions+1;
+ *modOptions && isspace(*modOptions);
+ modOptions++);
+
+ /* Find the closing bracket */
+ for (endp = modOptions;
+ *endp && *endp != ']'; endp++);
+
+ if (endp)
+ *endp = '\0';
+
+ } else {
+ modOptions = NULL;
+ }
+
+ (void) strcpy(sharedPath, MECH_LIB_PREFIX);
+ (void) strcat(sharedPath, sharedLib);
+
+ /*
+ * are we creating a new mechanism entry or
+ * just modifying existing (non loaded) mechanism entry
+ */
+ if (aMech) {
+ /*
+ * delete any old values and set new
+ * mechNameStr and mech_type are not modified
+ */
+ if (aMech->kmodName) {
+ free(aMech->kmodName);
+ aMech->kmodName = NULL;
+ }
+
+ if (aMech->optionStr) {
+ free(aMech->optionStr);
+ aMech->optionStr = NULL;
+ }
+
+ if ((tmpStr = strdup(sharedPath)) != NULL) {
+ if (aMech->uLibName)
+ free(aMech->uLibName);
+ aMech->uLibName = tmpStr;
+ }
+
+ if (kernMod) /* this is an optional parameter */
+ aMech->kmodName = strdup(kernMod);
+
+ if (modOptions) /* optional module options */
+ aMech->optionStr = strdup(modOptions);
+
+ /* the oid is already set */
+ free(mechOid->elements);
+ free(mechOid);
+ continue;
+ }
+
+ /* adding a new entry */
+ aMech = malloc(sizeof (struct gss_mech_config));
+ if (aMech == NULL) {
+ free(mechOid->elements);
+ free(mechOid);
+ continue;
+ }
+ (void) memset(aMech, 0, sizeof (struct gss_mech_config));
+ aMech->mech_type = mechOid;
+ aMech->uLibName = strdup(sharedPath);
+ aMech->mechNameStr = strdup(oidStr);
+
+ /* check if any memory allocations failed - bad news */
+ if (aMech->uLibName == NULL || aMech->mechNameStr == NULL) {
+ if (aMech->uLibName)
+ free(aMech->uLibName);
+ if (aMech->mechNameStr)
+ free(aMech->mechNameStr);
+ free(mechOid->elements);
+ free(mechOid);
+ free(aMech);
+ continue;
+ }
+ if (kernMod) /* this is an optional parameter */
+ aMech->kmodName = strdup(kernMod);
+
+ if (modOptions)
+ aMech->optionStr = strdup(modOptions);
+ /*
+ * add the new entry to the end of the list - make sure
+ * that only complete entries are added because other
+ * threads might currently be searching the list.
+ */
+ tmp = g_mechListTail;
+ g_mechListTail = aMech;
+
+ if (tmp != NULL)
+ tmp->next = aMech;
+
+ if (g_mechList == NULL)
+ g_mechList = aMech;
+ } /* while */
+ (void) fclose(confFile);
+} /* loadConfigFile */
-/* #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.
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
*/
ctx = (gss_union_ctx_id_t) context_handle;
- mech = __gss_get_mechanism (ctx->mech_type);
+ mech = gssint_get_mechanism (ctx->mech_type);
- if (!mech || !mech->gss_inquire_context || !mech->gss_display_name) {
- return(GSS_S_NO_CONTEXT);
-
+ if (!mech || !mech->gss_inquire_context || !mech->gss_display_name ||
+ !mech->gss_release_name) {
+ return (GSS_S_UNAVAILABLE);
}
status = mech->gss_inquire_context(
mech->context,
minor_status,
ctx->internal_ctx_id,
- src_name,
- targ_name,
+ (src_name ? &localSourceName : NULL),
+ (targ_name ? &localTargName : NULL),
lifetime_rec,
- mech_type,
+ NULL,
ctx_flags,
locally_initiated,
open);
/* need to convert names */
if (src_name) {
- status = __gss_convert_name_to_union_name(minor_status, mech,
- *src_name, src_name);
+ status = gssint_convert_name_to_union_name(minor_status, mech,
+ localSourceName, src_name);
if (status != GSS_S_COMPLETE) {
- (void) mech->gss_release_name(mech->context,
- &temp_minor, src_name);
- (void) mech->gss_release_name(mech->context,
- &temp_minor, targ_name);
- if (mech_type) {
- gss_release_oid(&temp_minor, mech_type);
- }
- return (GSS_S_FAILURE);
+ if (localTargName)
+ mech->gss_release_name(mech->context,
+ &temp_minor, &localTargName);
+ return (status);
}
}
if (targ_name) {
- status = __gss_convert_name_to_union_name(minor_status, mech,
- *targ_name, targ_name);
+ status = gssint_convert_name_to_union_name(minor_status, mech,
+ localTargName, targ_name);
if (status != GSS_S_COMPLETE) {
- if (mech_type) {
- gss_release_oid(&temp_minor, mech_type);
- }
- return (GSS_S_FAILURE);
+ if (src_name)
+ (void) gss_release_name(&temp_minor, src_name);
+
+ return (status);
}
}
+ /* spec says mech type must point to static storage */
+ if (mech_type)
+ *mech_type = &mech->mech_type;
return(GSS_S_COMPLETE);
}
-/* #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.
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) {
/*
* array, which becomes the default mechanism.
*/
- if ((mech = __gss_get_mechanism(GSS_C_NULL_OID)) == NULL)
- return(GSS_S_NO_CRED);
+ if ((mech = gssint_get_mechanism(GSS_C_NULL_OID)) == NULL)
+ return (GSS_S_DEFECTIVE_CREDENTIAL);
if (!mech->gss_inquire_cred)
- return (GSS_S_FAILURE);
+ return (GSS_S_UNAVAILABLE);
status = mech->gss_inquire_cred(mech->context, minor_status,
GSS_C_NO_CREDENTIAL,
/*
* Convert internal_name into a union_name equivalent.
*/
- status = __gss_convert_name_to_union_name(&temp_minor_status,
+ status = gssint_convert_name_to_union_name(&temp_minor_status,
mech, internal_name,
name);
if (status != GSS_S_COMPLETE) {
- if (minor_status)
- *minor_status = temp_minor_status;
- __gss_release_internal_name(&temp_minor_status,
- &mech->mech_type, &internal_name);
+ *minor_status = temp_minor_status;
+ if (mechanisms && *mechanisms) {
+ (void) gss_release_oid_set(
+ &temp_minor_status,
+ mechanisms);
+ }
return (status);
}
}
* 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
gss_union_cred_t union_cred;
gss_cred_id_t mech_cred;
gss_mechanism mech;
+ OM_uint32 status, temp_minor_status;
+ gss_name_t internal_name;
+
- mech = __gss_get_mechanism (mech_type);
+ mech = gssint_get_mechanism (mech_type);
if (!mech)
return (GSS_S_BAD_MECH);
if (!mech->gss_inquire_cred_by_mech)
return (GSS_S_BAD_BINDINGS);
union_cred = (gss_union_cred_t) cred_handle;
- mech_cred = __gss_get_mechanism_cred(union_cred, mech_type);
+ mech_cred = gssint_get_mechanism_cred(union_cred, mech_type);
+
+#if 0
+ if (mech_cred == NULL)
+ return (GSS_S_DEFECTIVE_CREDENTIAL);
+#endif
+
+ status = mech->gss_inquire_cred_by_mech(mech->context, minor_status,
+ mech_cred, mech_type,
+ name ? &internal_name : NULL,
+ initiator_lifetime,
+ acceptor_lifetime, cred_usage);
+
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ if (name) {
+ /*
+ * Convert internal_name into a union_name equivalent.
+ */
+ status = gssint_convert_name_to_union_name(
+ &temp_minor_status, mech,
+ internal_name, name);
+ if (status != GSS_S_COMPLETE) {
+ *minor_status = temp_minor_status;
+ return (status);
+ }
+ }
- return (mech->gss_inquire_cred_by_mech(mech->context, minor_status,
- mech_cred, mech_type,
- name, initiator_lifetime,
- acceptor_lifetime, cred_usage));
+ return (GSS_S_COMPLETE);
}
-/* #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.
#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)
OM_uint32 status;
gss_mechanism mech;
- gss_initialize();
-
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *minor_status = 0;
+
+ if (name_types == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
/*
* select the approprate underlying mechanism routine and
* call it.
*/
- mech = __gss_get_mechanism (mechanism);
+ mech = gssint_get_mechanism (mechanism);
if (mech) {
mechanism,
name_types);
else
- status = GSS_S_BAD_BINDINGS;
+ status = GSS_S_UNAVAILABLE;
return(status);
}
- return(GSS_S_NO_CONTEXT);
+ return (GSS_S_BAD_MECH);
+}
+OM_uint32 KRB5_CALLCONV
+gss_inquire_mechs_for_name(minor_status, input_name, mech_set)
+
+ OM_uint32 * minor_status;
+ const gss_name_t input_name;
+ gss_OID_set * mech_set;
+
+{
+ OM_uint32 status;
+ static char *mech_list[MAX_MECH_OID_PAIRS+1];
+ gss_OID_set mech_name_types;
+ int present;
+ char *mechanism;
+ gss_OID mechOid;
+ gss_OID name_type;
+ gss_buffer_desc name_buffer;
+ int i;
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *minor_status = 0;
+
+ if (input_name == NULL)
+ return (GSS_S_BAD_NAME);
+
+ status = gss_create_empty_oid_set(minor_status, mech_set);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+ *mech_list = NULL;
+ status = gssint_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+ for (i = 0; i < MAX_MECH_OID_PAIRS && mech_list[i] != NULL; i++) {
+ mechanism = mech_list[i];
+ if (gssint_mech_to_oid(mechanism, &mechOid) == GSS_S_COMPLETE) {
+ status = gss_inquire_names_for_mech(
+ minor_status,
+ mechOid,
+ &mech_name_types);
+ if (status == GSS_S_COMPLETE) {
+ status = gss_display_name(minor_status,
+ input_name,
+ &name_buffer,
+ &name_type);
+
+ (void) gss_release_buffer(NULL, &name_buffer);
+
+ if (status == GSS_S_COMPLETE && name_type) {
+ status = gss_test_oid_set_member(
+ minor_status,
+ name_type,
+ mech_name_types,
+ &present);
+ if (status == GSS_S_COMPLETE &&
+ present) {
+ status = gss_add_oid_set_member(
+ minor_status,
+ mechOid,
+ mech_set);
+ if (status != GSS_S_COMPLETE) {
+ (void) gss_release_oid_set(
+ minor_status,
+ &mech_name_types);
+ (void) gss_release_oid_set(
+ minor_status,
+ mech_set);
+ return (status);
+ }
+ }
+ }
+ (void) gss_release_oid_set(
+ minor_status,
+ &mech_name_types);
+ }
+ } else {
+ (void) gss_release_oid_set(
+ minor_status,
+ mech_set);
+ return (GSS_S_FAILURE);
+ }
+ }
+ return (GSS_S_COMPLETE);
}
#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;
/*
+/* #pragma ident "@(#)g_oid_ops.c 1.11 98/01/22 SMI" */
/*
* lib/gssapi/mechglue/g_oid_ops.c
*
#include "mglueP.h"
/* should include to get protos #include "../generic/gssapiP_generic.h" */
-extern gss_mechanism *__gss_mechs_array;
+extern gss_mechanism *gssint_mechs_array;
-OM_uint32 KRB5_CALLCONV
-gss_release_oid(minor_status, oid)
- OM_uint32 *minor_status;
- gss_OID *oid;
-{
- int i;
- OM_uint32 major_status;
-
- /* first call the gss_internal_release_oid for each mechanism
- * until one returns success. gss_internal_release_oid will only return
- * success when the OID was recognized as an internal mechanism OID.
- * if no mechanisms recognize the OID, then call the generic version.
- */
-
- for(i=0; __gss_mechs_array[i]->mech_type.length !=0; i++) {
- if (__gss_mechs_array[i]->gss_internal_release_oid) {
- major_status = __gss_mechs_array[i]->gss_internal_release_oid(
- __gss_mechs_array[i]->context,
- minor_status,
- oid);
- if (major_status == GSS_S_COMPLETE) {
- return (GSS_S_COMPLETE);
- }
- }
- }
-
- return generic_gss_release_oid(minor_status, oid);
-}
+/*
+ * gss_release_oid has been moved to g_initialize, becasue it requires access
+ * to the mechanism list. All functions requiring direct access to the
+ * mechanism list are now in g_initialize.c
+ */
OM_uint32 KRB5_CALLCONV
gss_create_empty_oid_set(minor_status, oid_set)
-/* #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.
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
*/
ctx = (gss_union_ctx_id_t) context_handle;
- mech = __gss_get_mechanism (ctx->mech_type);
+ mech = gssint_get_mechanism (ctx->mech_type);
if (mech) {
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);
}
-/* #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.
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
union_cred = (gss_union_cred_t) *cred_handle;
*cred_handle = NULL;
- if (union_cred == NULL)
- return GSS_S_NO_CRED;
+ if (union_cred == (gss_union_cred_t)GSS_C_NO_CREDENTIAL)
+ return (GSS_S_COMPLETE);
status = GSS_S_COMPLETE;
for(j=0; j < union_cred->count; j++) {
- mech = __gss_get_mechanism (&union_cred->mechs_array[j]);
+ mech = gssint_get_mechanism (&union_cred->mechs_array[j]);
if (union_cred->mechs_array[j].elements)
free(union_cred->mechs_array[j].elements);
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);
-/* #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.
{
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
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);
free(union_name->external_name);
if (union_name->mech_type) {
- __gss_release_internal_name(minor_status, union_name->mech_type,
+ gssint_release_internal_name(minor_status, union_name->mech_type,
&union_name->mech_name);
gss_release_oid(minor_status, &union_name->mech_type);
}
-/* #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.
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;
-/* #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.
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
*/
ctx = (gss_union_ctx_id_t) context_handle;
- mech = __gss_get_mechanism (ctx->mech_type);
+ mech = gssint_get_mechanism (ctx->mech_type);
if (mech) {
if (mech->gss_seal)
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
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);
}
/*
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
*/
ctx = (gss_union_ctx_id_t) context_handle;
- mech = __gss_get_mechanism (ctx->mech_type);
+ mech = gssint_get_mechanism (ctx->mech_type);
if (!mech)
- return (GSS_S_NO_CONTEXT);
+ return (GSS_S_BAD_MECH);
if (!mech->gss_wrap_size_limit)
- return (GSS_S_BAD_BINDINGS);
+ return (GSS_S_UNAVAILABLE);
- status = mech->gss_wrap_size_limit(mech->context, minor_status,
- context_handle, conf_req_flag, qop_req,
- req_output_size, max_input_size);
- return(status);
+ return (mech->gss_wrap_size_limit(mech->context, minor_status,
+ ctx->internal_ctx_id, conf_req_flag, qop_req,
+ req_output_size, max_input_size));
}
-/* #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.
gss_union_ctx_id_t ctx;
gss_mechanism mech;
- gss_initialize();
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *minor_status = 0;
if (context_handle == GSS_C_NO_CONTEXT)
- return GSS_S_NO_CONTEXT;
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+ if (message_buffer == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (msg_token == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ msg_token->value = NULL;
+ msg_token->length = 0;
/*
* select the approprate underlying mechanism routine and
* call it.
*/
ctx = (gss_union_ctx_id_t) context_handle;
- mech = __gss_get_mechanism (ctx->mech_type);
+ mech = gssint_get_mechanism (ctx->mech_type);
if (mech) {
if (mech->gss_sign)
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
--- /dev/null
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident "@(#)g_store_cred.c 1.2 04/04/05 SMI" */
+
+/*
+ * glue routine for gss_store_cred
+ */
+
+#include <mglueP.h>
+
+OM_uint32 gss_store_cred(minor_status,
+ input_cred_handle,
+ cred_usage,
+ desired_mech,
+ overwrite_cred,
+ default_cred,
+ elements_stored,
+ cred_usage_stored)
+
+OM_uint32 *minor_status;
+const gss_cred_id_t input_cred_handle;
+gss_cred_usage_t cred_usage;
+const gss_OID desired_mech;
+OM_uint32 overwrite_cred;
+OM_uint32 default_cred;
+gss_OID_set *elements_stored;
+gss_cred_usage_t *cred_usage_stored;
+
+{
+ OM_uint32 major_status = GSS_S_FAILURE;
+ gss_union_cred_t union_cred;
+ gss_cred_id_t mech_cred;
+ gss_mechanism mech;
+ gss_OID dmech;
+ int i;
+
+ /* Start by checking parameters */
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE|GSS_S_NO_CRED);
+ *minor_status = 0;
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (elements_stored != NULL)
+ *elements_stored = GSS_C_NULL_OID_SET;
+
+ if (cred_usage_stored != NULL)
+ *cred_usage_stored = GSS_C_BOTH; /* there's no GSS_C_NEITHER */
+
+ union_cred = (gss_union_cred_t)input_cred_handle;
+
+ /* desired_mech != GSS_C_NULL_OID -> store one element */
+ if (desired_mech != GSS_C_NULL_OID) {
+ mech = gssint_get_mechanism(desired_mech);
+ if (mech == NULL)
+ return (GSS_S_BAD_MECH);
+
+ if (mech->gss_store_cred == NULL)
+ return (major_status);
+
+ mech_cred = gssint_get_mechanism_cred(union_cred, desired_mech);
+ if (mech_cred == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_NO_CRED);
+
+ return (mech->gss_store_cred(mech->context,
+ minor_status,
+ (gss_cred_id_t)mech_cred,
+ cred_usage,
+ desired_mech,
+ overwrite_cred,
+ default_cred,
+ elements_stored,
+ cred_usage_stored));
+ }
+
+ /* desired_mech == GSS_C_NULL_OID -> store all elements */
+
+ *minor_status = 0;
+
+ for (i = 0; i < union_cred->count; i++) {
+ /* Get mech and cred element */
+ dmech = &union_cred->mechs_array[i];
+ mech = gssint_get_mechanism(dmech);
+ if (mech == NULL)
+ continue;
+
+ if (mech->gss_store_cred == NULL)
+ continue;
+
+ mech_cred = gssint_get_mechanism_cred(union_cred, dmech);
+ if (mech_cred == GSS_C_NO_CREDENTIAL)
+ continue; /* can't happen, but safe to ignore */
+
+ major_status = mech->gss_store_cred(mech->context,
+ minor_status,
+ (gss_cred_id_t)mech_cred,
+ cred_usage,
+ dmech,
+ overwrite_cred,
+ default_cred,
+ NULL,
+ cred_usage_stored);
+ if (major_status != GSS_S_COMPLETE)
+ continue;
+
+ /* Succeeded for at least one mech */
+
+ if (elements_stored == NULL)
+ continue;
+
+ if (*elements_stored == GSS_C_NULL_OID_SET) {
+ major_status = gss_create_empty_oid_set(minor_status,
+ elements_stored);
+
+ if (GSS_ERROR(major_status))
+ return (major_status);
+ }
+
+ major_status = gss_add_oid_set_member(minor_status, dmech,
+ elements_stored);
+
+ /* The caller should clean up elements_stored */
+ if (GSS_ERROR(major_status))
+ return (major_status);
+ }
+
+ /*
+ * Success with some mechs may mask failure with others, but
+ * that's what elements_stored is for.
+ */
+ return (major_status);
+}
-/* #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.
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
*/
ctx = (gss_union_ctx_id_t) context_handle;
- mech = __gss_get_mechanism (ctx->mech_type);
+ mech = gssint_get_mechanism (ctx->mech_type);
if (mech) {
if (mech->gss_unseal)
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
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));
}
--- /dev/null
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident "@(#)g_userok.c 1.1 04/03/25 SMI" */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <mglueP.h>
+#include <gssapi/gssapi.h>
+
+
+static OM_uint32
+compare_names(OM_uint32 *minor,
+ const gss_OID mech_type,
+ const gss_name_t name,
+ const char *user,
+ int *user_ok)
+{
+
+ OM_uint32 status, tmpMinor;
+ gss_name_t imported_name;
+ gss_name_t canon_name;
+ gss_buffer_desc gss_user;
+ int match = 0;
+
+ *user_ok = 0;
+
+ gss_user.value = (void *)user;
+ if (!gss_user.value || !name || !mech_type)
+ return (GSS_S_BAD_NAME);
+ gss_user.length = strlen(gss_user.value);
+
+ status = gss_import_name(minor,
+ &gss_user,
+ GSS_C_NT_USER_NAME,
+ &imported_name);
+ if (status != GSS_S_COMPLETE) {
+ goto out;
+ }
+
+ status = gss_canonicalize_name(minor,
+ imported_name,
+ mech_type,
+ &canon_name);
+ if (status != GSS_S_COMPLETE) {
+ (void) gss_release_name(&tmpMinor, &imported_name);
+ goto out;
+ }
+
+ status = gss_compare_name(minor,
+ canon_name,
+ name,
+ &match);
+ (void) gss_release_name(&tmpMinor, &canon_name);
+ (void) gss_release_name(&tmpMinor, &imported_name);
+ if (status == GSS_S_COMPLETE) {
+ if (match)
+ *user_ok = 1; /* remote user is a-ok */
+ }
+
+out:
+ return (status);
+}
+
+
+OM_uint32
+gssint_userok(OM_uint32 *minor,
+ const gss_name_t name,
+ const char *user,
+ int *user_ok)
+
+{
+ gss_mechanism mech;
+ gss_union_name_t intName;
+ gss_name_t mechName = NULL;
+ OM_uint32 major;
+
+ if (minor == NULL || user_ok == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (name == NULL || user == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ *user_ok = 0;
+ *minor = GSS_S_COMPLETE;
+
+ intName = (gss_union_name_t)name;
+
+ mech = gssint_get_mechanism(intName->mech_type);
+ if (mech == NULL)
+ return (GSS_S_UNAVAILABLE);
+
+ /* may need to import the name if this is not MN */
+ if (intName->mech_type == NULL) {
+ return (GSS_S_FAILURE);
+ } else
+ mechName = intName->mech_name;
+
+ if (mech->gssint_userok)
+ major = mech->gssint_userok(mech->context, minor, mechName,
+ user, user_ok);
+ else
+ major = compare_names(minor, intName->mech_type,
+ name, user, user_ok);
+
+ return (major);
+} /* gss_userok */
--- /dev/null
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident "@(#)g_utils.c 1.8 04/02/23 SMI" */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <ctype.h>
+#include <errno.h>
+#include <gssapi/gssapi.h>
+
+#define Q_DEFAULT "default"
+#define BUFLEN 256
+
+#if 0
+static int qop_num_pair_cnt;
+static const char QOP_NUM_FILE[] = "/etc/gss/qop";
+static qop_num qop_num_pairs[MAX_QOP_NUM_PAIRS+1];
+static mutex_t qopfile_lock = DEFAULTMUTEX;
+
+static OM_uint32 gssint_read_qop_file(void);
+
+/*
+ * This routine fetches qop and num from "/etc/gss/qop".
+ * There is a memory leak associated with rereading this file,
+ * because we can't free the qop_num_pairs array when we reread
+ * the file (some callers may have been given these pointers).
+ * In general, this memory leak should be a small one, because
+ * we don't expect the qop file to be changed and reread often.
+ */
+static OM_uint32
+gssint_read_qop_file(void)
+{
+ char buf[BUFLEN]; /* one line from the file */
+ char *name, *next;
+ char *qopname, *num_str;
+ char *line;
+ FILE *fp;
+ static int last = 0;
+ struct stat stbuf;
+ OM_uint32 major = GSS_S_COMPLETE;
+
+ (void) mutex_lock(&qopfile_lock);
+ if (stat(QOP_NUM_FILE, &stbuf) != 0 || stbuf.st_mtime < last) {
+ if (!qop_num_pairs[0].qop) {
+ major = GSS_S_FAILURE;
+ }
+ goto done;
+ }
+ last = stbuf.st_mtime;
+
+ fp = fopen(QOP_NUM_FILE, "r");
+ if (fp == (FILE *)0) {
+ major = GSS_S_FAILURE;
+ goto done;
+ }
+
+ /*
+ * For each line in the file parse it appropriately.
+ * File format : qopname num(int)
+ * Note that we silently ignore corrupt entries.
+ */
+ qop_num_pair_cnt = 0;
+ while (!feof(fp)) {
+ line = fgets(buf, BUFLEN, fp);
+ if (line == NULL)
+ break;
+
+ /* Skip comments and blank lines */
+ if ((*line == '#') || (*line == '\n'))
+ continue;
+
+ /* Skip trailing comments */
+ next = strchr(line, '#');
+ if (next)
+ *next = '\0';
+
+ name = &(buf[0]);
+ while (isspace(*name))
+ name++;
+ if (*name == '\0') /* blank line */
+ continue;
+
+ qopname = name; /* will contain qop name */
+ while (!isspace(*qopname))
+ qopname++;
+ if (*qopname == '\0') {
+ continue;
+ }
+ next = qopname+1;
+ *qopname = '\0'; /* null terminate qopname */
+ qop_num_pairs[qop_num_pair_cnt].qop = strdup(name);
+ if (qop_num_pairs[qop_num_pair_cnt].qop == NULL)
+ continue;
+
+ name = next;
+ while (isspace(*name))
+ name++;
+ if (*name == '\0') { /* end of line, no num */
+ free(qop_num_pairs[qop_num_pair_cnt].qop);
+ continue;
+ }
+ num_str = name; /* will contain num (n) */
+ while (!isspace(*num_str))
+ num_str++;
+ next = num_str+1;
+ *num_str++ = '\0'; /* null terminate num_str */
+
+ qop_num_pairs[qop_num_pair_cnt].num = (OM_uint32)atoi(name);
+ name = next;
+ while (isspace(*name))
+ name++;
+ if (*name == '\0') { /* end of line, no mechanism */
+ free(qop_num_pairs[qop_num_pair_cnt].qop);
+ continue;
+ }
+ num_str = name; /* will contain mech */
+ while (!isspace(*num_str))
+ num_str++;
+ *num_str = '\0';
+
+ qop_num_pairs[qop_num_pair_cnt].mech = strdup(name);
+ if (qop_num_pairs[qop_num_pair_cnt].mech == NULL) {
+ free(qop_num_pairs[qop_num_pair_cnt].qop);
+ continue;
+ }
+
+ if (qop_num_pair_cnt++ >= MAX_QOP_NUM_PAIRS)
+ break;
+ }
+ (void) fclose(fp);
+done:
+ (void) mutex_unlock(&qopfile_lock);
+ return (major);
+}
+
+OM_uint32
+gssint_qop_to_num(
+ char *qop,
+ char *mech,
+ OM_uint32 *num
+)
+{
+ int i;
+ OM_uint32 major = GSS_S_FAILURE;
+
+ if (!num)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (qop == NULL || strlen(qop) == 0 ||
+ strcasecmp(qop, Q_DEFAULT) == 0) {
+ *num = GSS_C_QOP_DEFAULT;
+ return (GSS_S_COMPLETE);
+ }
+
+ if ((major = gssint_read_qop_file()) != GSS_S_COMPLETE)
+ return (major);
+
+ for (i = 0; i < qop_num_pair_cnt; i++) {
+ if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
+ (strcasecmp(qop, qop_num_pairs[i].qop) == 0)) {
+ *num = qop_num_pairs[i].num;
+ return (GSS_S_COMPLETE);
+ }
+ }
+
+ return (GSS_S_FAILURE);
+}
+
+OM_uint32
+gssint_num_to_qop(
+ char *mech,
+ OM_uint32 num,
+ char **qop
+)
+{
+ int i;
+ OM_uint32 major;
+
+ if (!qop)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *qop = NULL;
+
+ if (num == GSS_C_QOP_DEFAULT) {
+ *qop = Q_DEFAULT;
+ return (GSS_S_COMPLETE);
+ }
+
+ if (mech == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if ((major = gssint_read_qop_file()) != GSS_S_COMPLETE)
+ return (major);
+
+ for (i = 0; i < qop_num_pair_cnt; i++) {
+ if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
+ (num == qop_num_pairs[i].num)) {
+ *qop = qop_num_pairs[i].qop;
+ return (GSS_S_COMPLETE);
+ }
+ }
+ return (GSS_S_FAILURE);
+}
+
+/*
+ * For a given mechanism pass back qop information about it in a buffer
+ * of size MAX_QOPS_PER_MECH+1.
+ */
+OM_uint32
+gssint_get_mech_info(
+ char *mech,
+ char **qops
+)
+{
+ int i, cnt = 0;
+ OM_uint32 major = GSS_S_COMPLETE;
+
+ if (!qops)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *qops = NULL;
+
+ if (!mech)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if ((major = gssint_read_qop_file()) != GSS_S_COMPLETE)
+ return (major);
+
+ for (i = 0; i < qop_num_pair_cnt; i++) {
+ if (strcmp(mech, qop_num_pairs[i].mech) == 0) {
+ if (cnt >= MAX_QOPS_PER_MECH) {
+ return (GSS_S_FAILURE);
+ }
+ qops[cnt++] = qop_num_pairs[i].qop;
+ }
+ }
+ qops[cnt] = NULL;
+ return (GSS_S_COMPLETE);
+}
+
+/*
+ * Copy the qop values and names for the mechanism back in a qop_num
+ * buffer of size MAX_QOPS_PER_MECH provided by the caller.
+ */
+OM_uint32
+gssint_mech_qops(
+ char *mech,
+ qop_num *mechqops,
+ int *numqop
+)
+{
+ int i;
+ OM_uint32 major;
+ int cnt = 0;
+
+ if (!mechqops || !numqop)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ *numqop = 0;
+
+ if (!mech)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if ((major = gssint_read_qop_file()) != GSS_S_COMPLETE)
+ return (major);
+
+ for (i = 0; i < qop_num_pair_cnt; i++) {
+ if (strcasecmp(mech, qop_num_pairs[i].mech) == 0) {
+ if (cnt >= MAX_QOPS_PER_MECH) {
+ return (GSS_S_FAILURE);
+ }
+ mechqops[cnt++] = qop_num_pairs[i];
+ }
+ }
+ *numqop = cnt;
+ return (GSS_S_COMPLETE);
+}
+#endif
-/* #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.
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
*/
ctx = (gss_union_ctx_id_t) context_handle;
- mech = __gss_get_mechanism (ctx->mech_type);
+ mech = gssint_get_mechanism (ctx->mech_type);
if (mech) {
if (mech->gss_verify)
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
-/* #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.
int status;
gss_mechanism mech;
- gss_initialize();
-
/*
* find the appropriate mechanism specific pname_to_uid procedure and
* call it.
*/
- mech = __gss_get_mechanism (mech_type);
+ mech = gssint_get_mechanism (mech_type);
if (mech) {
if (mech_type == GSS_C_NULL_OID)
#ifndef _GSS_MECHGLUEP_H
#define _GSS_MECHGLUEP_H
+#include "autoconf.h"
#include "mechglue.h"
+#include "gssapiP_generic.h"
+
+#define g_OID_copy(o1, o2) \
+do { \
+ memcpy((o1)->elements, (o2)->elements, (o2)->length); \
+ (o1)->length = (o2)->length; \
+} while (0)
+
+#define GSS_EMPTY_BUFFER(buf) ((buf) == NULL ||\
+ (buf)->value == NULL || (buf)->length == 0)
/*
* Array of context IDs typed by mechanism OID
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;
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 */
*/
typedef struct gss_config {
+ OM_uint32 priority;
+ char * mechNameStr;
gss_OID_desc mech_type;
void * context;
OM_uint32 (*gss_acquire_cred)
gss_OID, /* mech type */
uid_t * /* uid */
);
-
+ OM_uint32 (*gssint_userok)
+ (
+ void *, /* context */
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* pname */
+ const char *, /* local user */
+ int * /* user ok? */
+ /* */);
+ OM_uint32 (*gss_export_name)
+ (
+ void *, /* context */
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_buffer_t /* exported_name */
+ /* */);
+ OM_uint32 (*gss_store_cred)
+ (
+ void *, /* context */
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* input_cred */
+ gss_cred_usage_t, /* cred_usage */
+ const gss_OID, /* desired_mech */
+ OM_uint32, /* overwrite_cred */
+ OM_uint32, /* default_cred */
+ gss_OID_set *, /* elements_stored */
+ gss_cred_usage_t * /* cred_usage_stored */
+ /* */);
} *gss_mechanism;
+/* This structure MUST NOT be used by any code outside libgss */
+typedef struct gss_config_ext {
+ gss_acquire_cred_with_password_sfct gss_acquire_cred_with_password;
+} *gss_mechanism_ext;
+
+/*
+ * In the user space we use a wrapper structure to encompass the
+ * mechanism entry points. The wrapper contain the mechanism
+ * entry points and other data which is only relevant to the gss-api
+ * layer. In the kernel we use only the gss_config strucutre because
+ * the kernal does not cantain any of the extra gss-api specific data.
+ */
+typedef struct gss_mech_config {
+ char *kmodName; /* kernel module name */
+ char *uLibName; /* user library name */
+ char *mechNameStr; /* mechanism string name */
+ char *optionStr; /* optional mech parameters */
+ void *dl_handle; /* RTLD object handle for the mech */
+ gss_OID mech_type; /* mechanism oid */
+ gss_mechanism mech; /* mechanism initialization struct */
+ gss_mechanism_ext mech_ext; /* extensions */
+ struct gss_mech_config *next; /* next element in the list */
+} *gss_mech_info;
+
/********************************************************/
/* Internal mechglue routines */
-gss_mechanism __gss_get_mechanism (gss_OID);
-OM_uint32 __gss_get_mech_type (gss_OID, gss_buffer_t);
-OM_uint32 __gss_import_internal_name (OM_uint32 *, gss_OID, gss_union_name_t,
+int gssint_mechglue_init(void);
+void gssint_mechglue_fini(void);
+
+gss_mechanism gssint_get_mechanism (gss_OID);
+gss_mechanism_ext gssint_get_mechanism_ext(const gss_OID);
+OM_uint32 gssint_get_mech_type (gss_OID, gss_buffer_t);
+char *gssint_get_kmodName(const gss_OID);
+char *gssint_get_modOptions(const gss_OID);
+OM_uint32 gssint_import_internal_name (OM_uint32 *, gss_OID, gss_union_name_t,
gss_name_t *);
-OM_uint32 __gss_display_internal_name (OM_uint32 *, gss_OID, gss_name_t,
+OM_uint32 gssint_export_internal_name(OM_uint32 *, const gss_OID,
+ const gss_name_t, gss_buffer_t);
+OM_uint32 gssint_display_internal_name (OM_uint32 *, gss_OID, gss_name_t,
gss_buffer_t, gss_OID *);
-OM_uint32 __gss_release_internal_name (OM_uint32 *, gss_OID, gss_name_t *);
+OM_uint32 gssint_release_internal_name (OM_uint32 *, gss_OID, gss_name_t *);
-OM_uint32 __gss_convert_name_to_union_name
+OM_uint32 gssint_convert_name_to_union_name
(OM_uint32 *, /* minor_status */
gss_mechanism, /* mech */
gss_name_t, /* internal_name */
gss_name_t * /* external_name */
);
-gss_cred_id_t __gss_get_mechanism_cred
+gss_cred_id_t gssint_get_mechanism_cred
(gss_union_cred_t, /* union_cred */
gss_OID /* mech_type */
);
-OM_uint32 generic_gss_release_oid
- (OM_uint32 *, /* minor_status */
- gss_OID * /* oid */
- );
+OM_uint32 gssint_create_copy_buffer(
+ const gss_buffer_t, /* src buffer */
+ gss_buffer_t *, /* destination buffer */
+ int /* NULL terminate buffer ? */
+);
-OM_uint32 generic_gss_copy_oid
- (OM_uint32 *, /* minor_status */
- gss_OID, /* oid */
- gss_OID * /* new_oid */
- );
+OM_uint32 gssint_copy_oid_set(
+ OM_uint32 *, /* minor_status */
+ const gss_OID_set_desc *, /* oid set */
+ gss_OID_set * /* new oid set */
+);
-OM_uint32 generic_gss_create_empty_oid_set
- (OM_uint32 *, /* minor_status */
- gss_OID_set * /* oid_set */
- );
+gss_OID gss_find_mechanism_from_name_type (gss_OID); /* name_type */
-OM_uint32 generic_gss_add_oid_set_member
+OM_uint32 gss_add_mech_name_type
(OM_uint32 *, /* minor_status */
- gss_OID, /* member_oid */
- gss_OID_set * /* oid_set */
- );
+ gss_OID, /* name_type */
+ gss_OID /* mech */
+ );
-OM_uint32 generic_gss_test_oid_set_member
- (OM_uint32 *, /* minor_status */
- gss_OID, /* member */
- gss_OID_set, /* set */
- int * /* present */
- );
+/*
+ * Sun extensions to GSS-API v2
+ */
-OM_uint32 generic_gss_oid_to_str
- (OM_uint32 *, /* minor_status */
- gss_OID, /* oid */
- gss_buffer_t /* oid_str */
- );
+OM_uint32
+gssint_mech_to_oid(
+ const char *mech, /* mechanism string name */
+ gss_OID *oid /* mechanism oid */
+);
-OM_uint32 generic_gss_str_to_oid
- (OM_uint32 *, /* minor_status */
- gss_buffer_t, /* oid_str */
- gss_OID * /* oid */
- );
+const char *
+gssint_oid_to_mech(
+ const gss_OID oid /* mechanism oid */
+);
+OM_uint32
+gssint_get_mechanisms(
+ char *mechArray[], /* array to populate with mechs */
+ int arrayLen /* length of passed in array */
+);
-gss_OID gss_find_mechanism_from_name_type (gss_OID); /* name_type */
+OM_uint32
+gssint_userok(
+ OM_uint32 *, /* minor */
+ const gss_name_t, /* name */
+ const char *, /* user */
+ int * /* user_ok */
+);
-OM_uint32 gss_add_mech_name_type
- (OM_uint32 *, /* minor_status */
- gss_OID, /* name_type */
- gss_OID /* mech */
- );
+OM_uint32
+gss_store_cred(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* input_cred_handle */
+ gss_cred_usage_t, /* cred_usage */
+ const gss_OID, /* desired_mech */
+ OM_uint32, /* overwrite_cred */
+ OM_uint32, /* default_cred */
+ gss_OID_set *, /* elements_stored */
+ gss_cred_usage_t * /* cred_usage_stored */
+);
+
+int
+gssint_get_der_length(
+ unsigned char **, /* buf */
+ unsigned int, /* buf_len */
+ unsigned int * /* bytes */
+);
+
+unsigned int
+gssint_der_length_size(unsigned int /* len */);
+
+int
+gssint_put_der_length(
+ unsigned int, /* length */
+ unsigned char **, /* buf */
+ unsigned int /* max_len */
+);
#endif /* _GSS_MECHGLUEP_H */
+/* #pragma ident "@(#)oid_ops.c 1.19 04/02/23 SMI" */
/*
* lib/gssapi/generic/oid_ops.c
*
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);
* 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);
OM_uint32
generic_gss_copy_oid(minor_status, oid, new_oid)
OM_uint32 *minor_status;
- gss_OID oid, *new_oid;
+ const gss_OID_desc * const oid;
+ gss_OID *new_oid;
{
gss_OID p;
+ *minor_status = 0;
+
p = (gss_OID) malloc(sizeof(gss_OID_desc));
if (!p) {
*minor_status = ENOMEM;
p->elements = malloc(p->length);
if (!p->elements) {
free(p);
- *minor_status = ENOMEM;
return GSS_S_FAILURE;
}
memcpy(p->elements, oid->elements, p->length);
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 {
OM_uint32
generic_gss_add_oid_set_member(minor_status, member_oid, oid_set)
OM_uint32 *minor_status;
- gss_OID member_oid;
+ const gss_OID_desc * const member_oid;
gss_OID_set *oid_set;
{
gss_OID elist;
gss_OID lastel;
+ *minor_status = 0;
+
+ if (member_oid == NULL || member_oid->length == 0 ||
+ member_oid->elements == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
elist = (*oid_set)->elements;
/* Get an enlarged copy of the array */
if (((*oid_set)->elements = (gss_OID) malloc(((*oid_set)->count+1) *
OM_uint32
generic_gss_test_oid_set_member(minor_status, member, set, present)
OM_uint32 *minor_status;
- gss_OID member;
+ const gss_OID_desc * const member;
gss_OID_set set;
int *present;
{
- size_t i;
+ OM_uint32 i;
int result;
+ *minor_status = 0;
+
+ if (member == NULL || set == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (present == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
result = 0;
for (i=0; i<set->count; i++) {
if ((set->elements[i].length == member->length) &&
}
}
*present = result;
- *minor_status = 0;
return(GSS_S_COMPLETE);
}
OM_uint32
generic_gss_oid_to_str(minor_status, oid, oid_str)
OM_uint32 *minor_status;
- gss_OID oid;
+ const gss_OID_desc * const oid;
gss_buffer_t oid_str;
{
char numstr[128];
- unsigned long number;
+ OM_uint32 number;
int numshift;
- size_t string_length;
- size_t i;
+ OM_uint32 string_length;
+ OM_uint32 i;
unsigned char *cp;
char *bp;
+ *minor_status = 0;
+
+ if (oid == NULL || oid->length == 0 || oid->elements == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (oid_str == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
/* Decoded according to krb5/gssapi_krb5.c */
/* First determine the size of the string */
numshift = 0;
cp = (unsigned char *) oid->elements;
number = (unsigned long) cp[0];
- sprintf(numstr, "%ld ", number/40);
+ sprintf(numstr, "%lu ", (unsigned long)number/40);
string_length += strlen(numstr);
- sprintf(numstr, "%ld ", number%40);
+ sprintf(numstr, "%lu ", (unsigned long)number%40);
string_length += strlen(numstr);
for (i=1; i<oid->length; i++) {
- if ( (size_t) (numshift+7) < (sizeof(unsigned long)*8)) {
+ if ((OM_uint32) (numshift+7) < (sizeof (OM_uint32)*8)) {/* XXX */
number = (number << 7) | (cp[i] & 0x7f);
numshift += 7;
}
else {
- *minor_status = EINVAL;
return(GSS_S_FAILURE);
}
if ((cp[i] & 0x80) == 0) {
- sprintf(numstr, "%ld ", number);
+ sprintf(numstr, "%lu ", (unsigned long)number);
string_length += strlen(numstr);
number = 0;
numshift = 0;
string_length += 4;
if ((bp = (char *) malloc(string_length))) {
strcpy(bp, "{ ");
- number = (unsigned long) cp[0];
- sprintf(numstr, "%ld ", number/40);
+ number = (OM_uint32) cp[0];
+ sprintf(numstr, "%lu ", (unsigned long)number/40);
strcat(bp, numstr);
- sprintf(numstr, "%ld ", number%40);
+ sprintf(numstr, "%lu ", (unsigned long)number%40);
strcat(bp, numstr);
number = 0;
cp = (unsigned char *) oid->elements;
for (i=1; i<oid->length; i++) {
number = (number << 7) | (cp[i] & 0x7f);
if ((cp[i] & 0x80) == 0) {
- sprintf(numstr, "%ld ", number);
+ sprintf(numstr, "%lu ", (unsigned long)number);
strcat(bp, numstr);
number = 0;
}
strcat(bp, "}");
oid_str->length = strlen(bp)+1;
oid_str->value = (void *) bp;
- *minor_status = 0;
return(GSS_S_COMPLETE);
}
*minor_status = ENOMEM;
gss_buffer_t oid_str;
gss_OID *oid;
{
- char *cp, *bp, *startp;
+ unsigned char *cp, *bp, *startp;
int brace;
long numbuf;
long onumbuf;
int index;
unsigned char *op;
+ *minor_status = 0;
+
+ if (GSS_EMPTY_BUFFER(oid_str))
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (oid == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
brace = 0;
- bp = (char *) oid_str->value;
+ bp = oid_str->value;
cp = bp;
/* Skip over leading space */
while ((bp < &cp[oid_str->length]) && isspace(*bp))
/*
* The first two numbers are chewed up by the first octet.
*/
- if (sscanf(bp, "%ld", &numbuf) != 1) {
+ if (sscanf((char *)bp, "%ld", &numbuf) != 1) {
*minor_status = EINVAL;
return(GSS_S_FAILURE);
}
bp++;
while ((bp < &cp[oid_str->length]) && isspace(*bp))
bp++;
- if (sscanf(bp, "%ld", &numbuf) != 1) {
+ if (sscanf((char *)bp, "%ld", &numbuf) != 1) {
*minor_status = EINVAL;
return(GSS_S_FAILURE);
}
while ((bp < &cp[oid_str->length]) && isdigit(*bp))
bp++;
- while ((bp < &cp[oid_str->length]) && isspace(*bp))
+ while ((bp < &cp[oid_str->length]) &&
+ (isspace(*bp) || *bp == '.'))
bp++;
nbytes++;
while (isdigit(*bp)) {
- if (sscanf(bp, "%ld", &numbuf) != 1) {
- *minor_status = EINVAL;
+ if (sscanf((char *)bp, "%ld", &numbuf) != 1) {
return(GSS_S_FAILURE);
}
while (numbuf) {
}
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);
}
* Phew! We've come this far, so the syntax is good.
*/
if ((*oid = (gss_OID) malloc(sizeof(gss_OID_desc)))) {
- if (((*oid)->elements = (void *) malloc((size_t) nbytes))) {
+ if (((*oid)->elements = (void *) malloc(nbytes))) {
(*oid)->length = nbytes;
op = (unsigned char *) (*oid)->elements;
bp = startp;
- sscanf(bp, "%ld", &numbuf);
+ (void) sscanf((char *)bp, "%ld", &numbuf);
while (isdigit(*bp))
bp++;
- while (isspace(*bp))
+ while (isspace(*bp) || *bp == '.')
bp++;
onumbuf = 40*numbuf;
- sscanf(bp, "%ld", &numbuf);
+ (void) sscanf((char *)bp, "%ld", &numbuf);
onumbuf += numbuf;
*op = (unsigned char) onumbuf;
op++;
while (isdigit(*bp))
bp++;
- while (isspace(*bp))
+ while (isspace(*bp) || *bp == '.')
bp++;
while (isdigit(*bp)) {
- sscanf(bp, "%ld", &numbuf);
+ (void) sscanf((char *)bp, "%ld", &numbuf);
nbytes = 0;
/* Have to fill in the bytes msb-first */
onumbuf = numbuf;
}
while (isdigit(*bp))
bp++;
- while (isspace(*bp))
+ while (isspace(*bp) || *bp == '.')
bp++;
}
- *minor_status = 0;
return(GSS_S_COMPLETE);
}
else {
*oid = GSS_C_NO_OID;
}
}
- *minor_status = ENOMEM;
return(GSS_S_FAILURE);
}
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+OM_uint32
+gssint_copy_oid_set(
+ OM_uint32 *minor_status,
+ const gss_OID_set_desc * const oidset,
+ gss_OID_set *new_oidset
+ )
+{
+ gss_OID_set_desc *copy;
+ OM_uint32 minor = 0;
+ OM_uint32 major = GSS_S_COMPLETE;
+ OM_uint32 index;
+
+ if (minor_status)
+ *minor_status = 0;
+
+ if (oidset == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (new_oidset == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *new_oidset = NULL;
+
+ if ((copy = (gss_OID_set_desc *) calloc(1, sizeof (*copy))) == NULL) {
+ major = GSS_S_FAILURE;
+ goto done;
+ }
+
+ if ((copy->elements = (gss_OID_desc *)
+ calloc(oidset->count, sizeof (*copy->elements))) == NULL) {
+ major = GSS_S_FAILURE;
+ goto done;
+ }
+ copy->count = oidset->count;
+
+ for (index = 0; index < copy->count; index++) {
+ gss_OID_desc *out = ©->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, ©);
+ }
+
+ return (major);
+}
--- /dev/null
+thisconfigdir=../../..
+myfulldir=lib/gssapi/spnego
+mydir=spnego
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic -I../mechglue -I$(srcdir)/../mechglue
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=spnego
+##DOS##OBJFILE = ..\$(OUTPRE)spnego.lst
+
+##DOS##DLL_EXP_TYPE=GSS
+
+SRCS = $(srcdir)/spnego_mech.c
+
+OBJS = $(OUTPRE)spnego_mech.$(OBJEXT)
+
+STLIBOBJS = spnego_mech.o
+
+all-unix:: all-libobjs
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
--- /dev/null
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _GSSAPIP_SPNEGO_H_
+#define _GSSAPIP_SPNEGO_H_
+
+/* #pragma ident "@(#)gssapiP_spnego.h 1.3 03/09/18 SMI" */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <gssapi/gssapi.h>
+#include <syslog.h>
+
+#define SEC_CONTEXT_TOKEN 1
+#define SPNEGO_SIZE_OF_INT 4
+
+#define ACCEPT_COMPLETE 0
+#define ACCEPT_INCOMPLETE 1
+#define REJECT 2
+#define REQUEST_MIC 3
+#define ACCEPT_DEFECTIVE_TOKEN 0xffffffffUL
+
+/*
+ * constants for der encoding/decoding routines.
+ */
+
+#define MECH_OID 0x06
+#define OCTET_STRING 0x04
+#define CONTEXT 0xa0
+#define SEQUENCE 0x30
+#define SEQUENCE_OF 0x30
+#define BIT_STRING 0x03
+#define BIT_STRING_LENGTH 0x02
+#define BIT_STRING_PADDING 0x01
+#define ENUMERATED 0x0a
+#define ENUMERATION_LENGTH 1
+#define HEADER_ID 0x60
+
+/*
+ * SPNEGO specific error codes (minor status codes)
+ */
+#define ERR_SPNEGO_NO_MECHS_AVAILABLE 0x20000001
+#define ERR_SPNEGO_NO_CREDS_ACQUIRED 0x20000002
+#define ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR 0x20000003
+#define ERR_SPNEGO_NEGOTIATION_FAILED 0x20000004
+#define ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR 0x20000005
+
+/*
+ * send_token_flag is used to indicate in later steps what type
+ * of token, if any should be sent or processed.
+ * NO_TOKEN_SEND = no token should be sent
+ * INIT_TOKEN_SEND = initial token will be sent
+ * CONT_TOKEN_SEND = continuing tokens to be sent
+ * CHECK_MIC = no token to be sent, but have a MIC to check.
+ * ERROR_TOKEN_SEND = error token from peer needs to be sent.
+ */
+
+typedef enum {NO_TOKEN_SEND, INIT_TOKEN_SEND, CONT_TOKEN_SEND,
+ CHECK_MIC, ERROR_TOKEN_SEND} send_token_flag;
+
+/*
+ * The Mech OID:
+ * { iso(1) org(3) dod(6) internet(1) security(5)
+ * mechanism(5) spnego(2) }
+ */
+
+#define SPNEGO_OID_LENGTH 6
+#define SPNEGO_OID "\053\006\001\005\005\002"
+
+typedef void *spnego_token_t;
+
+/* spnego name structure for internal representation. */
+typedef struct {
+ gss_OID type;
+ gss_buffer_t buffer;
+ gss_OID mech_type;
+ gss_name_t mech_name;
+} spnego_name_desc, *spnego_name_t;
+
+/* Structure for context handle */
+typedef struct {
+ OM_uint32 magic_num;
+ gss_buffer_desc DER_mechTypes;
+ gss_OID internal_mech;
+ gss_ctx_id_t ctx_handle;
+ char *optionStr;
+ gss_cred_id_t default_cred;
+ int mic_reqd;
+ int mic_sent;
+ int mic_rcvd;
+ int firstpass;
+ int mech_complete;
+ int nego_done;
+ OM_uint32 ctx_flags;
+ gss_name_t internal_name;
+ gss_OID actual_mech;
+} spnego_gss_ctx_id_rec, *spnego_gss_ctx_id_t;
+
+/*
+ * The magic number must be less than a standard pagesize
+ * to avoid a possible collision with a real address.
+ */
+#define SPNEGO_MAGIC_ID 0x00000fed
+
+/* SPNEGO oid structure */
+static const gss_OID_desc spnego_oids[] = {
+ {SPNEGO_OID_LENGTH, SPNEGO_OID},
+};
+
+const gss_OID_desc * const gss_mech_spnego = spnego_oids+0;
+static const gss_OID_set_desc spnego_oidsets[] = {
+ {1, (gss_OID) spnego_oids+0},
+};
+const gss_OID_set_desc * const gss_mech_set_spnego = spnego_oidsets+0;
+
+#define TWRITE_STR(ptr, str, len) \
+ memcpy((ptr), (char *)(str), (len)); \
+ (ptr) += (len);
+
+#ifdef DEBUG
+#define dsyslog(a) syslog(LOG_DEBUG, a)
+#else
+#define dsyslog(a)
+#define SPNEGO_STATIC
+#endif /* DEBUG */
+
+/*
+ * declarations of internal name mechanism functions
+ */
+
+OM_uint32 spnego_gss_acquire_cred
+(
+ void *, /* spnego context */
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 * /* time_rec */
+);
+
+OM_uint32 spnego_gss_release_cred
+(
+ void *, /* spnego context */
+ OM_uint32 *, /* minor_status */
+ /* CSTYLED */
+ gss_cred_id_t * /* cred_handle */
+);
+
+OM_uint32 spnego_gss_init_sec_context
+(
+ void *, /* spnego context */
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* claimant_cred_handle */
+ gss_ctx_id_t *, /* context_handle */
+ gss_name_t, /* target_name */
+ gss_OID, /* mech_type */
+ OM_uint32, /* req_flags */
+ OM_uint32, /* time_req */
+ gss_channel_bindings_t, /* input_chan_bindings */
+ gss_buffer_t, /* input_token */
+ gss_OID *, /* actual_mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32 *, /* ret_flags */
+ OM_uint32 * /* time_rec */
+);
+
+OM_uint32 spnego_gss_accept_sec_context
+(
+ void *, /* spnego context */
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t *, /* context_handle */
+ gss_cred_id_t, /* verifier_cred_handle */
+ gss_buffer_t, /* input_token_buffer */
+ gss_channel_bindings_t, /* input_chan_bindings */
+ gss_name_t *, /* src_name */
+ gss_OID *, /* mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32 *, /* ret_flags */
+ OM_uint32 *, /* time_rec */
+ /* CSTYLED */
+ gss_cred_id_t * /* delegated_cred_handle */
+);
+
+OM_uint32 spnego_gss_display_name
+(
+ void *,
+ OM_uint32 *, /* minor_status */
+ gss_name_t, /* input_name */
+ gss_buffer_t, /* output_name_buffer */
+ gss_OID * /* output_name_type */
+);
+
+OM_uint32 spnego_gss_display_status
+(
+ void *, /* spnego context */
+ OM_uint32 *, /* minor_status */
+ OM_uint32, /* status_value */
+ int, /* status_type */
+ gss_OID, /* mech_type */
+ OM_uint32 *, /* message_context */
+ gss_buffer_t /* status_string */
+);
+
+OM_uint32 spnego_gss_import_name
+(
+ void *, /* spnego context */
+ OM_uint32 *, /* minor_status */
+ gss_buffer_t, /* input_name_buffer */
+ gss_OID, /* input_name_type */
+ /* CSTYLED */
+ gss_name_t * /* output_name */
+);
+
+OM_uint32 spnego_gss_release_name
+(
+ void *, /* spnego context */
+ OM_uint32 *, /* minor_status */
+ /* CSTYLED */
+ gss_name_t * /* input_name */
+);
+
+OM_uint32 spnego_gss_inquire_names_for_mech
+(
+ void *, /* spnego context */
+ OM_uint32 *, /* minor_status */
+ gss_OID, /* mechanism */
+ gss_OID_set * /* name_types */
+);
+
+OM_uint32 spnego_gss_unseal
+(
+ void *context,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int *conf_state,
+ int *qop_state
+);
+
+OM_uint32 spnego_gss_seal
+(
+ void *context,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ int qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer
+);
+
+OM_uint32 spnego_gss_process_context_token
+(
+ void *context,
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t token_buffer
+);
+
+OM_uint32 spnego_gss_delete_sec_context
+(
+ void *context,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token
+);
+
+OM_uint32 spnego_gss_context_time
+(
+ void *context,
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ OM_uint32 *time_rec
+);
+
+OM_uint32 spnego_gss_export_sec_context
+(
+ void *context,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t interprocess_token
+);
+
+OM_uint32 spnego_gss_import_sec_context
+(
+ void *context,
+ OM_uint32 *minor_status,
+ const gss_buffer_t interprocess_token,
+ gss_ctx_id_t *context_handle
+);
+
+OM_uint32 spnego_gss_inquire_context
+(
+ void *context,
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_name_t *src_name,
+ gss_name_t *targ_name,
+ OM_uint32 *lifetime_rec,
+ gss_OID *mech_type,
+ OM_uint32 *ctx_flags,
+ int *locally_initiated,
+ int *open
+);
+
+OM_uint32 spnego_gss_wrap_size_limit
+(
+ void *context,
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 req_output_size,
+ OM_uint32 *max_input_size
+);
+
+OM_uint32 spnego_gss_sign
+(
+ void *context,
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int qop_req,
+ const gss_buffer_t message_buffer,
+ gss_buffer_t message_token
+);
+
+OM_uint32 spnego_gss_verify
+(
+ void *context,
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t msg_buffer,
+ const gss_buffer_t token_buffer,
+ int *qop_state
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GSSAPIP_SPNEGO_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2006 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * A module that implements the spnego security mechanism.
+ * It is used to negotiate the security mechanism between
+ * peers using the GSS-API.
+ *
+ */
+
+/* #pragma ident "@(#)spnego_mech.c 1.7 04/09/28 SMI" */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <krb5.h>
+#include "gssapiP_spnego.h"
+#include <mglueP.h>
+#include <gssapi_err_generic.h>
+
+#undef g_token_size
+#undef g_verify_token_header
+#undef g_make_token_header
+
+#define HARD_ERROR(v) ((v) != GSS_S_COMPLETE && (v) != GSS_S_CONTINUE_NEEDED)
+typedef const gss_OID_desc *gss_OID_const;
+
+/* der routines defined in libgss */
+extern unsigned int gssint_der_length_size(OM_uint32);
+extern int gssint_get_der_length(unsigned char **, OM_uint32, OM_uint32*);
+extern int gssint_put_der_length(OM_uint32, unsigned char **, OM_uint32);
+
+
+/* private routines for spnego_mechanism */
+static spnego_token_t make_spnego_token(char *);
+static gss_buffer_desc make_err_msg(char *);
+static int g_token_size(gss_OID_const, OM_uint32);
+static int g_make_token_header(gss_OID_const, int, unsigned char **, int);
+static int g_verify_token_header(gss_OID_const, int *, unsigned char **,
+ int, int);
+static int g_verify_neg_token_init(unsigned char **, int);
+static gss_OID get_mech_oid(OM_uint32 *, unsigned char **, size_t);
+static gss_buffer_t get_input_token(unsigned char **, int);
+static gss_OID_set get_mech_set(OM_uint32 *, unsigned char **, int);
+static OM_uint32 get_req_flags(unsigned char **, OM_uint32, OM_uint32 *);
+static OM_uint32 get_available_mechs(OM_uint32 *, gss_name_t,
+ gss_cred_usage_t, gss_cred_id_t *, gss_OID_set *);
+static void release_spnego_ctx(spnego_gss_ctx_id_t *);
+static void check_spnego_options(spnego_gss_ctx_id_t);
+static spnego_gss_ctx_id_t create_spnego_ctx(void);
+static int put_req_flags(unsigned char **, OM_uint32, int);
+static int put_mech_set(gss_OID_set mechSet, gss_buffer_t buf);
+static int put_input_token(unsigned char **, gss_buffer_t, int);
+static int put_mech_oid(unsigned char **, gss_OID_const, int);
+static int put_negResult(unsigned char **, OM_uint32, int);
+
+static OM_uint32
+process_mic(OM_uint32 *, gss_buffer_t, spnego_gss_ctx_id_t,
+ gss_buffer_t *, OM_uint32 *, send_token_flag *);
+static OM_uint32
+handle_mic(OM_uint32 *, gss_buffer_t, int, spnego_gss_ctx_id_t,
+ gss_buffer_t *, OM_uint32 *, send_token_flag *);
+
+static OM_uint32
+init_ctx_new(OM_uint32 *, gss_cred_id_t, gss_ctx_id_t *,
+ gss_OID_set *, send_token_flag *);
+static OM_uint32
+init_ctx_nego(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32, gss_OID,
+ gss_buffer_t *, gss_buffer_t *,
+ OM_uint32 *, send_token_flag *);
+static OM_uint32
+init_ctx_cont(OM_uint32 *, gss_ctx_id_t *, gss_buffer_t,
+ gss_buffer_t *, gss_buffer_t *,
+ OM_uint32 *, send_token_flag *);
+static OM_uint32
+init_ctx_reselect(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32,
+ gss_OID, gss_buffer_t *, gss_buffer_t *,
+ OM_uint32 *, send_token_flag *);
+static OM_uint32
+init_ctx_call_init(OM_uint32 *, spnego_gss_ctx_id_t, gss_cred_id_t,
+ gss_name_t, OM_uint32, OM_uint32, gss_buffer_t,
+ gss_OID *, gss_buffer_t, OM_uint32 *, OM_uint32 *,
+ OM_uint32 *, send_token_flag *);
+
+static OM_uint32
+acc_ctx_new(OM_uint32 *, gss_buffer_t, gss_ctx_id_t *,
+ gss_cred_id_t, gss_buffer_t *,
+ gss_buffer_t *, OM_uint32 *, send_token_flag *);
+static OM_uint32
+acc_ctx_cont(OM_uint32 *, gss_buffer_t, gss_ctx_id_t *,
+ gss_buffer_t *, gss_buffer_t *,
+ OM_uint32 *, send_token_flag *);
+static OM_uint32
+acc_ctx_vfy_oid(OM_uint32 *, spnego_gss_ctx_id_t, gss_OID,
+ OM_uint32 *, send_token_flag *);
+static OM_uint32
+acc_ctx_call_acc(OM_uint32 *, spnego_gss_ctx_id_t, gss_cred_id_t,
+ gss_buffer_t, gss_OID *, gss_buffer_t,
+ OM_uint32 *, OM_uint32 *, gss_cred_id_t *,
+ OM_uint32 *, send_token_flag *);
+
+static gss_OID
+negotiate_mech_type(OM_uint32 *, gss_OID_set, gss_OID_set,
+ OM_uint32 *);
+static int
+g_get_tag_and_length(unsigned char **, int, int, int *);
+
+static int
+make_spnego_tokenInit_msg(spnego_gss_ctx_id_t, gss_buffer_t,
+ OM_uint32, gss_buffer_t, send_token_flag,
+ gss_buffer_t);
+static int
+make_spnego_tokenTarg_msg(OM_uint32, gss_OID, gss_buffer_t,
+ gss_buffer_t, send_token_flag,
+ gss_buffer_t);
+
+static OM_uint32
+get_negTokenInit(OM_uint32 *, gss_buffer_t, gss_buffer_t,
+ gss_OID_set *, OM_uint32 *, gss_buffer_t *,
+ gss_buffer_t *);
+static OM_uint32
+get_negTokenResp(OM_uint32 *, unsigned char *, unsigned int,
+ OM_uint32 *, gss_OID *, gss_buffer_t *, gss_buffer_t *);
+
+/*
+ * The Mech OID for SPNEGO:
+ * { iso(1) org(3) dod(6) internet(1) security(5)
+ * mechanism(5) spnego(2) }
+ */
+static struct gss_config spnego_mechanism =
+{
+ 400, "spnego",
+ {SPNEGO_OID_LENGTH, SPNEGO_OID},
+ NULL,
+ spnego_gss_acquire_cred,
+ spnego_gss_release_cred,
+ spnego_gss_init_sec_context,
+ spnego_gss_accept_sec_context,
+ NULL, /* gss_process_context_token */
+ spnego_gss_delete_sec_context, /* gss_delete_sec_context */
+ spnego_gss_context_time, /* gss_context_time */
+ spnego_gss_sign, /* gss_sign */
+ spnego_gss_verify, /* gss_verify */
+ spnego_gss_seal, /* gss_seal */
+ spnego_gss_unseal, /* gss_unseal */
+ spnego_gss_display_status,
+ NULL, /* gss_indicate_mechs */
+ NULL, /* gss_compare_name */
+ spnego_gss_display_name,
+ spnego_gss_import_name,
+ spnego_gss_release_name,
+ NULL, /* gss_inquire_cred */
+ NULL, /* gss_add_cred */
+ spnego_gss_export_sec_context, /* gss_export_sec_context */
+ spnego_gss_import_sec_context, /* gss_import_sec_context */
+ NULL, /* gss_inquire_cred_by_mech */
+ spnego_gss_inquire_names_for_mech,
+ spnego_gss_inquire_context, /* gss_inquire_context */
+ NULL, /* gss_internal_release_oid */
+ spnego_gss_wrap_size_limit, /* gss_wrap_size_limit */
+ NULL, /* gss_pname_to_uid */
+ NULL, /* gssint_userok */
+ NULL, /* gss_export_name */
+ NULL, /* gss_store_cred */
+};
+
+static gss_mechanism spnego_mech_configs[] = {
+ &spnego_mechanism, NULL
+};
+
+#if 1
+#define gssint_get_mech_configs spnego_gss_get_mech_configs
+#endif
+
+gss_mechanism *
+gssint_get_mech_configs(void)
+{
+ return spnego_mech_configs;
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_acquire_cred(void *ctx,
+ OM_uint32 *minor_status,
+ gss_name_t desired_name,
+ OM_uint32 time_req,
+ gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 status;
+ gss_OID_set amechs;
+ dsyslog("Entering spnego_gss_acquire_cred\n");
+
+ if (actual_mechs)
+ *actual_mechs = NULL;
+
+ if (time_rec)
+ *time_rec = 0;
+
+ /*
+ * If the user did not specify a list of mechs,
+ * use get_available_mechs to collect a list of
+ * mechs for which creds are available.
+ */
+ if (desired_mechs == GSS_C_NULL_OID_SET) {
+ status = get_available_mechs(minor_status,
+ desired_name, cred_usage,
+ output_cred_handle, &amechs);
+ } else {
+ /*
+ * The caller gave a specific list of mechanisms,
+ * so just get whatever creds are available.
+ * gss_acquire_creds will return the subset of mechs for
+ * which the given 'output_cred_handle' is valid.
+ */
+ status = gss_acquire_cred(minor_status,
+ desired_name, time_req,
+ desired_mechs, cred_usage,
+ output_cred_handle, &amechs,
+ time_rec);
+ }
+
+ if (actual_mechs && amechs != GSS_C_NULL_OID_SET) {
+ (void) gssint_copy_oid_set(minor_status, amechs, actual_mechs);
+ }
+ (void) gss_release_oid_set(minor_status, &amechs);
+
+ dsyslog("Leaving spnego_gss_acquire_cred\n");
+ return (status);
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_release_cred(void *ctx,
+ OM_uint32 *minor_status,
+ gss_cred_id_t *cred_handle)
+{
+ OM_uint32 status;
+
+ dsyslog("Entering spnego_gss_release_cred\n");
+
+ if (minor_status == NULL || cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *minor_status = 0;
+
+ if (*cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_COMPLETE);
+
+ status = gss_release_cred(minor_status, cred_handle);
+
+ dsyslog("Leaving spnego_gss_release_cred\n");
+ return (status);
+}
+
+static void
+check_spnego_options(spnego_gss_ctx_id_t spnego_ctx)
+{
+ spnego_ctx->optionStr = gssint_get_modOptions(
+ (const gss_OID)&spnego_oids[0]);
+}
+
+static spnego_gss_ctx_id_t
+create_spnego_ctx(void)
+{
+ spnego_gss_ctx_id_t spnego_ctx = NULL;
+ spnego_ctx = (spnego_gss_ctx_id_t)
+ malloc(sizeof (spnego_gss_ctx_id_rec));
+
+ if (spnego_ctx == NULL) {
+ return (NULL);
+ }
+
+ spnego_ctx->magic_num = SPNEGO_MAGIC_ID;
+ spnego_ctx->ctx_handle = GSS_C_NO_CONTEXT;
+ spnego_ctx->internal_mech = NULL;
+ spnego_ctx->optionStr = NULL;
+ spnego_ctx->DER_mechTypes.length = 0;
+ spnego_ctx->DER_mechTypes.value = NULL;
+ spnego_ctx->default_cred = GSS_C_NO_CREDENTIAL;
+ spnego_ctx->mic_reqd = 0;
+ spnego_ctx->mic_sent = 0;
+ spnego_ctx->mic_rcvd = 0;
+ spnego_ctx->mech_complete = 0;
+ spnego_ctx->nego_done = 0;
+ spnego_ctx->internal_name = GSS_C_NO_NAME;
+ spnego_ctx->actual_mech = GSS_C_NO_OID;
+
+ check_spnego_options(spnego_ctx);
+
+ return (spnego_ctx);
+}
+
+/*
+ * Both initiator and acceptor call here to verify and/or create
+ * mechListMIC, and to consistency-check the MIC state.
+ */
+static OM_uint32
+handle_mic(OM_uint32 *minor_status, gss_buffer_t mic_in,
+ int send_mechtok, spnego_gss_ctx_id_t sc,
+ gss_buffer_t *mic_out,
+ OM_uint32 *negState, send_token_flag *tokflag)
+{
+ OM_uint32 ret;
+
+ ret = GSS_S_FAILURE;
+ *mic_out = GSS_C_NO_BUFFER;
+ if (mic_in != GSS_C_NO_BUFFER) {
+ if (sc->mic_rcvd) {
+ /* Reject MIC if we've already received a MIC. */
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ } else if (sc->mic_reqd && !send_mechtok) {
+ /*
+ * If the peer sends the final mechanism token, it
+ * must send the MIC with that token if the
+ * negotiation requires MICs.
+ */
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ ret = process_mic(minor_status, mic_in, sc, mic_out,
+ negState, tokflag);
+ if (ret != GSS_S_COMPLETE) {
+ return ret;
+ }
+ if (sc->mic_reqd) {
+ assert(sc->mic_sent || sc->mic_rcvd);
+ }
+ if (sc->mic_sent && sc->mic_rcvd) {
+ ret = GSS_S_COMPLETE;
+ *negState = ACCEPT_COMPLETE;
+ if (*mic_out == GSS_C_NO_BUFFER) {
+ /*
+ * We sent a MIC on the previous pass; we
+ * shouldn't be sending a mechanism token.
+ */
+ assert(!send_mechtok);
+ *tokflag = NO_TOKEN_SEND;
+ } else {
+ *tokflag = CONT_TOKEN_SEND;
+ }
+ } else if (sc->mic_reqd) {
+ *negState = ACCEPT_INCOMPLETE;
+ ret = GSS_S_CONTINUE_NEEDED;
+ } else if (*negState == ACCEPT_COMPLETE) {
+ ret = GSS_S_COMPLETE;
+ } else {
+ ret = GSS_S_CONTINUE_NEEDED;
+ }
+ return ret;
+}
+
+/*
+ * Perform the actual verification and/or generation of mechListMIC.
+ */
+static OM_uint32
+process_mic(OM_uint32 *minor_status, gss_buffer_t mic_in,
+ spnego_gss_ctx_id_t sc, gss_buffer_t *mic_out,
+ OM_uint32 *negState, send_token_flag *tokflag)
+{
+ OM_uint32 ret, tmpmin;
+ gss_qop_t qop_state;
+ gss_buffer_desc tmpmic = GSS_C_EMPTY_BUFFER;
+
+ ret = GSS_S_FAILURE;
+ if (mic_in != GSS_C_NO_BUFFER) {
+ ret = gss_verify_mic(minor_status, sc->ctx_handle,
+ &sc->DER_mechTypes,
+ mic_in, &qop_state);
+ if (ret != GSS_S_COMPLETE) {
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ return ret;
+ }
+ /* If we got a MIC, we must send a MIC. */
+ sc->mic_reqd = 1;
+ sc->mic_rcvd = 1;
+ }
+ if (sc->mic_reqd && !sc->mic_sent) {
+ ret = gss_get_mic(minor_status, sc->ctx_handle,
+ GSS_C_QOP_DEFAULT,
+ &sc->DER_mechTypes,
+ &tmpmic);
+ if (ret != GSS_S_COMPLETE) {
+ gss_release_buffer(&tmpmin, &tmpmic);
+ *tokflag = NO_TOKEN_SEND;
+ return ret;
+ }
+ *mic_out = malloc(sizeof(gss_buffer_desc));
+ if (*mic_out == GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, &tmpmic);
+ *tokflag = NO_TOKEN_SEND;
+ return GSS_S_FAILURE;
+ }
+ **mic_out = tmpmic;
+ sc->mic_sent = 1;
+ }
+ return GSS_S_COMPLETE;
+}
+
+/*
+ * Initial call to spnego_gss_init_sec_context().
+ */
+static OM_uint32
+init_ctx_new(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ gss_ctx_id_t *ctx,
+ gss_OID_set *mechSet,
+ send_token_flag *tokflag)
+{
+ OM_uint32 ret, tmpmin;
+ gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
+ spnego_gss_ctx_id_t sc = NULL;
+
+ /* determine negotiation mech set */
+ if (cred == GSS_C_NO_CREDENTIAL) {
+ ret = get_available_mechs(minor_status, GSS_C_NO_NAME,
+ GSS_C_INITIATE, &creds, mechSet);
+ gss_release_cred(&tmpmin, &creds);
+ } else {
+ /*
+ * Use the list of mechs included in the cred that we
+ * were given.
+ */
+ ret = gss_inquire_cred(minor_status, cred,
+ NULL, NULL, NULL, mechSet);
+ }
+ if (ret != GSS_S_COMPLETE)
+ return ret;
+
+ sc = create_spnego_ctx();
+ if (sc == NULL)
+ return GSS_S_FAILURE;
+
+ /*
+ * need to pull the first mech from mechSet to do first
+ * gss_init_sec_context()
+ */
+ ret = generic_gss_copy_oid(minor_status, (*mechSet)->elements,
+ &sc->internal_mech);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+
+ if (put_mech_set(*mechSet, &sc->DER_mechTypes) < 0) {
+ generic_gss_release_oid(&tmpmin, &sc->internal_mech);
+ ret = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ /*
+ * The actual context is not yet determined, set the output
+ * context handle to refer to the spnego context itself.
+ */
+ sc->ctx_handle = GSS_C_NO_CONTEXT;
+ *ctx = (gss_ctx_id_t)sc;
+ *tokflag = INIT_TOKEN_SEND;
+ ret = GSS_S_CONTINUE_NEEDED;
+
+cleanup:
+ gss_release_oid_set(&tmpmin, mechSet);
+ return ret;
+}
+
+/*
+ * Called by second and later calls to spnego_gss_init_sec_context()
+ * to decode reply and update state.
+ */
+static OM_uint32
+init_ctx_cont(OM_uint32 *minor_status, gss_ctx_id_t *ctx, gss_buffer_t buf,
+ gss_buffer_t *responseToken, gss_buffer_t *mechListMIC,
+ OM_uint32 *negState, send_token_flag *tokflag)
+{
+ OM_uint32 ret, tmpmin, acc_negState;
+ unsigned char *ptr;
+ spnego_gss_ctx_id_t sc;
+ gss_OID supportedMech = GSS_C_NO_OID;
+
+ sc = (spnego_gss_ctx_id_t)*ctx;
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+
+ ptr = buf->value;
+ ret = get_negTokenResp(minor_status, ptr, buf->length,
+ &acc_negState, &supportedMech,
+ responseToken, mechListMIC);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+ if (acc_negState == ACCEPT_DEFECTIVE_TOKEN &&
+ supportedMech == GSS_C_NO_OID &&
+ *responseToken == GSS_C_NO_BUFFER &&
+ *mechListMIC == GSS_C_NO_BUFFER) {
+ /* Reject "empty" token. */
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ }
+ if (acc_negState == REJECT) {
+ *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+ *tokflag = NO_TOKEN_SEND;
+ ret = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ /*
+ * nego_done is false for the first call to init_ctx_cont()
+ */
+ if (!sc->nego_done) {
+ ret = init_ctx_nego(minor_status, sc,
+ acc_negState,
+ supportedMech, responseToken,
+ mechListMIC,
+ negState, tokflag);
+ } else if (!sc->mech_complete &&
+ *responseToken == GSS_C_NO_BUFFER) {
+ /*
+ * mech not finished and mech token missing
+ */
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ } else {
+ *negState = ACCEPT_INCOMPLETE;
+ *tokflag = CONT_TOKEN_SEND;
+ ret = GSS_S_CONTINUE_NEEDED;
+ }
+cleanup:
+ if (supportedMech != GSS_C_NO_OID)
+ generic_gss_release_oid(&tmpmin, &supportedMech);
+ return ret;
+}
+
+/*
+ * Consistency checking and mechanism negotiation handling for second
+ * call of spnego_gss_init_sec_context(). Call init_ctx_reselect() to
+ * update internal state if acceptor has counter-proposed.
+ */
+static OM_uint32
+init_ctx_nego(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+ OM_uint32 acc_negState, gss_OID supportedMech,
+ gss_buffer_t *responseToken, gss_buffer_t *mechListMIC,
+ OM_uint32 *negState, send_token_flag *tokflag)
+{
+ OM_uint32 ret;
+
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ /*
+ * Both supportedMech and negState must be present in first
+ * acceptor token.
+ */
+ if (supportedMech == GSS_C_NO_OID) {
+ *minor_status = ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ if (acc_negState == ACCEPT_DEFECTIVE_TOKEN) {
+ *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ if (!g_OID_equal(supportedMech, sc->internal_mech)) {
+ ret = init_ctx_reselect(minor_status, sc,
+ acc_negState, supportedMech,
+ responseToken, mechListMIC,
+ negState, tokflag);
+
+ } else if (*responseToken == GSS_C_NO_BUFFER) {
+ if (sc->mech_complete) {
+ /*
+ * Mech completed on first call to its
+ * init_sec_context(). Acceptor sends no mech
+ * token.
+ */
+ *negState = ACCEPT_COMPLETE;
+ *tokflag = NO_TOKEN_SEND;
+ ret = GSS_S_COMPLETE;
+ } else {
+ /*
+ * Reject missing mech token when optimistic
+ * mech selected.
+ */
+ *minor_status = ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR;
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ }
+ } else if (sc->mech_complete) {
+ /* Reject spurious mech token. */
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ } else {
+ *negState = ACCEPT_INCOMPLETE;
+ *tokflag = CONT_TOKEN_SEND;
+ ret = GSS_S_CONTINUE_NEEDED;
+ }
+ sc->nego_done = 1;
+ return ret;
+}
+
+/*
+ * Handle acceptor's counter-proposal of an alternative mechanism.
+ */
+static OM_uint32
+init_ctx_reselect(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+ OM_uint32 acc_negState, gss_OID supportedMech,
+ gss_buffer_t *responseToken, gss_buffer_t *mechListMIC,
+ OM_uint32 *negState, send_token_flag *tokflag)
+{
+ OM_uint32 ret, tmpmin;
+
+ generic_gss_release_oid(&tmpmin, &sc->internal_mech);
+ gss_delete_sec_context(&tmpmin, &sc->ctx_handle,
+ GSS_C_NO_BUFFER);
+
+ ret = generic_gss_copy_oid(minor_status, supportedMech,
+ &sc->internal_mech);
+ if (ret != GSS_S_COMPLETE) {
+ sc->internal_mech = GSS_C_NO_OID;
+ *tokflag = NO_TOKEN_SEND;
+ return ret;
+ }
+ if (*responseToken != GSS_C_NO_BUFFER) {
+ /* Reject spurious mech token. */
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ /*
+ * Windows 2003 and earlier don't correctly send a
+ * negState of request-mic when counter-proposing a
+ * mechanism. They probably don't handle mechListMICs
+ * properly either.
+ */
+ if (acc_negState != REQUEST_MIC)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ sc->mech_complete = 0;
+ sc->mic_reqd = 1;
+ *negState = REQUEST_MIC;
+ *tokflag = CONT_TOKEN_SEND;
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+/*
+ * Wrap call to mechanism gss_init_sec_context() and update state
+ * accordingly.
+ */
+static OM_uint32
+init_ctx_call_init(OM_uint32 *minor_status,
+ spnego_gss_ctx_id_t sc,
+ gss_cred_id_t claimant_cred_handle,
+ gss_name_t target_name,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_buffer_t mechtok_in,
+ gss_OID *actual_mech,
+ gss_buffer_t mechtok_out,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ OM_uint32 *negState,
+ send_token_flag *send_token)
+{
+ OM_uint32 ret;
+
+ ret = gss_init_sec_context(minor_status,
+ claimant_cred_handle,
+ &sc->ctx_handle,
+ target_name,
+ sc->internal_mech,
+ (req_flags | GSS_C_INTEG_FLAG),
+ time_req,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ mechtok_in,
+ &sc->actual_mech,
+ mechtok_out,
+ &sc->ctx_flags,
+ time_rec);
+ if (ret == GSS_S_COMPLETE) {
+ sc->mech_complete = 1;
+ if (ret_flags != NULL)
+ *ret_flags = sc->ctx_flags;
+ /*
+ * If this isn't the first time we've been called,
+ * we're done unless a MIC needs to be
+ * generated/handled.
+ */
+ if (*send_token == CONT_TOKEN_SEND &&
+ (!sc->mic_reqd ||
+ !(sc->ctx_flags & GSS_C_INTEG_FLAG))) {
+
+ *negState = ACCEPT_COMPLETE;
+ ret = GSS_S_COMPLETE;
+ if (mechtok_out->length == 0) {
+ *send_token = NO_TOKEN_SEND;
+ }
+ } else {
+ *negState = ACCEPT_INCOMPLETE;
+ ret = GSS_S_CONTINUE_NEEDED;
+ }
+ } else if (ret != GSS_S_CONTINUE_NEEDED) {
+ if (*send_token == INIT_TOKEN_SEND) {
+ /* Don't output token on error if first call. */
+ *send_token = NO_TOKEN_SEND;
+ } else {
+ *send_token = ERROR_TOKEN_SEND;
+ }
+ *negState = REJECT;
+ }
+ return ret;
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_init_sec_context(void *ct,
+ OM_uint32 *minor_status,
+ gss_cred_id_t claimant_cred_handle,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec)
+{
+ /*
+ * send_token is used to indicate in later steps
+ * what type of token, if any should be sent or processed.
+ * NO_TOKEN_SEND = no token should be sent
+ * INIT_TOKEN_SEND = initial token will be sent
+ * CONT_TOKEN_SEND = continuing tokens to be sent
+ * CHECK_MIC = no token to be sent, but have a MIC to check.
+ */
+ send_token_flag send_token = NO_TOKEN_SEND;
+ OM_uint32 tmpmin, ret, negState;
+ gss_buffer_t mechtok_in, mechListMIC_in, mechListMIC_out;
+ gss_buffer_desc mechtok_out = GSS_C_EMPTY_BUFFER;
+ gss_OID_set mechSet = GSS_C_NO_OID_SET;
+ spnego_gss_ctx_id_t spnego_ctx = NULL;
+
+ dsyslog("Entering init_sec_context\n");
+
+ mechtok_in = mechListMIC_out = mechListMIC_in = GSS_C_NO_BUFFER;
+ negState = REJECT;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+ if (output_token != GSS_C_NO_BUFFER) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+ if (minor_status == NULL ||
+ output_token == GSS_C_NO_BUFFER ||
+ context_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (actual_mech != NULL)
+ *actual_mech = GSS_C_NO_OID;
+
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ ret = init_ctx_new(minor_status, claimant_cred_handle,
+ context_handle, &mechSet, &send_token);
+ if (ret != GSS_S_CONTINUE_NEEDED) {
+ goto cleanup;
+ }
+ } else {
+ ret = init_ctx_cont(minor_status, context_handle,
+ input_token, &mechtok_in,
+ &mechListMIC_in, &negState, &send_token);
+ if (HARD_ERROR(ret)) {
+ goto cleanup;
+ }
+ }
+ spnego_ctx = (spnego_gss_ctx_id_t)*context_handle;
+ if (!spnego_ctx->mech_complete) {
+ ret = init_ctx_call_init(
+ minor_status, spnego_ctx,
+ claimant_cred_handle,
+ target_name, req_flags,
+ time_req, mechtok_in,
+ actual_mech, &mechtok_out,
+ ret_flags, time_rec,
+ &negState, &send_token);
+ }
+ /* create mic/check mic */
+ if (!HARD_ERROR(ret) && spnego_ctx->mech_complete &&
+ (spnego_ctx->ctx_flags & GSS_C_INTEG_FLAG)) {
+
+ ret = handle_mic(minor_status,
+ mechListMIC_in,
+ (mechtok_out.length != 0),
+ spnego_ctx, &mechListMIC_out,
+ &negState, &send_token);
+ }
+cleanup:
+ if (send_token == INIT_TOKEN_SEND) {
+ if (make_spnego_tokenInit_msg(spnego_ctx,
+ mechListMIC_out,
+ req_flags,
+ &mechtok_out, send_token,
+ output_token) < 0) {
+
+ ret = GSS_S_FAILURE;
+ }
+ } else if (send_token != NO_TOKEN_SEND) {
+ if (make_spnego_tokenTarg_msg(negState, GSS_C_NO_OID,
+ &mechtok_out, mechListMIC_out,
+ send_token,
+ output_token) < 0) {
+ ret = GSS_S_FAILURE;
+ }
+ }
+ if (ret == GSS_S_COMPLETE) {
+ /*
+ * Now, switch the output context to refer to the
+ * negotiated mechanism's context.
+ */
+ *context_handle = (gss_ctx_id_t)spnego_ctx->ctx_handle;
+ if (actual_mech != NULL)
+ *actual_mech = spnego_ctx->actual_mech;
+ release_spnego_ctx(&spnego_ctx);
+ } else if (ret != GSS_S_CONTINUE_NEEDED) {
+ if (spnego_ctx != NULL) {
+ gss_delete_sec_context(&tmpmin,
+ &spnego_ctx->ctx_handle,
+ GSS_C_NO_BUFFER);
+ release_spnego_ctx(&spnego_ctx);
+ }
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+ if (mechtok_in != GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, mechtok_in);
+ free(mechtok_in);
+ }
+ if (mechListMIC_in != GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, mechListMIC_in);
+ free(mechListMIC_in);
+ }
+ if (mechListMIC_out != GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, mechListMIC_out);
+ free(mechListMIC_out);
+ }
+ if (mechSet != GSS_C_NO_OID_SET) {
+ gss_release_oid_set(&tmpmin, &mechSet);
+ }
+ return ret;
+} /* init_sec_context */
+
+/*
+ * Set negState to REJECT if the token is defective, else
+ * ACCEPT_INCOMPLETE or REQUEST_MIC, depending on whether initiator's
+ * preferred mechanism is supported.
+ */
+static OM_uint32
+acc_ctx_new(OM_uint32 *minor_status,
+ gss_buffer_t buf,
+ gss_ctx_id_t *ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t *mechToken,
+ gss_buffer_t *mechListMIC,
+ OM_uint32 *negState,
+ send_token_flag *return_token)
+{
+ OM_uint32 tmpmin, ret, req_flags;
+ gss_OID_set supported_mechSet, mechTypes;
+ gss_buffer_desc der_mechTypes;
+ gss_OID mech_wanted;
+ spnego_gss_ctx_id_t sc = NULL;
+
+ *ctx = GSS_C_NO_CONTEXT;
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ der_mechTypes.length = 0;
+ der_mechTypes.value = NULL;
+ *mechToken = *mechListMIC = GSS_C_NO_BUFFER;
+ supported_mechSet = mechTypes = GSS_C_NO_OID_SET;
+ *return_token = ERROR_TOKEN_SEND;
+ *negState = REJECT;
+ *minor_status = 0;
+
+ ret = get_negTokenInit(minor_status, buf, &der_mechTypes,
+ &mechTypes, &req_flags,
+ mechToken, mechListMIC);
+ if (ret != GSS_S_COMPLETE) {
+ goto cleanup;
+ }
+ if (cred != GSS_C_NO_CREDENTIAL) {
+ ret = gss_inquire_cred(minor_status, cred, NULL, NULL,
+ NULL, &supported_mechSet);
+ if (ret != GSS_S_COMPLETE) {
+ *return_token = NO_TOKEN_SEND;
+ goto cleanup;
+ }
+ } else {
+ ret = get_available_mechs(minor_status, GSS_C_NO_NAME,
+ GSS_C_ACCEPT, NULL,
+ &supported_mechSet);
+ if (ret != GSS_S_COMPLETE) {
+ *return_token = NO_TOKEN_SEND;
+ goto cleanup;
+ }
+ }
+ /*
+ * Select the best match between the list of mechs
+ * that the initiator requested and the list that
+ * the acceptor will support.
+ */
+ mech_wanted = negotiate_mech_type(minor_status,
+ supported_mechSet,
+ mechTypes,
+ negState);
+ if (*negState == REJECT) {
+ ret = GSS_S_BAD_MECH;
+ goto cleanup;
+ }
+ sc = create_spnego_ctx();
+ if (sc == NULL) {
+ ret = GSS_S_FAILURE;
+ *return_token = NO_TOKEN_SEND;
+ generic_gss_release_oid(&tmpmin, &mech_wanted);
+ goto cleanup;
+ }
+ sc->internal_mech = mech_wanted;
+ sc->DER_mechTypes = der_mechTypes;
+ der_mechTypes.length = 0;
+ der_mechTypes.value = NULL;
+
+ if (*negState == REQUEST_MIC)
+ sc->mic_reqd = 1;
+
+ *return_token = INIT_TOKEN_SEND;
+ sc->firstpass = 1;
+ *ctx = (gss_ctx_id_t)sc;
+ ret = GSS_S_COMPLETE;
+cleanup:
+ gss_release_oid_set(&tmpmin, &mechTypes);
+ gss_release_oid_set(&tmpmin, &supported_mechSet);
+ if (der_mechTypes.length != 0)
+ gss_release_buffer(&tmpmin, &der_mechTypes);
+
+ return ret;
+}
+
+static OM_uint32
+acc_ctx_cont(OM_uint32 *minstat,
+ gss_buffer_t buf,
+ gss_ctx_id_t *ctx,
+ gss_buffer_t *responseToken,
+ gss_buffer_t *mechListMIC,
+ OM_uint32 *negState,
+ send_token_flag *return_token)
+{
+ OM_uint32 ret, tmpmin;
+ gss_OID supportedMech;
+ spnego_gss_ctx_id_t sc;
+ int len;
+ unsigned char *ptr, *bufstart;
+
+ sc = (spnego_gss_ctx_id_t)*ctx;
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ *negState = REJECT;
+ *minstat = 0;
+ supportedMech = GSS_C_NO_OID;
+ *return_token = ERROR_TOKEN_SEND;
+ *responseToken = *mechListMIC = GSS_C_NO_BUFFER;
+
+ ptr = bufstart = buf->value;
+#define REMAIN (buf->length - (ptr - bufstart))
+ if (REMAIN > INT_MAX)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ /*
+ * Attempt to work with old Sun SPNEGO.
+ */
+ if (*ptr == HEADER_ID) {
+ ret = g_verify_token_header(gss_mech_spnego,
+ &len, &ptr, 0, REMAIN);
+ if (ret) {
+ *minstat = ret;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ }
+ if (*ptr != (CONTEXT | 0x01)) {
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ ret = get_negTokenResp(minstat, ptr, REMAIN,
+ negState, &supportedMech,
+ responseToken, mechListMIC);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+
+ if (*responseToken == GSS_C_NO_BUFFER &&
+ *mechListMIC == GSS_C_NO_BUFFER) {
+
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+ if (supportedMech != GSS_C_NO_OID) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+ sc->firstpass = 0;
+ *negState = ACCEPT_INCOMPLETE;
+ *return_token = CONT_TOKEN_SEND;
+cleanup:
+ if (supportedMech != GSS_C_NO_OID) {
+ generic_gss_release_oid(&tmpmin, &supportedMech);
+ }
+ return ret;
+#undef REMAIN
+}
+
+/*
+ * Verify that mech OID is either exactly the same as the negotiated
+ * mech OID, or is a mech OID supported by the negotiated mech. MS
+ * implementations can list a most preferred mech using an incorrect
+ * krb5 OID while emitting a krb5 initiator mech token having the
+ * correct krb5 mech OID.
+ */
+static OM_uint32
+acc_ctx_vfy_oid(OM_uint32 *minor_status,
+ spnego_gss_ctx_id_t sc, gss_OID mechoid,
+ OM_uint32 *negState, send_token_flag *tokflag)
+{
+ OM_uint32 ret, tmpmin;
+ gss_mechanism mech = NULL;
+ gss_OID_set mech_set = GSS_C_NO_OID_SET;
+ int present = 0;
+
+ if (g_OID_equal(sc->internal_mech, mechoid))
+ return GSS_S_COMPLETE;
+
+ mech = gssint_get_mechanism(sc->internal_mech);
+ if (mech == NULL || mech->gss_indicate_mechs == NULL) {
+ *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ return GSS_S_BAD_MECH;
+ }
+ ret = mech->gss_indicate_mechs(NULL, minor_status, &mech_set);
+ if (ret != GSS_S_COMPLETE) {
+ *tokflag = NO_TOKEN_SEND;
+ goto cleanup;
+ }
+ ret = gss_test_oid_set_member(minor_status, mechoid,
+ mech_set, &present);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+ if (!present) {
+ *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED;
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ ret = GSS_S_BAD_MECH;
+ }
+cleanup:
+ gss_release_oid_set(&tmpmin, &mech_set);
+ return ret;
+}
+
+/*
+ * Wrap call to gss_accept_sec_context() and update state
+ * accordingly.
+ */
+static OM_uint32
+acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
+ gss_cred_id_t cred, gss_buffer_t mechtok_in,
+ gss_OID *mech_type, gss_buffer_t mechtok_out,
+ OM_uint32 *ret_flags, OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle,
+ OM_uint32 *negState, send_token_flag *tokflag)
+{
+ OM_uint32 ret;
+ gss_OID_desc mechoid;
+
+ /*
+ * mechoid is an alias; don't free it.
+ */
+ ret = gssint_get_mech_type(&mechoid, mechtok_in);
+ if (ret != GSS_S_COMPLETE) {
+ *tokflag = NO_TOKEN_SEND;
+ return ret;
+ }
+ ret = acc_ctx_vfy_oid(minor_status, sc, &mechoid,
+ negState, tokflag);
+ if (ret != GSS_S_COMPLETE)
+ return ret;
+
+ ret = gss_accept_sec_context(minor_status,
+ &sc->ctx_handle,
+ cred,
+ mechtok_in,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &sc->internal_name,
+ mech_type,
+ mechtok_out,
+ &sc->ctx_flags,
+ time_rec,
+ delegated_cred_handle);
+ if (ret == GSS_S_COMPLETE) {
+#ifdef MS_BUG_TEST
+ /*
+ * Force MIC to be not required even if we previously
+ * requested a MIC.
+ */
+ char *envstr = getenv("MS_FORCE_NO_MIC");
+
+ if (envstr != NULL && strcmp(envstr, "1") == 0 &&
+ !(sc->ctx_flags & GSS_C_MUTUAL_FLAG) &&
+ sc->mic_reqd) {
+
+ sc->mic_reqd = 0;
+ }
+#endif
+ sc->mech_complete = 1;
+ if (ret_flags != NULL)
+ *ret_flags = sc->ctx_flags;
+
+ if (!sc->mic_reqd) {
+ *negState = ACCEPT_COMPLETE;
+ ret = GSS_S_COMPLETE;
+ } else {
+ ret = GSS_S_CONTINUE_NEEDED;
+ }
+ } else if (ret != GSS_S_CONTINUE_NEEDED) {
+ *negState = REJECT;
+ *tokflag = ERROR_TOKEN_SEND;
+ }
+ return ret;
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_accept_sec_context(void *ct,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_cred_id_t verifier_cred_handle,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle)
+{
+ OM_uint32 ret, tmpret, tmpmin, negState;
+ send_token_flag return_token;
+ gss_buffer_t mechtok_in, mic_in, mic_out;
+ gss_buffer_desc mechtok_out = GSS_C_EMPTY_BUFFER;
+ spnego_gss_ctx_id_t sc = NULL;
+ OM_uint32 mechstat = GSS_S_FAILURE;
+
+ mechtok_in = mic_in = mic_out = GSS_C_NO_BUFFER;
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+ if (output_token != GSS_C_NO_BUFFER) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+
+ if (minor_status == NULL ||
+ output_token == GSS_C_NO_BUFFER ||
+ context_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (input_token == GSS_C_NO_BUFFER)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ if (src_name != NULL)
+ *src_name = GSS_C_NO_NAME;
+ if (mech_type != NULL)
+ *mech_type = GSS_C_NO_OID;
+ if (time_rec != NULL)
+ *time_rec = 0;
+ if (ret_flags != NULL)
+ *ret_flags = 0;
+ if (delegated_cred_handle != NULL)
+ *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+ /* Can set negState to REQUEST_MIC */
+ ret = acc_ctx_new(minor_status, input_token,
+ context_handle, verifier_cred_handle,
+ &mechtok_in, &mic_in,
+ &negState, &return_token);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+ ret = GSS_S_CONTINUE_NEEDED;
+ } else {
+ /* Can set negState to ACCEPT_INCOMPLETE */
+ ret = acc_ctx_cont(minor_status, input_token,
+ context_handle, &mechtok_in,
+ &mic_in, &negState, &return_token);
+ if (ret != GSS_S_COMPLETE)
+ goto cleanup;
+ ret = GSS_S_CONTINUE_NEEDED;
+ }
+ sc = (spnego_gss_ctx_id_t)*context_handle;
+ /*
+ * Handle mechtok_in and mic_in only if they are
+ * present in input_token. If neither is present, whether
+ * this is an error depends on whether this is the first
+ * round-trip. RET is set to a default value according to
+ * whether it is the first round-trip.
+ */
+ mechstat = GSS_S_FAILURE;
+ if (negState != REQUEST_MIC && mechtok_in != GSS_C_NO_BUFFER) {
+ ret = acc_ctx_call_acc(minor_status, sc,
+ verifier_cred_handle, mechtok_in,
+ mech_type, &mechtok_out,
+ ret_flags, time_rec,
+ delegated_cred_handle,
+ &negState, &return_token);
+ } else if (negState == REQUEST_MIC) {
+ mechstat = GSS_S_CONTINUE_NEEDED;
+ }
+ if (!HARD_ERROR(ret) && sc->mech_complete &&
+ (sc->ctx_flags & GSS_C_INTEG_FLAG)) {
+
+ ret = handle_mic(minor_status, mic_in,
+ (mechtok_out.length != 0),
+ sc, &mic_out,
+ &negState, &return_token);
+ }
+cleanup:
+ if (return_token != NO_TOKEN_SEND && return_token != CHECK_MIC) {
+ tmpret = make_spnego_tokenTarg_msg(negState, sc->internal_mech,
+ &mechtok_out, mic_out,
+ return_token,
+ output_token);
+ if (tmpret != GSS_S_COMPLETE) {
+ ret = tmpret;
+ }
+ }
+ if (ret == GSS_S_COMPLETE) {
+ *context_handle = (gss_ctx_id_t)sc->ctx_handle;
+ if (sc->internal_name != GSS_C_NO_NAME &&
+ src_name != NULL) {
+ *src_name = sc->internal_name;
+ }
+ release_spnego_ctx(&sc);
+ }
+ gss_release_buffer(&tmpmin, &mechtok_out);
+ if (mechtok_in != GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, mechtok_in);
+ free(mechtok_in);
+ }
+ if (mic_in != GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, mic_in);
+ free(mic_in);
+ }
+ if (mic_out != GSS_C_NO_BUFFER) {
+ gss_release_buffer(&tmpmin, mic_out);
+ free(mic_out);
+ }
+ return ret;
+}
+
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_display_status(void *ctx,
+ OM_uint32 *minor_status,
+ OM_uint32 status_value,
+ int status_type,
+ gss_OID mech_type,
+ OM_uint32 *message_context,
+ gss_buffer_t status_string)
+{
+ dsyslog("Entering display_status\n");
+
+ *message_context = 0;
+ switch (status_value) {
+ case ERR_SPNEGO_NO_MECHS_AVAILABLE:
+ /* CSTYLED */
+ *status_string = make_err_msg("SPNEGO cannot find mechanisms to negotiate");
+ break;
+ case ERR_SPNEGO_NO_CREDS_ACQUIRED:
+ /* CSTYLED */
+ *status_string = make_err_msg("SPNEGO failed to acquire creds");
+ break;
+ case ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR:
+ /* CSTYLED */
+ *status_string = make_err_msg("SPNEGO acceptor did not select a mechanism");
+ break;
+ case ERR_SPNEGO_NEGOTIATION_FAILED:
+ /* CSTYLED */
+ *status_string = make_err_msg("SPNEGO failed to negotiate a mechanism");
+ break;
+ case ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR:
+ /* CSTYLED */
+ *status_string = make_err_msg("SPNEGO acceptor did not return a valid token");
+ break;
+ default:
+ status_string->length = 0;
+ status_string->value = "";
+ break;
+ }
+
+ dsyslog("Leaving display_status\n");
+ return (GSS_S_COMPLETE);
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_import_name(void *ctx,
+ OM_uint32 *minor_status,
+ gss_buffer_t input_name_buffer,
+ gss_OID input_name_type,
+ gss_name_t *output_name)
+{
+ OM_uint32 status;
+
+ dsyslog("Entering import_name\n");
+
+ status = gss_import_name(minor_status, input_name_buffer,
+ input_name_type, output_name);
+
+ dsyslog("Leaving import_name\n");
+ return (status);
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_release_name(void *ctx,
+ OM_uint32 *minor_status,
+ gss_name_t *input_name)
+{
+ OM_uint32 status;
+
+ dsyslog("Entering release_name\n");
+
+ status = gss_release_name(minor_status, input_name);
+
+ dsyslog("Leaving release_name\n");
+ return (status);
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_display_name(void *ctx,
+ OM_uint32 *minor_status,
+ gss_name_t input_name,
+ gss_buffer_t output_name_buffer,
+ gss_OID *output_name_type)
+{
+ OM_uint32 status = GSS_S_COMPLETE;
+ dsyslog("Entering display_name\n");
+
+ status = gss_display_name(minor_status, input_name,
+ output_name_buffer, output_name_type);
+
+ dsyslog("Leaving display_name\n");
+ return (status);
+}
+
+/*ARGSUSED*/
+OM_uint32
+spnego_gss_inquire_names_for_mech(void *ctx,
+ OM_uint32 *minor_status,
+ gss_OID mechanism,
+ gss_OID_set *name_types)
+{
+ OM_uint32 major, minor;
+
+ dsyslog("Entering inquire_names_for_mech\n");
+ /*
+ * We only know how to handle our own mechanism.
+ */
+ if ((mechanism != GSS_C_NULL_OID) &&
+ !g_OID_equal(gss_mech_spnego, mechanism)) {
+ *minor_status = 0;
+ return (GSS_S_FAILURE);
+ }
+
+ major = gss_create_empty_oid_set(minor_status, name_types);
+ if (major == GSS_S_COMPLETE) {
+ /* Now add our members. */
+ if (((major = gss_add_oid_set_member(minor_status,
+ (gss_OID) GSS_C_NT_USER_NAME,
+ name_types)) == GSS_S_COMPLETE) &&
+ ((major = gss_add_oid_set_member(minor_status,
+ (gss_OID) GSS_C_NT_MACHINE_UID_NAME,
+ name_types)) == GSS_S_COMPLETE) &&
+ ((major = gss_add_oid_set_member(minor_status,
+ (gss_OID) GSS_C_NT_STRING_UID_NAME,
+ name_types)) == GSS_S_COMPLETE)) {
+ major = gss_add_oid_set_member(minor_status,
+ (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
+ name_types);
+ }
+
+ if (major != GSS_S_COMPLETE)
+ (void) gss_release_oid_set(&minor, name_types);
+ }
+
+ dsyslog("Leaving inquire_names_for_mech\n");
+ return (major);
+}
+
+OM_uint32
+spnego_gss_unseal(void *context,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int *conf_state,
+ int *qop_state)
+{
+ OM_uint32 ret;
+ ret = gss_unseal(minor_status,
+ context_handle,
+ input_message_buffer,
+ output_message_buffer,
+ conf_state,
+ qop_state);
+
+ return (ret);
+}
+
+OM_uint32
+spnego_gss_seal(void *context,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ int qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ OM_uint32 ret;
+ ret = gss_seal(minor_status,
+ context_handle,
+ conf_req_flag,
+ qop_req,
+ input_message_buffer,
+ conf_state,
+ output_message_buffer);
+
+ return (ret);
+}
+
+OM_uint32
+spnego_gss_process_context_token(void *context,
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t token_buffer)
+{
+ OM_uint32 ret;
+ ret = gss_process_context_token(minor_status,
+ context_handle,
+ token_buffer);
+
+ return (ret);
+}
+
+OM_uint32
+spnego_gss_delete_sec_context(void *context,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token)
+{
+ OM_uint32 ret = GSS_S_COMPLETE;
+ spnego_gss_ctx_id_t *ctx =
+ (spnego_gss_ctx_id_t *)context_handle;
+
+ if (context_handle == NULL)
+ return (GSS_S_FAILURE);
+
+ /*
+ * If this is still an SPNEGO mech, release it locally.
+ */
+ if (*ctx != NULL &&
+ (*ctx)->magic_num == SPNEGO_MAGIC_ID) {
+ (void) release_spnego_ctx(ctx);
+ } else {
+ ret = gss_delete_sec_context(minor_status,
+ context_handle,
+ output_token);
+ }
+
+ return (ret);
+}
+
+OM_uint32
+spnego_gss_context_time(void *context,
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 ret;
+ ret = gss_context_time(minor_status,
+ context_handle,
+ time_rec);
+ return (ret);
+}
+
+OM_uint32
+spnego_gss_export_sec_context(void *context,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t interprocess_token)
+{
+ OM_uint32 ret;
+ ret = gss_export_sec_context(minor_status,
+ context_handle,
+ interprocess_token);
+ return (ret);
+}
+
+OM_uint32
+spnego_gss_import_sec_context(void *context,
+ OM_uint32 *minor_status,
+ const gss_buffer_t interprocess_token,
+ gss_ctx_id_t *context_handle)
+{
+ OM_uint32 ret;
+ ret = gss_import_sec_context(minor_status,
+ interprocess_token,
+ context_handle);
+ return (ret);
+}
+
+OM_uint32
+spnego_gss_inquire_context(void *context,
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_name_t *src_name,
+ gss_name_t *targ_name,
+ OM_uint32 *lifetime_rec,
+ gss_OID *mech_type,
+ OM_uint32 *ctx_flags,
+ int *locally_initiated,
+ int *open)
+{
+ OM_uint32 ret = GSS_S_COMPLETE;
+
+ ret = gss_inquire_context(minor_status,
+ context_handle,
+ src_name,
+ targ_name,
+ lifetime_rec,
+ mech_type,
+ ctx_flags,
+ locally_initiated,
+ open);
+
+ return (ret);
+}
+
+OM_uint32
+spnego_gss_wrap_size_limit(void *context,
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 req_output_size,
+ OM_uint32 *max_input_size)
+{
+ OM_uint32 ret;
+ ret = gss_wrap_size_limit(minor_status,
+ context_handle,
+ conf_req_flag,
+ qop_req,
+ req_output_size,
+ max_input_size);
+ return (ret);
+}
+
+OM_uint32
+spnego_gss_sign(void *context,
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int qop_req,
+ const gss_buffer_t message_buffer,
+ gss_buffer_t message_token)
+{
+ OM_uint32 ret;
+ ret = gss_sign(minor_status,
+ context_handle,
+ qop_req,
+ message_buffer,
+ message_token);
+ return (ret);
+}
+
+OM_uint32
+spnego_gss_verify(void *context,
+ OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t msg_buffer,
+ const gss_buffer_t token_buffer,
+ int *qop_state)
+{
+ OM_uint32 ret;
+ ret = gss_verify_mic(minor_status,
+ context_handle,
+ msg_buffer,
+ token_buffer,
+ (gss_qop_t *)qop_state); /* XXX */
+ return (ret);
+}
+
+/*
+ * We will release everything but the ctx_handle so that it
+ * can be passed back to init/accept context. This routine should
+ * not be called until after the ctx_handle memory is assigned to
+ * the supplied context handle from init/accept context.
+ */
+static void
+release_spnego_ctx(spnego_gss_ctx_id_t *ctx)
+{
+ spnego_gss_ctx_id_t context;
+ OM_uint32 minor_stat;
+ context = *ctx;
+
+ if (context != NULL) {
+ (void) gss_release_buffer(&minor_stat,
+ &context->DER_mechTypes);
+
+ (void) generic_gss_release_oid(&minor_stat,
+ &context->internal_mech);
+
+ if (context->optionStr != NULL) {
+ free(context->optionStr);
+ context->optionStr = NULL;
+ }
+ free(context);
+ *ctx = NULL;
+ }
+}
+
+/*
+ * Can't use gss_indicate_mechs by itself to get available mechs for
+ * SPNEGO because it will also return the SPNEGO mech and we do not
+ * want to consider SPNEGO as an available security mech for
+ * negotiation. For this reason, get_available_mechs will return
+ * all available mechs except SPNEGO.
+ *
+ * If a ptr to a creds list is given, this function will attempt
+ * to acquire creds for the creds given and trim the list of
+ * returned mechanisms to only those for which creds are valid.
+ *
+ */
+static OM_uint32
+get_available_mechs(OM_uint32 *minor_status,
+ gss_name_t name, gss_cred_usage_t usage,
+ gss_cred_id_t *creds, gss_OID_set *rmechs)
+{
+ int i;
+ int found = 0;
+ OM_uint32 stat = GSS_S_COMPLETE, tmpmin;
+ gss_OID_set mechs, goodmechs;
+
+ stat = gss_indicate_mechs(minor_status, &mechs);
+
+ if (stat != GSS_S_COMPLETE) {
+ return (stat);
+ }
+
+ stat = gss_create_empty_oid_set(minor_status, rmechs);
+
+ if (stat != GSS_S_COMPLETE) {
+ (void) gss_release_oid_set(minor_status, &mechs);
+ return (stat);
+ }
+
+ for (i = 0; i < mechs->count && stat == GSS_S_COMPLETE; i++) {
+ if ((mechs->elements[i].length
+ != spnego_mechanism.mech_type.length) ||
+ memcmp(mechs->elements[i].elements,
+ spnego_mechanism.mech_type.elements,
+ spnego_mechanism.mech_type.length)) {
+
+ stat = gss_add_oid_set_member(minor_status,
+ &mechs->elements[i],
+ rmechs);
+ if (stat == GSS_S_COMPLETE)
+ found++;
+ }
+ }
+
+ /*
+ * If the caller wanted a list of creds returned,
+ * trim the list of mechanisms down to only those
+ * for which the creds are valid.
+ */
+ if (found > 0 && stat == GSS_S_COMPLETE && creds != NULL) {
+ stat = gss_acquire_cred(minor_status,
+ name, GSS_C_INDEFINITE, *rmechs, usage, creds,
+ &goodmechs, NULL);
+
+ /*
+ * Drop the old list in favor of the new
+ * "trimmed" list.
+ */
+ (void) gss_release_oid_set(&tmpmin, rmechs);
+ if (stat == GSS_S_COMPLETE) {
+ (void) gssint_copy_oid_set(&tmpmin,
+ goodmechs, rmechs);
+ (void) gss_release_oid_set(&tmpmin, &goodmechs);
+ }
+ }
+
+ (void) gss_release_oid_set(&tmpmin, &mechs);
+ if (found == 0 || stat != GSS_S_COMPLETE) {
+ *minor_status = ERR_SPNEGO_NO_MECHS_AVAILABLE;
+ if (stat == GSS_S_COMPLETE)
+ stat = GSS_S_FAILURE;
+ }
+
+ return (stat);
+}
+
+/* following are token creation and reading routines */
+
+/*
+ * If buff_in is not pointing to a MECH_OID, then return NULL and do not
+ * advance the buffer, otherwise, decode the mech_oid from the buffer and
+ * place in gss_OID.
+ */
+static gss_OID
+get_mech_oid(OM_uint32 *minor_status, unsigned char **buff_in, size_t length)
+{
+ OM_uint32 status;
+ gss_OID_desc toid;
+ gss_OID mech_out = NULL;
+ unsigned char *start, *end;
+
+ if (length < 1 || **buff_in != MECH_OID)
+ return (NULL);
+
+ start = *buff_in;
+ end = start + length;
+
+ (*buff_in)++;
+ toid.length = *(*buff_in)++;
+
+ if ((*buff_in + toid.length) > end)
+ return (NULL);
+
+ toid.elements = *buff_in;
+ *buff_in += toid.length;
+
+ status = generic_gss_copy_oid(minor_status, &toid, &mech_out);
+
+ if (status != GSS_S_COMPLETE)
+ mech_out = NULL;
+
+ return (mech_out);
+}
+
+/*
+ * der encode the given mechanism oid into buf_out, advancing the
+ * buffer pointer.
+ */
+
+static int
+put_mech_oid(unsigned char **buf_out, gss_OID_const mech, int buflen)
+{
+ if (buflen < mech->length + 2)
+ return (-1);
+ *(*buf_out)++ = MECH_OID;
+ *(*buf_out)++ = (unsigned char) mech->length;
+ memcpy((void *)(*buf_out), mech->elements, mech->length);
+ *buf_out += mech->length;
+ return (0);
+}
+
+/*
+ * verify that buff_in points to an octet string, if it does not,
+ * return NULL and don't advance the pointer. If it is an octet string
+ * decode buff_in into a gss_buffer_t and return it, advancing the
+ * buffer pointer.
+ */
+static gss_buffer_t
+get_input_token(unsigned char **buff_in, int buff_length)
+{
+ gss_buffer_t input_token;
+ unsigned int bytes;
+
+ if (**buff_in != OCTET_STRING)
+ return (NULL);
+
+ (*buff_in)++;
+ input_token = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
+
+ if (input_token == NULL)
+ return (NULL);
+
+ input_token->length = gssint_get_der_length(buff_in, buff_length, &bytes);
+ if ((int)input_token->length == -1) {
+ free(input_token);
+ return (NULL);
+ }
+ input_token->value = malloc(input_token->length);
+
+ if (input_token->value == NULL) {
+ free(input_token);
+ return (NULL);
+ }
+
+ (void) memcpy(input_token->value, *buff_in, input_token->length);
+ *buff_in += input_token->length;
+ return (input_token);
+}
+
+/*
+ * verify that the input token length is not 0. If it is, just return.
+ * If the token length is greater than 0, der encode as an octet string
+ * and place in buf_out, advancing buf_out.
+ */
+
+static int
+put_input_token(unsigned char **buf_out, gss_buffer_t input_token,
+ int buflen)
+{
+ int ret;
+
+ /* if token length is 0, we do not want to send */
+ if (input_token->length == 0)
+ return (0);
+
+ if (input_token->length > buflen)
+ return (-1);
+
+ *(*buf_out)++ = OCTET_STRING;
+ if ((ret = gssint_put_der_length(input_token->length, buf_out,
+ input_token->length)))
+ return (ret);
+ TWRITE_STR(*buf_out, input_token->value, ((int)input_token->length));
+ return (0);
+}
+
+/*
+ * verify that buff_in points to a sequence of der encoding. The mech
+ * set is the only sequence of encoded object in the token, so if it is
+ * a sequence of encoding, decode the mechset into a gss_OID_set and
+ * return it, advancing the buffer pointer.
+ */
+static gss_OID_set
+get_mech_set(OM_uint32 *minor_status, unsigned char **buff_in, int buff_length)
+{
+ gss_OID_set returned_mechSet;
+ OM_uint32 major_status;
+ OM_uint32 length;
+ OM_uint32 bytes;
+ OM_uint32 set_length;
+ unsigned char *start;
+ int i;
+
+ if (**buff_in != SEQUENCE_OF)
+ return (NULL);
+
+ start = *buff_in;
+ (*buff_in)++;
+
+ length = gssint_get_der_length(buff_in, buff_length, &bytes);
+
+ major_status = gss_create_empty_oid_set(minor_status,
+ &returned_mechSet);
+ if (major_status != GSS_S_COMPLETE)
+ return (NULL);
+
+ for (set_length = 0, i = 0; set_length < length; i++) {
+ gss_OID_desc *temp = get_mech_oid(minor_status, buff_in,
+ buff_length - (*buff_in - start));
+ if (temp != NULL) {
+ major_status = gss_add_oid_set_member(minor_status,
+ temp, &returned_mechSet);
+ if (major_status == GSS_S_COMPLETE) {
+ set_length += returned_mechSet->elements[i].length +2;
+ generic_gss_release_oid(minor_status, &temp);
+ }
+ }
+ }
+
+ return (returned_mechSet);
+}
+
+/*
+ * Encode mechSet into buf.
+ */
+static int
+put_mech_set(gss_OID_set mechSet, gss_buffer_t buf)
+{
+ unsigned char *ptr;
+ int i, tlen, ilen;
+
+ tlen = ilen = 0;
+ for (i = 0; i < mechSet->count; i++) {
+ /*
+ * 0x06 [DER LEN] [OID]
+ */
+ ilen += 1 +
+ gssint_der_length_size(mechSet->elements[i].length) +
+ mechSet->elements[i].length;
+ }
+ /*
+ * 0x30 [DER LEN]
+ */
+ tlen = 1 + gssint_der_length_size(ilen) + ilen;
+ ptr = malloc(tlen);
+ if (ptr == NULL)
+ return -1;
+
+ buf->value = ptr;
+ buf->length = tlen;
+#define REMAIN (buf->length - ((unsigned char *)buf->value - ptr))
+
+ *ptr++ = SEQUENCE_OF;
+ if (gssint_put_der_length(ilen, &ptr, REMAIN) < 0)
+ return -1;
+ for (i = 0; i < mechSet->count; i++) {
+ if (put_mech_oid(&ptr, &mechSet->elements[i], REMAIN) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+#undef REMAIN
+}
+
+/*
+ * Verify that buff_in is pointing to a BIT_STRING with the correct
+ * length and padding for the req_flags. If it is, decode req_flags
+ * and return them, otherwise, return NULL.
+ */
+static OM_uint32
+get_req_flags(unsigned char **buff_in, OM_uint32 bodysize,
+ OM_uint32 *req_flags)
+{
+ int len;
+ unsigned char *start = *buff_in;
+
+ if (**buff_in != (CONTEXT | 0x01))
+ return (0);
+
+ if (g_get_tag_and_length(buff_in, (CONTEXT | 0x01),
+ bodysize, &len) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (*(*buff_in)++ != BIT_STRING)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (*(*buff_in)++ != BIT_STRING_LENGTH)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (*(*buff_in)++ != BIT_STRING_PADDING)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ *req_flags = (OM_uint32) (*(*buff_in)++ >> 1);
+ return (0);
+}
+
+/*
+ * der encode the passed req_flags into buf_out, advancing
+ * the buffer pointer.
+ */
+
+static int
+put_req_flags(unsigned char **buf_out, OM_uint32 req_flags, int buflen)
+{
+ int ret = 0;
+ if (buflen < 6)
+ return (-1);
+
+ *(*buf_out)++ = CONTEXT | 0x01;
+ if ((ret = gssint_put_der_length(4, buf_out, buflen-1)) != 0)
+ return (ret);
+
+ *(*buf_out)++ = BIT_STRING;
+ *(*buf_out)++ = BIT_STRING_LENGTH;
+ *(*buf_out)++ = BIT_STRING_PADDING;
+ *(*buf_out)++ = (unsigned char) (req_flags << 1);
+ return (ret);
+}
+
+static OM_uint32
+get_negTokenInit(OM_uint32 *minor_status,
+ gss_buffer_t buf,
+ gss_buffer_t der_mechSet,
+ gss_OID_set *mechSet,
+ OM_uint32 *req_flags,
+ gss_buffer_t *mechtok,
+ gss_buffer_t *mechListMIC)
+{
+ OM_uint32 err;
+ unsigned char *ptr, *bufstart;
+ int len;
+ gss_buffer_desc tmpbuf;
+
+ *minor_status = 0;
+ der_mechSet->length = 0;
+ der_mechSet->value = NULL;
+ *mechSet = GSS_C_NO_OID_SET;
+ *req_flags = 0;
+ *mechtok = *mechListMIC = GSS_C_NO_BUFFER;
+
+ ptr = bufstart = buf->value;
+ if ((buf->length - (ptr - bufstart)) > INT_MAX)
+ return GSS_S_FAILURE;
+#define REMAIN ((int)(buf->length - (ptr - bufstart)))
+
+ err = g_verify_token_header(gss_mech_spnego,
+ &len, &ptr, 0, REMAIN);
+ if (err) {
+ *minor_status = err;
+ return GSS_S_FAILURE;
+ }
+ *minor_status = g_verify_neg_token_init(&ptr, REMAIN);
+ if (*minor_status)
+ return GSS_S_FAILURE;
+
+ /* alias into input_token */
+ tmpbuf.value = ptr;
+ tmpbuf.length = REMAIN;
+ *mechSet = get_mech_set(minor_status, &ptr, REMAIN);
+ if (*mechSet == NULL)
+ return GSS_S_FAILURE;
+
+ tmpbuf.length = ptr - (unsigned char *)tmpbuf.value;
+ der_mechSet->value = malloc(tmpbuf.length);
+ if (der_mechSet->value == NULL)
+ return GSS_S_FAILURE;
+ memcpy(der_mechSet->value, tmpbuf.value, tmpbuf.length);
+ der_mechSet->length = tmpbuf.length;
+
+ err = get_req_flags(&ptr, REMAIN, req_flags);
+ if (err != GSS_S_COMPLETE) {
+ return err;
+ }
+ if (g_get_tag_and_length(&ptr, (CONTEXT | 0x02),
+ REMAIN, &len) >= 0) {
+ *mechtok = get_input_token(&ptr, len);
+ if (*mechtok == GSS_C_NO_BUFFER) {
+ return GSS_S_FAILURE;
+ }
+ }
+ if (g_get_tag_and_length(&ptr, (CONTEXT | 0x03),
+ REMAIN, &len) >= 0) {
+ *mechListMIC = get_input_token(&ptr, len);
+ if (*mechListMIC == GSS_C_NO_BUFFER) {
+ return GSS_S_FAILURE;
+ }
+ }
+ return GSS_S_COMPLETE;
+#undef REMAIN
+}
+
+static OM_uint32
+get_negTokenResp(OM_uint32 *minor_status,
+ unsigned char *buf, unsigned int buflen,
+ OM_uint32 *negState,
+ gss_OID *supportedMech,
+ gss_buffer_t *responseToken,
+ gss_buffer_t *mechListMIC)
+{
+ unsigned char *ptr, *bufstart;
+ int len, bytes;
+ unsigned int tag;
+
+ *negState = ACCEPT_DEFECTIVE_TOKEN;
+ *supportedMech = GSS_C_NO_OID;
+ *responseToken = *mechListMIC = GSS_C_NO_BUFFER;
+ ptr = bufstart = buf;
+#define REMAIN (buflen - (ptr - bufstart))
+
+ if (g_get_tag_and_length(&ptr, (CONTEXT | 0x01), REMAIN, &len) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+ if (*ptr++ == SEQUENCE) {
+ len = gssint_get_der_length(&ptr, REMAIN, &bytes);
+ if (len < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ if (REMAIN < 1)
+ tag = 0;
+ else
+ tag = *ptr++;
+
+ if (tag == CONTEXT) {
+ len = gssint_get_der_length(&ptr, REMAIN, &bytes);
+ if (len < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (g_get_tag_and_length(&ptr, ENUMERATED,
+ REMAIN, &len) < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (len != ENUMERATION_LENGTH)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (REMAIN < 1)
+ return GSS_S_DEFECTIVE_TOKEN;
+ *negState = *ptr++;
+
+ if (REMAIN < 1)
+ tag = 0;
+ else
+ tag = *ptr++;
+ }
+ if (tag == (CONTEXT | 0x01)) {
+ len = gssint_get_der_length(&ptr, REMAIN, &bytes);
+ if (len < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ *supportedMech = get_mech_oid(minor_status, &ptr, REMAIN);
+ if (*supportedMech == GSS_C_NO_OID)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (REMAIN < 1)
+ tag = 0;
+ else
+ tag = *ptr++;
+ }
+ if (tag == (CONTEXT | 0x02)) {
+ len = gssint_get_der_length(&ptr, REMAIN, &bytes);
+ if (len < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ *responseToken = get_input_token(&ptr, REMAIN);
+ if (*responseToken == GSS_C_NO_BUFFER)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (REMAIN < 1)
+ tag = 0;
+ else
+ tag = *ptr++;
+ }
+ if (tag == (CONTEXT | 0x03)) {
+ len = gssint_get_der_length(&ptr, REMAIN, &bytes);
+ if (len < 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ *mechListMIC = get_input_token(&ptr, REMAIN);
+ if (*mechListMIC == GSS_C_NO_BUFFER)
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+ return GSS_S_COMPLETE;
+#undef REMAIN
+}
+
+/*
+ * der encode the passed negResults as an ENUMERATED type and
+ * place it in buf_out, advancing the buffer.
+ */
+
+static int
+put_negResult(unsigned char **buf_out, OM_uint32 negResult, int buflen)
+{
+ if (buflen < 3)
+ return (-1);
+ *(*buf_out)++ = ENUMERATED;
+ *(*buf_out)++ = ENUMERATION_LENGTH;
+ *(*buf_out)++ = (unsigned char) negResult;
+ return (0);
+}
+
+/*
+ * This routine compares the recieved mechset to the mechset that
+ * this server can support. It looks sequentially through the mechset
+ * and the first one that matches what the server can support is
+ * chosen as the negotiated mechanism. If one is found, negResult
+ * is set to ACCEPT_INCOMPLETE if it's the first mech, REQUEST_MIC if
+ * it's not the first mech, otherwise we return NULL and negResult
+ * is set to REJECT.
+ *
+ * NOTE: There is currently no way to specify a preference order of
+ * mechanisms supported by the acceptor.
+ */
+static gss_OID
+negotiate_mech_type(OM_uint32 *minor_status,
+ gss_OID_set supported_mechSet,
+ gss_OID_set mechset,
+ OM_uint32 *negResult)
+{
+ gss_OID returned_mech;
+ OM_uint32 status;
+ int present;
+ int i;
+
+ for (i = 0; i < mechset->count; i++) {
+ gss_test_oid_set_member(minor_status, &mechset->elements[i],
+ supported_mechSet, &present);
+ if (!present)
+ continue;
+
+ if (i == 0)
+ *negResult = ACCEPT_INCOMPLETE;
+ else
+ *negResult = REQUEST_MIC;
+
+ status = generic_gss_copy_oid(minor_status,
+ &mechset->elements[i],
+ &returned_mech);
+ if (status != GSS_S_COMPLETE) {
+ *negResult = REJECT;
+ return (NULL);
+ }
+ return (returned_mech);
+ }
+ *negResult = REJECT;
+ return (NULL);
+}
+
+/*
+ * the next two routines make a token buffer suitable for
+ * spnego_gss_display_status. These currently take the string
+ * in name and place it in the token. Eventually, if
+ * spnego_gss_display_status returns valid error messages,
+ * these routines will be changes to return the error string.
+ */
+static spnego_token_t
+make_spnego_token(char *name)
+{
+ spnego_token_t token;
+
+ token = (spnego_token_t)malloc(strlen(name)+1);
+
+ if (token == NULL)
+ return (NULL);
+ strcpy(token, name);
+ return (token);
+}
+
+static gss_buffer_desc
+make_err_msg(char *name)
+{
+ gss_buffer_desc buffer;
+
+ if (name == NULL) {
+ buffer.length = 0;
+ buffer.value = NULL;
+ } else {
+ buffer.length = strlen(name)+1;
+ buffer.value = make_spnego_token(name);
+ }
+
+ return (buffer);
+}
+
+/*
+ * Create the client side spnego token passed back to gss_init_sec_context
+ * and eventually up to the application program and over to the server.
+ *
+ * Use DER rules, definite length method per RFC 2478
+ */
+static int
+make_spnego_tokenInit_msg(spnego_gss_ctx_id_t spnego_ctx,
+ gss_buffer_t mechListMIC, OM_uint32 req_flags,
+ gss_buffer_t data, send_token_flag sendtoken,
+ gss_buffer_t outbuf)
+{
+ int tlen, dataLen = 0, ret = 0;
+ int negTokenInitSize = 0;
+ int negTokenInitSeqSize = 0;
+ int negTokenInitContSize = 0;
+ int rspTokenSize = 0;
+ int mechListTokenSize = 0;
+ int micTokenSize = 0;
+ int i;
+ unsigned char *t;
+ unsigned char *ptr;
+ unsigned char *MechListPtr = NULL;
+ gss_buffer_desc MICbuff;
+
+ if (outbuf == GSS_C_NO_BUFFER)
+ return (-1);
+
+ outbuf->length = 0;
+ outbuf->value = NULL;
+
+ /* calculate the data length */
+
+ /*
+ * 0xa0 [DER LEN] [mechTypes]
+ */
+ mechListTokenSize = 1 +
+ gssint_der_length_size(spnego_ctx->DER_mechTypes.length) +
+ spnego_ctx->DER_mechTypes.length;
+ dataLen += mechListTokenSize;
+ /*
+ * 4 bytes for ret_flags:
+ * ASN.1 token + ASN.1 Length + Padding + Flags
+ * 0xa1 LENGTH BIT_STRING BIT_STRING_LEN PAD DATA
+ */
+ if (req_flags != 0)
+ dataLen += 6;
+
+ /*
+ * If a token from gss_init_sec_context exists,
+ * add the length of the token + the ASN.1 overhead
+ */
+ if (data != NULL) {
+ /*
+ * Encoded in final output as:
+ * 0xa2 [DER LEN] 0x04 [DER LEN] [DATA]
+ * -----s--------|--------s2----------
+ */
+ rspTokenSize = 1 +
+ gssint_der_length_size(data->length) +
+ data->length;
+ dataLen += 1 + gssint_der_length_size(rspTokenSize) +
+ rspTokenSize;
+ }
+
+ if (mechListMIC) {
+ /*
+ * Encoded in final output as:
+ * 0xa3 [DER LEN] 0x04 [DER LEN] [DATA]
+ * --s-- -----tlen------------
+ */
+ micTokenSize = 1 +
+ gssint_der_length_size(mechListMIC->length) +
+ mechListMIC->length;
+ dataLen += 1 +
+ gssint_der_length_size(micTokenSize) +
+ micTokenSize;
+ }
+
+ /*
+ * Add size of DER encoding
+ * [ SEQUENCE { MechTypeList | ReqFLags | Token | mechListMIC } ]
+ * 0x30 [DER_LEN] [data]
+ *
+ */
+ negTokenInitContSize = dataLen;
+ negTokenInitSeqSize = 1 + gssint_der_length_size(dataLen) + dataLen;
+ dataLen = negTokenInitSeqSize;
+
+ /*
+ * negTokenInitSize indicates the bytes needed to
+ * hold the ASN.1 encoding of the entire NegTokenInit
+ * SEQUENCE.
+ * 0xa0 [DER_LEN] + data
+ *
+ */
+ negTokenInitSize = 1 +
+ gssint_der_length_size(negTokenInitSeqSize) +
+ negTokenInitSeqSize;
+
+ tlen = g_token_size(gss_mech_spnego, negTokenInitSize);
+
+ t = (unsigned char *) malloc(tlen);
+
+ if (t == NULL) {
+ return (-1);
+ }
+
+ ptr = t;
+
+ /* create the message */
+ if ((ret = g_make_token_header(gss_mech_spnego, negTokenInitSize,
+ &ptr, tlen)))
+ goto errout;
+
+ *ptr++ = CONTEXT; /* NegotiationToken identifier */
+ if ((ret = gssint_put_der_length(negTokenInitSeqSize, &ptr, tlen)))
+ goto errout;
+
+ *ptr++ = SEQUENCE;
+ if ((ret = gssint_put_der_length(negTokenInitContSize, &ptr,
+ tlen - (int)(ptr-t))))
+ goto errout;
+
+ *ptr++ = CONTEXT; /* MechTypeList identifier */
+ if ((ret = gssint_put_der_length(spnego_ctx->DER_mechTypes.length,
+ &ptr, tlen - (int)(ptr-t))))
+ goto errout;
+
+ /* We already encoded the MechSetList */
+ (void) memcpy(ptr, spnego_ctx->DER_mechTypes.value,
+ spnego_ctx->DER_mechTypes.length);
+
+ ptr += spnego_ctx->DER_mechTypes.length;
+
+ if (req_flags != 0) {
+ if ((ret = put_req_flags(&ptr, req_flags,
+ tlen - (int)(ptr-t))))
+ goto errout;
+ }
+
+ if (data != NULL) {
+ *ptr++ = CONTEXT | 0x02;
+ if ((ret = gssint_put_der_length(rspTokenSize,
+ &ptr, tlen - (int)(ptr - t))))
+ goto errout;
+
+ if ((ret = put_input_token(&ptr, data,
+ tlen - (int)(ptr - t))))
+ goto errout;
+ }
+
+ if (mechListMIC != GSS_C_NO_BUFFER) {
+ *ptr++ = CONTEXT | 0x03;
+ if ((ret = gssint_put_der_length(micTokenSize,
+ &ptr, tlen - (int)(ptr - t))))
+ goto errout;
+
+ if ((ret = put_input_token(&ptr, mechListMIC,
+ tlen - (int)(ptr - t))))
+ goto errout;
+ }
+
+errout:
+ if (ret != 0) {
+ if (t)
+ free(t);
+ t = NULL;
+ tlen = 0;
+ }
+ outbuf->length = tlen;
+ outbuf->value = (void *) t;
+
+ return (ret);
+}
+
+/*
+ * create the server side spnego token passed back to
+ * gss_accept_sec_context and eventually up to the application program
+ * and over to the client.
+ */
+static int
+make_spnego_tokenTarg_msg(OM_uint32 status, gss_OID mech_wanted,
+ gss_buffer_t data, gss_buffer_t mechListMIC,
+ send_token_flag sendtoken,
+ gss_buffer_t outbuf)
+{
+ int tlen;
+ int ret;
+ int NegTokenTargSize;
+ int negresultTokenSize;
+ int NegTokenSize;
+ int rspTokenSize;
+ int micTokenSize;
+ int dataLen = 0;
+ unsigned char *t;
+ unsigned char *ptr;
+
+ if (outbuf == GSS_C_NO_BUFFER)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ outbuf->length = 0;
+ outbuf->value = NULL;
+
+ /*
+ * ASN.1 encoding of the negResult
+ * ENUMERATED type is 3 bytes
+ * ENUMERATED TAG, Length, Value,
+ * Plus 2 bytes for the CONTEXT id and length.
+ */
+ dataLen = 5;
+
+ /*
+ * calculate data length
+ *
+ * If this is the initial token, include length of
+ * mech_type and the negotiation result fields.
+ */
+ if (sendtoken == INIT_TOKEN_SEND) {
+ int mechlistTokenSize;
+ /*
+ * 1 byte for the CONTEXT ID(0xa0),
+ * 1 byte for the OID ID(0x06)
+ * 1 byte for OID Length field
+ * Plus the rest... (OID Length, OID value)
+ */
+ mechlistTokenSize = 3 + mech_wanted->length +
+ gssint_der_length_size(mech_wanted->length);
+
+ dataLen += mechlistTokenSize;
+ }
+ if (data != NULL && data->length > 0) {
+ /* Length of the inner token */
+ rspTokenSize = 1 + gssint_der_length_size(data->length) +
+ data->length;
+
+ dataLen += rspTokenSize;
+
+ /* Length of the outer token */
+ dataLen += 1 + gssint_der_length_size(rspTokenSize);
+ }
+ if (mechListMIC != NULL) {
+
+ /* Length of the inner token */
+ micTokenSize = 1 + gssint_der_length_size(mechListMIC->length) +
+ mechListMIC->length;
+
+ dataLen += micTokenSize;
+
+ /* Length of the outer token */
+ dataLen += 1 + gssint_der_length_size(micTokenSize);
+ }
+ /*
+ * Add size of DER encoded:
+ * NegTokenTarg [ SEQUENCE ] of
+ * NegResult[0] ENUMERATED {
+ * accept_completed(0),
+ * accept_incomplete(1),
+ * reject(2) }
+ * supportedMech [1] MechType OPTIONAL,
+ * responseToken [2] OCTET STRING OPTIONAL,
+ * mechListMIC [3] OCTET STRING OPTIONAL
+ *
+ * size = data->length + MechListMic + SupportedMech len +
+ * Result Length + ASN.1 overhead
+ */
+ NegTokenTargSize = dataLen;
+ dataLen += 1 + gssint_der_length_size(NegTokenTargSize);
+
+ /*
+ * NegotiationToken [ CHOICE ]{
+ * negTokenInit [0] NegTokenInit,
+ * negTokenTarg [1] NegTokenTarg }
+ */
+ NegTokenSize = dataLen;
+ dataLen += 1 + gssint_der_length_size(NegTokenSize);
+
+ tlen = dataLen;
+ t = (unsigned char *) malloc(tlen);
+
+ if (t == NULL) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+
+ ptr = t;
+
+ /*
+ * Indicate that we are sending CHOICE 1
+ * (NegTokenTarg)
+ */
+ *ptr++ = CONTEXT | 0x01;
+ if (gssint_put_der_length(NegTokenSize, &ptr, dataLen) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ *ptr++ = SEQUENCE;
+ if (gssint_put_der_length(NegTokenTargSize, &ptr,
+ tlen - (int)(ptr-t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+
+ /*
+ * First field of the NegTokenTarg SEQUENCE
+ * is the ENUMERATED NegResult.
+ */
+ *ptr++ = CONTEXT;
+ if (gssint_put_der_length(3, &ptr,
+ tlen - (int)(ptr-t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ if (put_negResult(&ptr, status, tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ if (sendtoken == INIT_TOKEN_SEND) {
+ /*
+ * Next, is the Supported MechType
+ */
+ *ptr++ = CONTEXT | 0x01;
+ if (gssint_put_der_length(mech_wanted->length + 2,
+ &ptr,
+ tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ if (put_mech_oid(&ptr, mech_wanted,
+ tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ }
+ if (data != NULL && data->length > 0) {
+ *ptr++ = CONTEXT | 0x02;
+ if (gssint_put_der_length(rspTokenSize, &ptr,
+ tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ if (put_input_token(&ptr, data,
+ tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ }
+ if (mechListMIC != NULL) {
+ *ptr++ = CONTEXT | 0x03;
+ if (gssint_put_der_length(micTokenSize, &ptr,
+ tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ if (put_input_token(&ptr, mechListMIC,
+ tlen - (int)(ptr - t)) < 0) {
+ ret = GSS_S_DEFECTIVE_TOKEN;
+ goto errout;
+ }
+ }
+ ret = GSS_S_COMPLETE;
+errout:
+ if (ret != GSS_S_COMPLETE) {
+ if (t)
+ free(t);
+ } else {
+ outbuf->length = ptr - t;
+ outbuf->value = (void *) t;
+ }
+
+ return (ret);
+}
+
+/* determine size of token */
+static int
+g_token_size(gss_OID_const mech, unsigned int body_size)
+{
+ int hdrsize;
+
+ /*
+ * Initialize the header size to the
+ * MECH_OID byte + the bytes needed to indicate the
+ * length of the OID + the OID itself.
+ *
+ * 0x06 [MECHLENFIELD] MECHDATA
+ */
+ hdrsize = 1 + gssint_der_length_size(mech->length) + mech->length;
+
+ /*
+ * Now add the bytes needed for the initial header
+ * token bytes:
+ * 0x60 + [DER_LEN] + HDRSIZE
+ */
+ hdrsize += 1 + gssint_der_length_size(body_size + hdrsize);
+
+ return (hdrsize + body_size);
+}
+
+/*
+ * generate token header.
+ *
+ * Use DER Definite Length method per RFC2478
+ * Use of indefinite length encoding will not be compatible
+ * with Microsoft or others that actually follow the spec.
+ */
+static int
+g_make_token_header(gss_OID_const mech,
+ int body_size,
+ unsigned char **buf,
+ int totallen)
+{
+ int hdrsize, ret = 0;
+ unsigned char *p = *buf;
+
+ hdrsize = 1 + gssint_der_length_size(mech->length) + mech->length;
+
+ *(*buf)++ = HEADER_ID;
+ if ((ret = gssint_put_der_length(hdrsize + body_size, buf, totallen)))
+ return (ret);
+
+ *(*buf)++ = MECH_OID;
+ if ((ret = gssint_put_der_length(mech->length, buf,
+ totallen - (int)(p - *buf))))
+ return (ret);
+ TWRITE_STR(*buf, mech->elements, ((int)mech->length));
+ return (0);
+}
+
+/*
+ * NOTE: This checks that the length returned by
+ * gssint_get_der_length() is not greater than the number of octets
+ * remaining, even though gssint_get_der_length() already checks, in
+ * theory.
+ */
+static int
+g_get_tag_and_length(unsigned char **buf, int tag, int buflen, int *outlen)
+{
+ unsigned char *ptr = *buf;
+ int ret = -1; /* pessimists, assume failure ! */
+ unsigned int encoded_len;
+
+ if (buflen > 1 && *ptr == tag) {
+ ptr++;
+ *outlen = gssint_get_der_length(&ptr, buflen - 1,
+ &encoded_len);
+ if (*outlen < 0) {
+ ret = -1;
+ } else if (*outlen > buflen - (ptr - *buf)) {
+ ret = -1;
+ } else
+ ret = 0;
+ }
+
+ *buf = ptr;
+ return (ret);
+}
+
+static int
+g_verify_neg_token_init(unsigned char **buf_in, int cur_size)
+{
+ unsigned char *buf = *buf_in;
+ unsigned char *endptr = buf + cur_size;
+ int seqsize;
+ int ret = 0;
+ unsigned int bytes;
+
+ /*
+ * Verify this is a NegotiationToken type token
+ * - check for a0(context specific identifier)
+ * - get length and verify that enoughd ata exists
+ */
+ if (g_get_tag_and_length(&buf, CONTEXT, cur_size, &seqsize) < 0)
+ return (G_BAD_TOK_HEADER);
+
+ cur_size = seqsize; /* should indicate bytes remaining */
+
+ /*
+ * Verify the next piece, it should identify this as
+ * a strucure of type NegTokenInit.
+ */
+ if (*buf++ == SEQUENCE) {
+ if ((seqsize = gssint_get_der_length(&buf, cur_size, &bytes)) < 0)
+ return (G_BAD_TOK_HEADER);
+ /*
+ * Make sure we have the entire buffer as described
+ */
+ if (buf + seqsize > endptr)
+ return (G_BAD_TOK_HEADER);
+ } else {
+ return (G_BAD_TOK_HEADER);
+ }
+
+ cur_size = seqsize; /* should indicate bytes remaining */
+
+ /*
+ * Verify that the first blob is a sequence of mechTypes
+ */
+ if (*buf++ == CONTEXT) {
+ if ((seqsize = gssint_get_der_length(&buf, cur_size, &bytes)) < 0)
+ return (G_BAD_TOK_HEADER);
+ /*
+ * Make sure we have the entire buffer as described
+ */
+ if (buf + bytes > endptr)
+ return (G_BAD_TOK_HEADER);
+ } else {
+ return (G_BAD_TOK_HEADER);
+ }
+
+ /*
+ * At this point, *buf should be at the beginning of the
+ * DER encoded list of mech types that are to be negotiated.
+ */
+ *buf_in = buf;
+
+ return (ret);
+
+}
+
+/* verify token header. */
+static int
+g_verify_token_header(gss_OID_const mech,
+ int *body_size,
+ unsigned char **buf_in,
+ int tok_type,
+ int toksize)
+{
+ unsigned char *buf = *buf_in;
+ int seqsize;
+ gss_OID_desc toid;
+ int ret = 0;
+ unsigned int bytes;
+
+ if ((toksize -= 1) < 0)
+ return (G_BAD_TOK_HEADER);
+
+ if (*buf++ != HEADER_ID)
+ return (G_BAD_TOK_HEADER);
+
+ if ((seqsize = gssint_get_der_length(&buf, toksize, &bytes)) < 0)
+ return (G_BAD_TOK_HEADER);
+
+ if ((seqsize + bytes) != toksize)
+ return (G_BAD_TOK_HEADER);
+
+ if ((toksize -= 1) < 0)
+ return (G_BAD_TOK_HEADER);
+
+
+ if (*buf++ != MECH_OID)
+ return (G_BAD_TOK_HEADER);
+
+ if ((toksize -= 1) < 0)
+ return (G_BAD_TOK_HEADER);
+
+ toid.length = *buf++;
+
+ if ((toksize -= toid.length) < 0)
+ return (G_BAD_TOK_HEADER);
+
+ toid.elements = buf;
+ buf += toid.length;
+
+ if (!g_OID_equal(&toid, mech))
+ ret = G_WRONG_MECH;
+
+ /*
+ * G_WRONG_MECH is not returned immediately because it's more important
+ * to return G_BAD_TOK_HEADER if the token header is in fact bad
+ */
+ if ((toksize -= 2) < 0)
+ return (G_BAD_TOK_HEADER);
+
+ if (!ret) {
+ *buf_in = buf;
+ *body_size = toksize;
+ }
+
+ return (ret);
+}
gss_release_cred(&minor_stat, &server_creds_list[i]);
free(server_creds_list);
server_creds_list = NULL;
- server_creds_count = 0;
}
if (server_name_list) {
gss_release_name(&minor_stat, &server_name_list[i]);
free(server_name_list);
server_name_list = NULL;
- server_creds_count = 0;
}
+ server_creds_count = 0;
}
expect {
-i $server_id
- -re "rpc_test server: Authen.*failed: .* referenced credentials have expired" { pass "expired" }
+ -re "rpc_test server: Authen.*failed:.*credential.*expired" { pass "expired" }
timeout { fail "expired: timeout waiting for expired creds error" }
}
expect -nocase -re "$localhostname.*ftp server .version \[0-9.\]*. ready."
expect -re "Using authentication type GSSAPI; ADAT must follow"
expect "GSSAPI accepted as authentication type"
- expect "GSSAPI error major: Miscellaneous failure"
+ expect -re "GSSAPI error major: (Unspecified GSS|Miscellaneous) failure"
expect {
"GSSAPI error minor: Unsupported credentials cache format version number" {}
"GSSAPI error minor: No credentials cache found" {}