From: Tom Yu Date: Wed, 14 Jun 2006 22:27:54 +0000 (+0000) Subject: Merge from branches/mechglue. Initial integration of Sun-donated X-Git-Tag: krb5-1.5-beta1~32 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=4c2bc7a022bff031e101a88363ff7756871e8721;p=krb5.git Merge from branches/mechglue. Initial integration of Sun-donated mechglue and SPNEGO implementations. Additional changes outside of src/lib/gssapi: * src/configure.in: Add lib/gssapi/mechglue and lib/gssapi/spnego to list of directories to output Makefile in. * src/lib/rpc/unit-test/rpc_test.0/expire.exp (expired): Update regexp for mechglue. * src/tests/dejagnu/krb-standalone/v4gssftp.exp (v4ftp_test): Update "Miscellaneous failure" regexp for mechglue. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@18131 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/README b/README index 300df13d9..243af7d7e 100644 --- a/README +++ b/README @@ -222,9 +222,76 @@ src/lib/crypto/aes has the following copyright: in respect of any properties, including, but not limited to, correctness and fitness for purpose. +--- The implementations of GSSAPI mechglue in GSSAPI-SPNEGO in + src/lib/gssapi, including the following files: + +lib/gssapi/generic/gssapi_err_generic.et +lib/gssapi/mechglue/g_accept_sec_context.c +lib/gssapi/mechglue/g_acquire_cred.c +lib/gssapi/mechglue/g_canon_name.c +lib/gssapi/mechglue/g_compare_name.c +lib/gssapi/mechglue/g_context_time.c +lib/gssapi/mechglue/g_delete_sec_context.c +lib/gssapi/mechglue/g_dsp_name.c +lib/gssapi/mechglue/g_dsp_status.c +lib/gssapi/mechglue/g_dup_name.c +lib/gssapi/mechglue/g_exp_sec_context.c +lib/gssapi/mechglue/g_export_name.c +lib/gssapi/mechglue/g_glue.c +lib/gssapi/mechglue/g_imp_name.c +lib/gssapi/mechglue/g_imp_sec_context.c +lib/gssapi/mechglue/g_init_sec_context.c +lib/gssapi/mechglue/g_initialize.c +lib/gssapi/mechglue/g_inquire_context.c +lib/gssapi/mechglue/g_inquire_cred.c +lib/gssapi/mechglue/g_inquire_names.c +lib/gssapi/mechglue/g_process_context.c +lib/gssapi/mechglue/g_rel_buffer.c +lib/gssapi/mechglue/g_rel_cred.c +lib/gssapi/mechglue/g_rel_name.c +lib/gssapi/mechglue/g_rel_oid_set.c +lib/gssapi/mechglue/g_seal.c +lib/gssapi/mechglue/g_sign.c +lib/gssapi/mechglue/g_store_cred.c +lib/gssapi/mechglue/g_unseal.c +lib/gssapi/mechglue/g_userok.c +lib/gssapi/mechglue/g_utils.c +lib/gssapi/mechglue/g_verify.c +lib/gssapi/mechglue/gssd_pname_to_uid.c +lib/gssapi/mechglue/mglueP.h +lib/gssapi/mechglue/oid_ops.c +lib/gssapi/spnego/gssapiP_spnego.h +lib/gssapi/spnego/spnego_mech.c + +are subject to the following license: + +Copyright (c) 2004 Sun Microsystems, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + Acknowledgements ---------------- +Thanks to Sun Microsystems for donating their implementations of +mechglue and SPNEGO. + Thanks to the members of the Kerberos V5 development team at MIT, both past and present: Danilo Almeida, Jeffrey Altman, Richard Basch, Jay Berkenbilt, Mitch Berger, Andrew Boardman, Joe Calzaretta, John Carr, diff --git a/src/configure.in b/src/configure.in index 68adb76bf..7c6cc95eb 100644 --- a/src/configure.in +++ b/src/configure.in @@ -912,6 +912,7 @@ V5_AC_OUTPUT_MAKEFILE(. lib/krb5/keytab lib/krb5/krb lib/krb5/rcache lib/krb5/os lib/gssapi lib/gssapi/generic lib/gssapi/krb5 + lib/gssapi/mechglue lib/gssapi/spnego lib/rpc lib/rpc/unit-test diff --git a/src/include/krb5/locate.h b/src/include/krb5/locate.h new file mode 100644 index 000000000..552369ca2 --- /dev/null +++ b/src/include/krb5/locate.h @@ -0,0 +1,30 @@ +#ifndef K5_PLUGIN_H_INCLUDED +#define K5_PLUGIN_H_INCLUDED +#include + +enum locate_service_type { + locate_service_kdc = 1, + locate_service_master_kdc, + locate_service_kadmin, + locate_service_krb524, + locate_service_kpasswd +}; + +struct krb5plugin_service_locate_ftable { + int vmajor, vminor; + /* Per-context setup and teardown. Returned void* blob is + private to the plugin. */ + krb5_error_code (*init)(krb5_context, void **); + void (*fini)(void *); + /* Callback function returns non-zero if the plugin function + should quit and return; this may be because of an error, or may + indicate we've already contacted the service, whatever. The + lookup function should only return an error if it detects a + problem, not if the callback function tells it to quit. */ + krb5_error_code (*lookup)(void *, + enum locate_service_type svc, const char *realm, + int socktype, int family, + int (*cbfunc)(void *,int,struct sockaddr *), + void *cbdata); +}; +#endif diff --git a/src/lib/gssapi/LICENSE b/src/lib/gssapi/LICENSE new file mode 100644 index 000000000..612f8ad6e --- /dev/null +++ b/src/lib/gssapi/LICENSE @@ -0,0 +1,91 @@ +[ NOTE: MIT has only incorporated the mechglue and spnego change, and +not the incremental propagation changes. The filenames are different +between the Sun and MIT sources. The actual MIT filenames appear in +the top-level README file. Original text of Sun's LICENSE file +follows. ] + +Subject to the license set forth below, Sun Microsystems, Inc. donates +the attached files to MIT for the purpose of including these +modifications and additions in future versions of the Kerberos system. + +Many of the files attached are subject to licenses issued by other +entities, including OpenVision, MIT, and FundsXpress. See the +individual files, and/or related Readme files, for these licenses. + +In addition Sun requires that the license set forth below be +incorporated into any future version of the Kerberos system which +contains portions of the files attached. The following files must be +listed, in the top level Readme file, as being provided subject to such +license: + +cmd/krb5/iprop/iprop.x +cmd/krb5/iprop/iprop_hdr.h +cmd/krb5/kadmin/server/ipropd_svc.c +cmd/krb5/kproplog/kproplog.c +cmd/krb5/slave/kpropd_rpc.c +lib/gss_mechs/mech_krb5/et/kdb5_err.c +lib/gss_mechs/mech_spnego/mech/gssapiP_spnego.h +lib/gss_mechs/mech_spnego/mech/spnego_mech.c +lib/krb5/kadm5/kadm_host_srv_names.c +lib/krb5/kdb/kdb_convert.c +lib/krb5/kdb/kdb_hdr.h +lib/krb5/kdb/kdb_log.c +lib/krb5/kdb/kdb_log.h +lib/libgss/g_accept_sec_context.c +lib/libgss/g_acquire_cred.c +lib/libgss/g_canon_name.c +lib/libgss/g_compare_name.c +lib/libgss/g_context_time.c +lib/libgss/g_delete_sec_context.c +lib/libgss/g_dsp_name.c +lib/libgss/g_dsp_status.c +lib/libgss/g_dup_name.c +lib/libgss/g_exp_sec_context.c +lib/libgss/g_export_name.c +lib/libgss/g_glue.c +lib/libgss/g_imp_name.c +lib/libgss/g_imp_sec_context.c +lib/libgss/g_init_sec_context.c +lib/libgss/g_initialize.c +lib/libgss/g_inquire_context.c +lib/libgss/g_inquire_cred.c +lib/libgss/g_inquire_names.c +lib/libgss/g_process_context.c +lib/libgss/g_rel_buffer.c +lib/libgss/g_rel_cred.c +lib/libgss/g_rel_name.c +lib/libgss/g_rel_oid_set.c +lib/libgss/g_seal.c +lib/libgss/g_sign.c +lib/libgss/g_store_cred.c +lib/libgss/g_unseal.c +lib/libgss/g_userok.c +lib/libgss/g_utils.c +lib/libgss/g_verify.c +lib/libgss/gssd_pname_to_uid.c +uts/common/gssapi/include/gssapi_err_generic.h +uts/common/gssapi/include/mechglueP.h + +Sun's License is as follows: + +Copyright (c) 2004 Sun Microsystems, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/src/lib/gssapi/Makefile.in b/src/lib/gssapi/Makefile.in index daf0818dd..d9c9e7707 100644 --- a/src/lib/gssapi/Makefile.in +++ b/src/lib/gssapi/Makefile.in @@ -2,7 +2,7 @@ thisconfigdir=../.. myfulldir=lib/gssapi mydir=lib/gssapi BUILDTOP=$(REL)..$(S).. -LOCAL_SUBDIRS= generic krb5 +LOCAL_SUBDIRS= generic mechglue krb5 spnego DEFS= ##DOSLIBNAME=$(OUTPRE)gssapi.lib @@ -14,7 +14,7 @@ DEFS= ##DOS##DLL_EXP_TYPE=GSS -LOCALINCLUDES = -Igeneric -I$(srcdir)/generic -Ikrb5 -I$(srcdir)/krb5 +LOCALINCLUDES = -Igeneric -I$(srcdir)/generic -Ikrb5 -I$(srcdir)/krb5 -I$(srcdir)/mechglue STLIBOBJS=\ gss_libinit.o @@ -29,11 +29,11 @@ LIBMAJOR=2 LIBMINOR=2 LIBINITFUNC=gssint_lib_init LIBFINIFUNC=gssint_lib_fini -STOBJLISTS=OBJS.ST generic/OBJS.ST krb5/OBJS.ST -SUBDIROBJLISTS=generic/OBJS.ST krb5/OBJS.ST +STOBJLISTS=OBJS.ST generic/OBJS.ST mechglue/OBJS.ST krb5/OBJS.ST spnego/OBJS.ST +SUBDIROBJLISTS=generic/OBJS.ST mechglue/OBJS.ST krb5/OBJS.ST SHLIB_EXPDEPS=\ $(KRB5_DEPLIB) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB) $(COM_ERR_DEPLIB) -SHLIB_EXPLIBS=-lkrb5 -lk5crypto -lcom_err $(SUPPORT_LIB) $(LIBS) +SHLIB_EXPLIBS=-lkrb5 -lk5crypto -lcom_err $(SUPPORT_LIB) $(DL_LIB) $(LIBS) SHLIB_DIRS=-L$(TOPLIBD) SHLIB_RDIRS=$(KRB5_LIBDIR) RELDIR=gssapi diff --git a/src/lib/gssapi/generic/Makefile.in b/src/lib/gssapi/generic/Makefile.in index 9dfa68e6f..38b55e1b4 100644 --- a/src/lib/gssapi/generic/Makefile.in +++ b/src/lib/gssapi/generic/Makefile.in @@ -67,11 +67,9 @@ SRCS = \ $(srcdir)/disp_com_err_status.c \ $(srcdir)/disp_major_status.c \ $(srcdir)/gssapi_generic.c \ - $(srcdir)/oid_ops.c \ $(srcdir)/rel_buffer.c \ $(srcdir)/rel_oid_set.c \ $(srcdir)/util_buffer.c \ - $(srcdir)/util_oid.c \ $(srcdir)/util_ordering.c \ $(srcdir)/util_set.c \ $(srcdir)/util_token.c \ @@ -82,11 +80,9 @@ OBJS = \ $(OUTPRE)disp_com_err_status.$(OBJEXT) \ $(OUTPRE)disp_major_status.$(OBJEXT) \ $(OUTPRE)gssapi_generic.$(OBJEXT) \ - $(OUTPRE)oid_ops.$(OBJEXT) \ $(OUTPRE)rel_buffer.$(OBJEXT) \ $(OUTPRE)rel_oid_set.$(OBJEXT) \ $(OUTPRE)util_buffer.$(OBJEXT) \ - $(OUTPRE)util_oid.$(OBJEXT) \ $(OUTPRE)util_ordering.$(OBJEXT) \ $(OUTPRE)util_set.$(OBJEXT) \ $(OUTPRE)util_token.$(OBJEXT) \ @@ -97,11 +93,9 @@ STLIBOBJS = \ disp_com_err_status.o \ disp_major_status.o \ gssapi_generic.o \ - oid_ops.o \ rel_buffer.o \ rel_oid_set.o \ util_buffer.o \ - util_oid.o \ util_ordering.o \ util_set.o \ util_token.o \ diff --git a/src/lib/gssapi/generic/gssapi.hin b/src/lib/gssapi/generic/gssapi.hin index 37b79e807..28b5b1123 100644 --- a/src/lib/gssapi/generic/gssapi.hin +++ b/src/lib/gssapi/generic/gssapi.hin @@ -691,6 +691,13 @@ OM_uint32 KRB5_CALLCONV gss_inquire_names_for_mech gss_OID_set * /* name_types */ ); +/* New for V2 */ +OM_uint32 KRB5_CALLCONV gss_inquire_mechs_for_name( + OM_uint32 *, /* minor_status */ + const gss_name_t, /* input_name */ + gss_OID_set * /* mech_types */ +); + /* * The following routines are obsolete variants of gss_get_mic, gss_wrap, * gss_verify_mic and gss_unwrap. They should be provided by GSSAPI V2 diff --git a/src/lib/gssapi/generic/gssapiP_generic.h b/src/lib/gssapi/generic/gssapiP_generic.h index ca19b1891..2752f1dfa 100644 --- a/src/lib/gssapi/generic/gssapiP_generic.h +++ b/src/lib/gssapi/generic/gssapiP_generic.h @@ -48,9 +48,9 @@ typedef UINT64_TYPE gssint_uint64; /** helper macros **/ -#define g_OID_equal(o1,o2) \ - (((o1)->length == (o2)->length) && \ - (memcmp((o1)->elements,(o2)->elements,(unsigned int) (o1)->length) == 0)) +#define g_OID_equal(o1, o2) \ + (((o1)->length == (o2)->length) && \ + (memcmp((o1)->elements, (o2)->elements, (o1)->length) == 0)) /* this code knows that an int on the wire is 32 bits. The type of num should be at least this big, or the extra shifts may do weird @@ -122,7 +122,6 @@ typedef UINT64_TYPE gssint_uint64; #define g_delete_ctx_id gssint_g_delete_ctx_id #define g_delete_lucidctx_id gssint_g_delete_lucidctx_id #define g_make_string_buffer gssint_g_make_string_buffer -#define g_copy_OID_set gssint_g_copy_OID_set #define g_token_size gssint_g_token_size #define g_make_token_header gssint_g_make_token_header #define g_verify_token_header gssint_g_verify_token_header @@ -168,8 +167,6 @@ int g_delete_lucidctx_id (g_set *vdb, void *lctx); int g_make_string_buffer (const char *str, gss_buffer_t buffer); -int g_copy_OID_set (const gss_OID_set_desc * const in, gss_OID_set *out); - unsigned int g_token_size (const gss_OID_desc * mech, unsigned int body_size); void g_make_token_header (const gss_OID_desc * mech, unsigned int body_size, diff --git a/src/lib/gssapi/generic/gssapi_err_generic.et b/src/lib/gssapi/generic/gssapi_err_generic.et index 99ba45fe3..3e976e3db 100644 --- a/src/lib/gssapi/generic/gssapi_err_generic.et +++ b/src/lib/gssapi/generic/gssapi_err_generic.et @@ -43,4 +43,7 @@ error_code G_BAD_DIRECTION, "Packet was replayed in wrong direction" error_code G_TOK_TRUNC, "Token is missing data" error_code G_REFLECT, "Token was reflected" error_code G_WRONG_TOKID, "Received token ID does not match expected token ID" +error_code G_CRED_USAGE_MISMATCH, "The given credential's usage does not match the requested usage" +error_code G_STORE_ACCEPTOR_CRED_NOSUPP, "Storing of acceptor credentials is not supported by the mechanism" +error_code G_STORE_NON_DEFAULT_CRED_NOSUPP, "Storing of non-default credentials is not supported by the mechanism" end diff --git a/src/lib/gssapi/generic/oid_ops.c b/src/lib/gssapi/generic/oid_ops.c deleted file mode 100644 index 1234f2ee7..000000000 --- a/src/lib/gssapi/generic/oid_ops.c +++ /dev/null @@ -1,389 +0,0 @@ -/* - * lib/gssapi/generic/oid_ops.c - * - * Copyright 1995 by the Massachusetts Institute of Technology. - * All Rights Reserved. - * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. Furthermore if you modify this software you must label - * your software as modified software and not distribute it in such a - * fashion that it might be confused with the original M.I.T. software. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - * - */ - -/* - * oid_ops.c - GSS-API V2 interfaces to manipulate OIDs - */ - -#include "gssapiP_generic.h" - -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#include -#include -#include -#include - -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; icount; 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; ilength; 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; ilength; i++) { - number = (number << 7) | (cp[i] & 0x7f); - if ((cp[i] & 0x80) == 0) { - sprintf(numstr, "%ld ", number); - strcat(bp, numstr); - number = 0; - } - } - strcat(bp, "}"); - oid_str->length = strlen(bp)+1; - oid_str->value = (void *) bp; - *minor_status = 0; - return(GSS_S_COMPLETE); - } - *minor_status = ENOMEM; - return(GSS_S_FAILURE); -} - -OM_uint32 -generic_gss_str_to_oid(minor_status, oid_str, oid) - OM_uint32 *minor_status; - gss_buffer_t oid_str; - gss_OID *oid; -{ - char *cp, *bp, *startp; - int brace; - long numbuf; - long onumbuf; - OM_uint32 nbytes; - int idx; - unsigned char *op; - - brace = 0; - bp = (char *) oid_str->value; - cp = bp; - /* Skip over leading space */ - while ((bp < &cp[oid_str->length]) && isspace((int) *bp)) - bp++; - if (*bp == '{') { - brace = 1; - bp++; - } - while ((bp < &cp[oid_str->length]) && isspace((int) *bp)) - bp++; - startp = bp; - nbytes = 0; - - /* - * The first two numbers are chewed up by the first octet. - */ - if (sscanf(bp, "%ld", &numbuf) != 1) { - *minor_status = EINVAL; - return(GSS_S_FAILURE); - } - while ((bp < &cp[oid_str->length]) && isdigit((int) *bp)) - bp++; - while ((bp < &cp[oid_str->length]) && isspace((int) *bp)) - bp++; - if (sscanf(bp, "%ld", &numbuf) != 1) { - *minor_status = EINVAL; - return(GSS_S_FAILURE); - } - while ((bp < &cp[oid_str->length]) && isdigit((int) *bp)) - bp++; - while ((bp < &cp[oid_str->length]) && isspace((int) *bp)) - bp++; - nbytes++; - while (isdigit((int) *bp)) { - if (sscanf(bp, "%ld", &numbuf) != 1) { - *minor_status = EINVAL; - return(GSS_S_FAILURE); - } - while (numbuf) { - nbytes++; - numbuf >>= 7; - } - while ((bp < &cp[oid_str->length]) && isdigit((int) *bp)) - bp++; - while ((bp < &cp[oid_str->length]) && isspace((int) *bp)) - bp++; - } - if (brace && (*bp != '}')) { - *minor_status = EINVAL; - return(GSS_S_FAILURE); - } - - /* - * Phew! We've come this far, so the syntax is good. - */ - if ((*oid = (gss_OID) malloc(sizeof(gss_OID_desc)))) { - if (((*oid)->elements = (void *) malloc((size_t) nbytes))) { - (*oid)->length = nbytes; - op = (unsigned char *) (*oid)->elements; - bp = startp; - sscanf(bp, "%ld", &numbuf); - while (isdigit((int) *bp)) - bp++; - while (isspace((int) *bp)) - bp++; - onumbuf = 40*numbuf; - sscanf(bp, "%ld", &numbuf); - onumbuf += numbuf; - *op = (unsigned char) onumbuf; - op++; - while (isdigit((int) *bp)) - bp++; - while (isspace((int) *bp)) - bp++; - while (isdigit((int) *bp)) { - sscanf(bp, "%ld", &numbuf); - nbytes = 0; - /* Have to fill in the bytes msb-first */ - onumbuf = numbuf; - while (numbuf) { - nbytes++; - numbuf >>= 7; - } - numbuf = onumbuf; - op += nbytes; - idx = -1; - while (numbuf) { - op[idx] = (unsigned char) numbuf & 0x7f; - if (idx != -1) - op[idx] |= 0x80; - idx--; - numbuf >>= 7; - } - while (isdigit((int) *bp)) - bp++; - while (isspace((int) *bp)) - bp++; - } - *minor_status = 0; - return(GSS_S_COMPLETE); - } - else { - free(*oid); - *oid = GSS_C_NO_OID; - } - } - *minor_status = ENOMEM; - return(GSS_S_FAILURE); -} - diff --git a/src/lib/gssapi/generic/util_oid.c b/src/lib/gssapi/generic/util_oid.c deleted file mode 100644 index 60b1e157e..000000000 --- a/src/lib/gssapi/generic/util_oid.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 1993 by OpenVision Technologies, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appears in all copies and - * that both that copyright notice and this permission notice appear in - * supporting documentation, and that the name of OpenVision not be used - * in advertising or publicity pertaining to distribution of the software - * without specific, written prior permission. OpenVision makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include "gssapiP_generic.h" -#include "string.h" - -/* - * $Id$ - */ - -int -g_copy_OID_set(in, out) - const gss_OID_set_desc * const in; - gss_OID_set *out; -{ - gss_OID_set copy; - gss_OID new_oid; - size_t i; - size_t len; - - *out = NULL; - - if ((copy = - (gss_OID_set_desc *) xmalloc(sizeof(gss_OID_set_desc))) == NULL) - return(0); - - copy->count = in->count; - len = sizeof(gss_OID_desc) * copy->count; - - if ((copy->elements = - (gss_OID_desc *) xmalloc( len )) == NULL) { - xfree(copy); - return(0); - } - - memset( copy->elements, 0, len ); - - for (i=0; icount; 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); -} diff --git a/src/lib/gssapi/gss_libinit.c b/src/lib/gssapi/gss_libinit.c index f16359497..16031e26e 100644 --- a/src/lib/gssapi/gss_libinit.c +++ b/src/lib/gssapi/gss_libinit.c @@ -7,6 +7,8 @@ #include "gss_libinit.h" #include "k5-platform.h" +#include "mglueP.h" + /* * Initialize the GSSAPI library. */ @@ -26,6 +28,9 @@ int gssint_lib_init(void) add_error_table(&et_k5g_error_table); add_error_table(&et_ggss_error_table); #endif + err = gssint_mechglue_init(); + if (err) + return err; err = k5_mutex_finish_init(&gssint_krb5_keytab_lock); if (err) return err; @@ -61,6 +66,7 @@ void gssint_lib_fini(void) k5_mutex_destroy(&kg_vdb.mutex); k5_mutex_destroy(&kg_kdc_flag_mutex); k5_mutex_destroy(&gssint_krb5_keytab_lock); + gssint_mechglue_fini(); } OM_uint32 gssint_initialize_library (void) diff --git a/src/lib/gssapi/krb5/Makefile.in b/src/lib/gssapi/krb5/Makefile.in index 7d9e8826f..7cd9848e7 100644 --- a/src/lib/gssapi/krb5/Makefile.in +++ b/src/lib/gssapi/krb5/Makefile.in @@ -2,7 +2,7 @@ thisconfigdir=../../.. myfulldir=lib/gssapi/krb5 mydir=lib/gssapi/krb5 BUILDTOP=$(REL)..$(S)..$(S).. -LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic +LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic -I../mechglue -I$(srcdir)/../mechglue DEFS= ##DOS##BUILDTOP = ..\..\.. diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c index ecda750f5..f461e8d50 100644 --- a/src/lib/gssapi/krb5/accept_sec_context.c +++ b/src/lib/gssapi/krb5/accept_sec_context.c @@ -347,6 +347,12 @@ krb5_gss_accept_sec_context(minor_status, context_handle, &ptr, KG_TOK_CTX_AP_REQ, input_token->length, 1))) { mech_used = gss_mech_krb5; + } else if ((code == G_WRONG_MECH) + &&!(code = g_verify_token_header((gss_OID) gss_mech_krb5_wrong, + &(ap_req.length), + &ptr, KG_TOK_CTX_AP_REQ, + input_token->length, 1))) { + mech_used = gss_mech_krb5_wrong; } else if ((code == G_WRONG_MECH) && !(code = g_verify_token_header(gss_mech_krb5_old, &(ap_req.length), diff --git a/src/lib/gssapi/krb5/copy_ccache.c b/src/lib/gssapi/krb5/copy_ccache.c index b0cc96fd8..195be0f84 100644 --- a/src/lib/gssapi/krb5/copy_ccache.c +++ b/src/lib/gssapi/krb5/copy_ccache.c @@ -1,7 +1,7 @@ #include "gssapiP_krb5.h" OM_uint32 KRB5_CALLCONV -gss_krb5_copy_ccache(minor_status, cred_handle, out_ccache) +gss_krb5int_copy_ccache(minor_status, cred_handle, out_ccache) OM_uint32 *minor_status; gss_cred_id_t cred_handle; krb5_ccache out_ccache; diff --git a/src/lib/gssapi/krb5/get_tkt_flags.c b/src/lib/gssapi/krb5/get_tkt_flags.c index 74f1532ae..19841a086 100644 --- a/src/lib/gssapi/krb5/get_tkt_flags.c +++ b/src/lib/gssapi/krb5/get_tkt_flags.c @@ -27,7 +27,7 @@ */ OM_uint32 KRB5_CALLCONV -gss_krb5_get_tkt_flags(minor_status, context_handle, ticket_flags) +gss_krb5int_get_tkt_flags(minor_status, context_handle, ticket_flags) OM_uint32 *minor_status; gss_ctx_id_t context_handle; krb5_flags *ticket_flags; diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h index 3539ac7a9..b23bda406 100644 --- a/src/lib/gssapi/krb5/gssapiP_krb5.h +++ b/src/lib/gssapi/krb5/gssapiP_krb5.h @@ -74,6 +74,17 @@ /** constants **/ +#define GSS_MECH_KRB5_OID_LENGTH 9 +#define GSS_MECH_KRB5_OID "\052\206\110\206\367\022\001\002\002" + +#define GSS_MECH_KRB5_OLD_OID_LENGTH 5 +#define GSS_MECH_KRB5_OLD_OID "\053\005\001\005\002" + +/* Incorrect krb5 mech OID emitted by MS. */ +#define GSS_MECH_KRB5_WRONG_OID_LENGTH 9 +#define GSS_MECH_KRB5_WRONG_OID "\052\206\110\202\367\022\001\002\002" + + #define CKSUMTYPE_KG_CB 0x8003 #define KG_TOK_CTX_AP_REQ 0x0100 @@ -575,7 +586,7 @@ OM_uint32 krb5_gss_import_sec_context krb5_error_code krb5_gss_ser_init(krb5_context); -OM_uint32 krb5_gss_release_oid +OM_uint32 krb5_gss_internal_release_oid (OM_uint32 *, /* minor_status */ gss_OID * /* oid */ ); @@ -631,6 +642,33 @@ OM_uint32 gss_krb5int_unseal_token_v3(krb5_context *contextptr, int *conf_state, int *qop_state, int toktype); +/* + * These take unglued krb5-mech-specific contexts. + */ + +OM_uint32 KRB5_CALLCONV gss_krb5int_get_tkt_flags + (OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + krb5_flags *ticket_flags); + +OM_uint32 KRB5_CALLCONV gss_krb5int_copy_ccache + (OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + krb5_ccache out_ccache); + +OM_uint32 KRB5_CALLCONV +gss_krb5int_set_allowable_enctypes(OM_uint32 *minor_status, + gss_cred_id_t cred, + OM_uint32 num_ktypes, + krb5_enctype *ktypes); + +OM_uint32 KRB5_CALLCONV +gss_krb5int_export_lucid_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + OM_uint32 version, + void **kctx); + + extern k5_mutex_t kg_kdc_flag_mutex; krb5_error_code krb5_gss_init_context (krb5_context *ctxp); diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c index 94f11ef03..f1c27e487 100644 --- a/src/lib/gssapi/krb5/gssapi_krb5.c +++ b/src/lib/gssapi/krb5/gssapi_krb5.c @@ -87,9 +87,11 @@ const gss_OID_desc krb5_gss_oid_array[] = { /* this is the official, rfc-specified OID */ - {9, "\052\206\110\206\367\022\001\002\002"}, - /* this is the unofficial, wrong OID */ - {5, "\053\005\001\005\002"}, + {GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID}, + /* this pre-RFC mech OID */ + {GSS_MECH_KRB5_OLD_OID_LENGTH, GSS_MECH_KRB5_OLD_OID}, + /* this is the unofficial, incorrect mech OID emitted by MS */ + {GSS_MECH_KRB5_WRONG_OID_LENGTH, GSS_MECH_KRB5_WRONG_OID}, /* this is the v2 assigned OID */ {9, "\052\206\110\206\367\022\001\002\003"}, /* these two are name type OID's */ @@ -108,14 +110,15 @@ const gss_OID_desc krb5_gss_oid_array[] = { const gss_OID_desc * const gss_mech_krb5 = krb5_gss_oid_array+0; const gss_OID_desc * const gss_mech_krb5_old = krb5_gss_oid_array+1; -const gss_OID_desc * const gss_nt_krb5_name = krb5_gss_oid_array+3; -const gss_OID_desc * const gss_nt_krb5_principal = krb5_gss_oid_array+4; -const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME = krb5_gss_oid_array+3; +const gss_OID_desc * const gss_mech_krb5_wrong = krb5_gss_oid_array+2; +const gss_OID_desc * const gss_nt_krb5_name = krb5_gss_oid_array+4; +const gss_OID_desc * const gss_nt_krb5_principal = krb5_gss_oid_array+5; +const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME = krb5_gss_oid_array+4; static const gss_OID_set_desc oidsets[] = { {1, (gss_OID) krb5_gss_oid_array+0}, {1, (gss_OID) krb5_gss_oid_array+1}, - {2, (gss_OID) krb5_gss_oid_array+0}, + {3, (gss_OID) krb5_gss_oid_array+0}, {1, (gss_OID) krb5_gss_oid_array+2}, {3, (gss_OID) krb5_gss_oid_array+0}, }; diff --git a/src/lib/gssapi/krb5/gssapi_krb5.hin b/src/lib/gssapi/krb5/gssapi_krb5.hin index 20002478e..647d14e39 100644 --- a/src/lib/gssapi/krb5/gssapi_krb5.hin +++ b/src/lib/gssapi/krb5/gssapi_krb5.hin @@ -72,6 +72,7 @@ GSS_DLLIMP extern const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME; GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5; GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5_old; +GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5_wrong; GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5; GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5_old; GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5_both; diff --git a/src/lib/gssapi/krb5/indicate_mechs.c b/src/lib/gssapi/krb5/indicate_mechs.c index 48baf1a0e..9f2a2a1aa 100644 --- a/src/lib/gssapi/krb5/indicate_mechs.c +++ b/src/lib/gssapi/krb5/indicate_mechs.c @@ -25,6 +25,7 @@ */ #include "gssapiP_krb5.h" +#include "mglueP.h" OM_uint32 krb5_gss_indicate_mechs(minor_status, mech_set) @@ -33,7 +34,7 @@ krb5_gss_indicate_mechs(minor_status, mech_set) { *minor_status = 0; - if (! g_copy_OID_set(gss_mech_set_krb5_both, mech_set)) { + if (! gssint_copy_oid_set(minor_status, gss_mech_set_krb5_both, mech_set)) { *mech_set = GSS_C_NO_OID_SET; *minor_status = ENOMEM; return(GSS_S_FAILURE); diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c index 2ce795bb8..6d27fd33c 100644 --- a/src/lib/gssapi/krb5/init_sec_context.c +++ b/src/lib/gssapi/krb5/init_sec_context.c @@ -918,6 +918,9 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) { if (!cred->prerfc_mech) err = 1; + } else if (g_OID_equal(mech_type, gss_mech_krb5_wrong)) { + if (!cred->rfc_mech) + err = 1; } else { err = 1; } diff --git a/src/lib/gssapi/krb5/krb5_gss_glue.c b/src/lib/gssapi/krb5/krb5_gss_glue.c index 583881d8e..758cfbcb0 100644 --- a/src/lib/gssapi/krb5/krb5_gss_glue.c +++ b/src/lib/gssapi/krb5/krb5_gss_glue.c @@ -25,11 +25,402 @@ */ #include "gssapiP_krb5.h" +#include "mglueP.h" -OM_uint32 KRB5_CALLCONV -gss_accept_sec_context(minor_status, context_handle, verifier_cred_handle, +/** mechglue wrappers **/ + +static OM_uint32 k5glue_acquire_cred +(void *, OM_uint32*, /* minor_status */ + gss_name_t, /* desired_name */ + OM_uint32, /* time_req */ + gss_OID_set, /* desired_mechs */ + gss_cred_usage_t, /* cred_usage */ + gss_cred_id_t*, /* output_cred_handle */ + gss_OID_set*, /* actual_mechs */ + OM_uint32* /* time_rec */ + ); + +static OM_uint32 k5glue_release_cred +(void *, OM_uint32*, /* minor_status */ + gss_cred_id_t* /* cred_handle */ + ); + +static OM_uint32 k5glue_init_sec_context +(void *, OM_uint32*, /* minor_status */ + gss_cred_id_t, /* claimant_cred_handle */ + gss_ctx_id_t*, /* context_handle */ + gss_name_t, /* target_name */ + gss_OID, /* mech_type */ + OM_uint32, /* req_flags */ + OM_uint32, /* time_req */ + gss_channel_bindings_t, + /* input_chan_bindings */ + gss_buffer_t, /* input_token */ + gss_OID*, /* actual_mech_type */ + gss_buffer_t, /* output_token */ + OM_uint32*, /* ret_flags */ + OM_uint32* /* time_rec */ + ); + +static OM_uint32 k5glue_accept_sec_context +(void *, OM_uint32*, /* minor_status */ + gss_ctx_id_t*, /* context_handle */ + gss_cred_id_t, /* verifier_cred_handle */ + gss_buffer_t, /* input_token_buffer */ + gss_channel_bindings_t, + /* input_chan_bindings */ + gss_name_t*, /* src_name */ + gss_OID*, /* mech_type */ + gss_buffer_t, /* output_token */ + OM_uint32*, /* ret_flags */ + OM_uint32*, /* time_rec */ + gss_cred_id_t* /* delegated_cred_handle */ + ); + +static OM_uint32 k5glue_process_context_token +(void *, OM_uint32*, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t /* token_buffer */ + ); + +static OM_uint32 k5glue_delete_sec_context +(void *, OM_uint32*, /* minor_status */ + gss_ctx_id_t*, /* context_handle */ + gss_buffer_t /* output_token */ + ); + +static OM_uint32 k5glue_context_time +(void *, OM_uint32*, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + OM_uint32* /* time_rec */ + ); + +static OM_uint32 k5glue_sign +(void *, OM_uint32*, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + int, /* qop_req */ + gss_buffer_t, /* message_buffer */ + gss_buffer_t /* message_token */ + ); + +static OM_uint32 k5glue_verify +(void *, OM_uint32*, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t, /* message_buffer */ + gss_buffer_t, /* token_buffer */ + int* /* qop_state */ + ); + +static OM_uint32 k5glue_seal +(void *, OM_uint32*, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + int, /* conf_req_flag */ + int, /* qop_req */ + gss_buffer_t, /* input_message_buffer */ + int*, /* conf_state */ + gss_buffer_t /* output_message_buffer */ + ); + +static OM_uint32 k5glue_unseal +(void *, OM_uint32*, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t, /* input_message_buffer */ + gss_buffer_t, /* output_message_buffer */ + int*, /* conf_state */ + int* /* qop_state */ + ); + +static OM_uint32 k5glue_display_status +(void *, OM_uint32*, /* minor_status */ + OM_uint32, /* status_value */ + int, /* status_type */ + gss_OID, /* mech_type */ + OM_uint32*, /* message_context */ + gss_buffer_t /* status_string */ + ); + +static OM_uint32 k5glue_indicate_mechs +(void *, OM_uint32*, /* minor_status */ + gss_OID_set* /* mech_set */ + ); + +static OM_uint32 k5glue_compare_name +(void *, OM_uint32*, /* minor_status */ + gss_name_t, /* name1 */ + gss_name_t, /* name2 */ + int* /* name_equal */ + ); + +static OM_uint32 k5glue_display_name +(void *, OM_uint32*, /* minor_status */ + gss_name_t, /* input_name */ + gss_buffer_t, /* output_name_buffer */ + gss_OID* /* output_name_type */ + ); + +static OM_uint32 k5glue_import_name +(void *, OM_uint32*, /* minor_status */ + gss_buffer_t, /* input_name_buffer */ + gss_OID, /* input_name_type */ + gss_name_t* /* output_name */ + ); + +static OM_uint32 k5glue_release_name +(void *, OM_uint32*, /* minor_status */ + gss_name_t* /* input_name */ + ); + +static OM_uint32 k5glue_inquire_cred +(void *, OM_uint32 *, /* minor_status */ + gss_cred_id_t, /* cred_handle */ + gss_name_t *, /* name */ + OM_uint32 *, /* lifetime */ + gss_cred_usage_t*,/* cred_usage */ + gss_OID_set * /* mechanisms */ + ); + +static OM_uint32 k5glue_inquire_context +(void *, OM_uint32*, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_name_t*, /* initiator_name */ + gss_name_t*, /* acceptor_name */ + OM_uint32*, /* lifetime_rec */ + gss_OID*, /* mech_type */ + OM_uint32*, /* ret_flags */ + int*, /* locally_initiated */ + int* /* open */ + ); + +#if 0 +/* New V2 entry points */ +static OM_uint32 k5glue_get_mic +(void *, OM_uint32 *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_qop_t, /* qop_req */ + gss_buffer_t, /* message_buffer */ + gss_buffer_t /* message_token */ + ); + +static OM_uint32 k5glue_verify_mic +(void *, OM_uint32 *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t, /* message_buffer */ + gss_buffer_t, /* message_token */ + gss_qop_t * /* qop_state */ + ); + +static OM_uint32 k5glue_wrap +(void *, OM_uint32 *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + int, /* conf_req_flag */ + gss_qop_t, /* qop_req */ + gss_buffer_t, /* input_message_buffer */ + int *, /* conf_state */ + gss_buffer_t /* output_message_buffer */ + ); + +static OM_uint32 k5glue_unwrap +(void *, OM_uint32 *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t, /* input_message_buffer */ + gss_buffer_t, /* output_message_buffer */ + int *, /* conf_state */ + gss_qop_t * /* qop_state */ + ); +#endif + +static OM_uint32 k5glue_wrap_size_limit +(void *, OM_uint32 *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + int, /* conf_req_flag */ + gss_qop_t, /* qop_req */ + OM_uint32, /* req_output_size */ + OM_uint32 * /* max_input_size */ + ); + +#if 0 +static OM_uint32 k5glue_import_name_object +(void *, OM_uint32 *, /* minor_status */ + void *, /* input_name */ + gss_OID, /* input_name_type */ + gss_name_t * /* output_name */ + ); + +static OM_uint32 k5glue_export_name_object +(void *, OM_uint32 *, /* minor_status */ + gss_name_t, /* input_name */ + gss_OID, /* desired_name_type */ + void * * /* output_name */ + ); +#endif + +static OM_uint32 k5glue_add_cred +(void *, OM_uint32 *, /* minor_status */ + gss_cred_id_t, /* input_cred_handle */ + gss_name_t, /* desired_name */ + gss_OID, /* desired_mech */ + gss_cred_usage_t, /* cred_usage */ + OM_uint32, /* initiator_time_req */ + OM_uint32, /* acceptor_time_req */ + gss_cred_id_t *, /* output_cred_handle */ + gss_OID_set *, /* actual_mechs */ + OM_uint32 *, /* initiator_time_rec */ + OM_uint32 * /* acceptor_time_rec */ + ); + +static OM_uint32 k5glue_inquire_cred_by_mech +(void *, OM_uint32 *, /* minor_status */ + gss_cred_id_t, /* cred_handle */ + gss_OID, /* mech_type */ + gss_name_t *, /* name */ + OM_uint32 *, /* initiator_lifetime */ + OM_uint32 *, /* acceptor_lifetime */ + gss_cred_usage_t * /* cred_usage */ + ); + +static OM_uint32 k5glue_export_sec_context +(void *, OM_uint32 *, /* minor_status */ + gss_ctx_id_t *, /* context_handle */ + gss_buffer_t /* interprocess_token */ + ); + +static OM_uint32 k5glue_import_sec_context +(void *, OM_uint32 *, /* minor_status */ + gss_buffer_t, /* interprocess_token */ + gss_ctx_id_t * /* context_handle */ + ); + +krb5_error_code k5glue_ser_init(krb5_context); + +static OM_uint32 k5glue_internal_release_oid +(void *, OM_uint32 *, /* minor_status */ + gss_OID * /* oid */ + ); + +static OM_uint32 k5glue_inquire_names_for_mech +(void *, OM_uint32 *, /* minor_status */ + gss_OID, /* mechanism */ + gss_OID_set * /* name_types */ + ); + +#if 0 +static OM_uint32 k5glue_canonicalize_name +(void *, OM_uint32 *, /* minor_status */ + const gss_name_t, /* input_name */ + const gss_OID, /* mech_type */ + gss_name_t * /* output_name */ + ); +#endif + +static OM_uint32 k5glue_export_name +(void *, OM_uint32 *, /* minor_status */ + const gss_name_t, /* input_name */ + gss_buffer_t /* exported_name */ + ); + +#if 0 +static OM_uint32 k5glue_duplicate_name +(void *, OM_uint32 *, /* minor_status */ + const gss_name_t, /* input_name */ + gss_name_t * /* dest_name */ + ); +#endif + +#if 0 +static OM_uint32 k5glue_validate_cred +(void *, OM_uint32 *, /* minor_status */ + gss_cred_id_t /* cred */ + ); +#endif + +/* + * The krb5 mechanism provides two mech OIDs; use this initializer to + * ensure that both dispatch tables contain identical function + * pointers. + */ +#define KRB5_GSS_CONFIG_INIT \ + NULL, \ + k5glue_acquire_cred, \ + k5glue_release_cred, \ + k5glue_init_sec_context, \ + k5glue_accept_sec_context, \ + k5glue_process_context_token, \ + k5glue_delete_sec_context, \ + k5glue_context_time, \ + k5glue_sign, \ + k5glue_verify, \ + k5glue_seal, \ + k5glue_unseal, \ + k5glue_display_status, \ + k5glue_indicate_mechs, \ + k5glue_compare_name, \ + k5glue_display_name, \ + k5glue_import_name, \ + k5glue_release_name, \ + k5glue_inquire_cred, \ + k5glue_add_cred, \ + k5glue_export_sec_context, \ + k5glue_import_sec_context, \ + k5glue_inquire_cred_by_mech, \ + k5glue_inquire_names_for_mech, \ + k5glue_inquire_context, \ + k5glue_internal_release_oid, \ + k5glue_wrap_size_limit, \ + NULL, /* pname_to_uid */ \ + NULL, /* userok */ \ + k5glue_export_name, \ + NULL /* store_cred */ + +static struct gss_config krb5_mechanism = { + 100, "kerberos_v5", + { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID }, + KRB5_GSS_CONFIG_INIT +}; + +static struct gss_config krb5_mechanism_old = { + 200, "kerberos_v5 (pre-RFC OID)", + { GSS_MECH_KRB5_OLD_OID_LENGTH, GSS_MECH_KRB5_OLD_OID }, + KRB5_GSS_CONFIG_INIT +}; + +static struct gss_config krb5_mechanism_wrong = { + 300, "kerberos_v5 (wrong OID)", + { GSS_MECH_KRB5_WRONG_OID_LENGTH, GSS_MECH_KRB5_WRONG_OID }, + KRB5_GSS_CONFIG_INIT +}; + +static gss_mechanism krb5_mech_configs[] = { + &krb5_mechanism, &krb5_mechanism_old, &krb5_mechanism_wrong, NULL +}; + +#ifdef MS_BUG_TEST +static gss_mechanism krb5_mech_configs_hack[] = { + &krb5_mechanism, &krb5_mechanism_old, NULL +} +#endif + +#if 1 +#define gssint_get_mech_configs krb5_gss_get_mech_configs +#endif + +gss_mechanism * +gssint_get_mech_configs(void) +{ +#ifdef MS_BUG_TEST + char *envstr = getenv("MS_FORCE_NO_MSOID"); + + if (envstr != NULL && strcmp(envstr, "1") == 0) { + return krb5_mech_configs_hack; + } +#endif + return krb5_mech_configs; +} + +static OM_uint32 +k5glue_accept_sec_context(ctx, minor_status, context_handle, verifier_cred_handle, input_token, input_chan_bindings, src_name, mech_type, output_token, ret_flags, time_rec, delegated_cred_handle) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t *context_handle; gss_cred_id_t verifier_cred_handle; @@ -55,9 +446,10 @@ gss_accept_sec_context(minor_status, context_handle, verifier_cred_handle, delegated_cred_handle)); } -OM_uint32 KRB5_CALLCONV -gss_acquire_cred(minor_status, desired_name, time_req, desired_mechs, +static OM_uint32 +k5glue_acquire_cred(ctx, minor_status, desired_name, time_req, desired_mechs, cred_usage, output_cred_handle, actual_mechs, time_rec) + void *ctx; OM_uint32 *minor_status; gss_name_t desired_name; OM_uint32 time_req; @@ -78,11 +470,12 @@ gss_acquire_cred(minor_status, desired_name, time_req, desired_mechs, } /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_add_cred(minor_status, input_cred_handle, desired_name, desired_mech, +static OM_uint32 +k5glue_add_cred(ctx, minor_status, input_cred_handle, desired_name, desired_mech, cred_usage, initiator_time_req, acceptor_time_req, output_cred_handle, actual_mechs, initiator_time_rec, acceptor_time_rec) + void *ctx; OM_uint32 *minor_status; gss_cred_id_t input_cred_handle; gss_name_t desired_name; @@ -102,18 +495,22 @@ gss_add_cred(minor_status, input_cred_handle, desired_name, desired_mech, acceptor_time_rec)); } +#if 0 /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_add_oid_set_member(minor_status, member_oid, oid_set) +static OM_uint32 +k5glue_add_oid_set_member(ctx, minor_status, member_oid, oid_set) + void *ctx; OM_uint32 *minor_status; gss_OID member_oid; gss_OID_set *oid_set; { return(generic_gss_add_oid_set_member(minor_status, member_oid, oid_set)); } +#endif -OM_uint32 KRB5_CALLCONV -gss_compare_name(minor_status, name1, name2, name_equal) +static OM_uint32 +k5glue_compare_name(ctx, minor_status, name1, name2, name_equal) + void *ctx; OM_uint32 *minor_status; gss_name_t name1; gss_name_t name2; @@ -123,8 +520,9 @@ gss_compare_name(minor_status, name1, name2, name_equal) name2, name_equal)); } -OM_uint32 KRB5_CALLCONV -gss_context_time(minor_status, context_handle, time_rec) +static OM_uint32 +k5glue_context_time(ctx, minor_status, context_handle, time_rec) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; OM_uint32 *time_rec; @@ -133,17 +531,21 @@ gss_context_time(minor_status, context_handle, time_rec) time_rec)); } +#if 0 /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_create_empty_oid_set(minor_status, oid_set) +static OM_uint32 +k5glue_create_empty_oid_set(ctx, minor_status, oid_set) + void *ctx; OM_uint32 *minor_status; gss_OID_set *oid_set; { return(generic_gss_create_empty_oid_set(minor_status, oid_set)); } +#endif -OM_uint32 KRB5_CALLCONV -gss_delete_sec_context(minor_status, context_handle, output_token) +static OM_uint32 +k5glue_delete_sec_context(ctx, minor_status, context_handle, output_token) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t *context_handle; gss_buffer_t output_token; @@ -152,8 +554,9 @@ gss_delete_sec_context(minor_status, context_handle, output_token) context_handle, output_token)); } -OM_uint32 KRB5_CALLCONV -gss_display_name(minor_status, input_name, output_name_buffer, output_name_type) +static OM_uint32 +k5glue_display_name(ctx, minor_status, input_name, output_name_buffer, output_name_type) + void *ctx; OM_uint32 *minor_status; gss_name_t input_name; gss_buffer_t output_name_buffer; @@ -163,9 +566,10 @@ gss_display_name(minor_status, input_name, output_name_buffer, output_name_type) output_name_buffer, output_name_type)); } -OM_uint32 KRB5_CALLCONV -gss_display_status(minor_status, status_value, status_type, +static OM_uint32 +k5glue_display_status(ctx, minor_status, status_value, status_type, mech_type, message_context, status_string) + void *ctx; OM_uint32 *minor_status; OM_uint32 status_value; int status_type; @@ -179,8 +583,9 @@ gss_display_status(minor_status, status_value, status_type, } /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_export_sec_context(minor_status, context_handle, interprocess_token) +static OM_uint32 +k5glue_export_sec_context(ctx, minor_status, context_handle, interprocess_token) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t *context_handle; gss_buffer_t interprocess_token; @@ -190,10 +595,12 @@ gss_export_sec_context(minor_status, context_handle, interprocess_token) interprocess_token)); } +#if 0 /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_get_mic(minor_status, context_handle, qop_req, +static OM_uint32 +k5glue_get_mic(ctx, minor_status, context_handle, qop_req, message_buffer, message_token) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_qop_t qop_req; @@ -203,27 +610,32 @@ gss_get_mic(minor_status, context_handle, qop_req, return(krb5_gss_get_mic(minor_status, context_handle, qop_req, message_buffer, message_token)); } +#endif -OM_uint32 KRB5_CALLCONV -gss_import_name(minor_status, input_name_buffer, input_name_type, output_name) +static OM_uint32 +k5glue_import_name(ctx, minor_status, input_name_buffer, input_name_type, output_name) + void *ctx; OM_uint32 *minor_status; gss_buffer_t input_name_buffer; gss_OID input_name_type; gss_name_t *output_name; { +#if 0 OM_uint32 err; err = gssint_initialize_library(); if (err) { *minor_status = err; return GSS_S_FAILURE; } +#endif return(krb5_gss_import_name(minor_status, input_name_buffer, input_name_type, output_name)); } /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_import_sec_context(minor_status, interprocess_token, context_handle) +static OM_uint32 +k5glue_import_sec_context(ctx, minor_status, interprocess_token, context_handle) + void *ctx; OM_uint32 *minor_status; gss_buffer_t interprocess_token; gss_ctx_id_t *context_handle; @@ -233,19 +645,21 @@ gss_import_sec_context(minor_status, interprocess_token, context_handle) context_handle)); } -OM_uint32 KRB5_CALLCONV -gss_indicate_mechs(minor_status, mech_set) +static OM_uint32 +k5glue_indicate_mechs(ctx, minor_status, mech_set) + void *ctx; OM_uint32 *minor_status; gss_OID_set *mech_set; { return(krb5_gss_indicate_mechs(minor_status, mech_set)); } -OM_uint32 KRB5_CALLCONV -gss_init_sec_context(minor_status, claimant_cred_handle, context_handle, +static OM_uint32 +k5glue_init_sec_context(ctx, minor_status, claimant_cred_handle, context_handle, target_name, mech_type, req_flags, time_req, input_chan_bindings, input_token, actual_mech_type, output_token, ret_flags, time_rec) + void *ctx; OM_uint32 *minor_status; gss_cred_id_t claimant_cred_handle; gss_ctx_id_t *context_handle; @@ -268,10 +682,11 @@ gss_init_sec_context(minor_status, claimant_cred_handle, context_handle, time_rec)); } -OM_uint32 KRB5_CALLCONV -gss_inquire_context(minor_status, context_handle, initiator_name, acceptor_name, +static OM_uint32 +k5glue_inquire_context(ctx, minor_status, context_handle, initiator_name, acceptor_name, lifetime_rec, mech_type, ret_flags, locally_initiated, open) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_name_t *initiator_name; @@ -288,9 +703,10 @@ gss_inquire_context(minor_status, context_handle, initiator_name, acceptor_name, open)); } -OM_uint32 KRB5_CALLCONV -gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, +static OM_uint32 +k5glue_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret, cred_usage, mechanisms) + void *ctx; OM_uint32 *minor_status; gss_cred_id_t cred_handle; gss_name_t *name; @@ -303,9 +719,10 @@ gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, } /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name, +static OM_uint32 +k5glue_inquire_cred_by_mech(ctx, minor_status, cred_handle, mech_type, name, initiator_lifetime, acceptor_lifetime, cred_usage) + void *ctx; OM_uint32 *minor_status; gss_cred_id_t cred_handle; gss_OID mech_type; @@ -320,8 +737,9 @@ gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name, } /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_inquire_names_for_mech(minor_status, mechanism, name_types) +static OM_uint32 +k5glue_inquire_names_for_mech(ctx, minor_status, mechanism, name_types) + void *ctx; OM_uint32 *minor_status; gss_OID mechanism; gss_OID_set *name_types; @@ -331,18 +749,22 @@ gss_inquire_names_for_mech(minor_status, mechanism, name_types) name_types)); } +#if 0 /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_oid_to_str(minor_status, oid, oid_str) +static OM_uint32 +k5glue_oid_to_str(ctx, minor_status, oid, oid_str) + void *ctx; OM_uint32 *minor_status; gss_OID oid; gss_buffer_t oid_str; { return(generic_gss_oid_to_str(minor_status, oid, oid_str)); } +#endif -OM_uint32 KRB5_CALLCONV -gss_process_context_token(minor_status, context_handle, token_buffer) +static OM_uint32 +k5glue_process_context_token(ctx, minor_status, context_handle, token_buffer) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_buffer_t token_buffer; @@ -351,52 +773,62 @@ gss_process_context_token(minor_status, context_handle, token_buffer) context_handle, token_buffer)); } -OM_uint32 KRB5_CALLCONV -gss_release_cred(minor_status, cred_handle) +static OM_uint32 +k5glue_release_cred(ctx, minor_status, cred_handle) + void *ctx; OM_uint32 *minor_status; gss_cred_id_t *cred_handle; { return(krb5_gss_release_cred(minor_status, cred_handle)); } -OM_uint32 KRB5_CALLCONV -gss_release_name(minor_status, input_name) +static OM_uint32 +k5glue_release_name(ctx, minor_status, input_name) + void *ctx; OM_uint32 *minor_status; gss_name_t *input_name; { return(krb5_gss_release_name(minor_status, input_name)); } -OM_uint32 KRB5_CALLCONV -gss_release_buffer(minor_status, buffer) +#if 0 +static OM_uint32 +k5glue_release_buffer(ctx, minor_status, buffer) + void *ctx; OM_uint32 *minor_status; gss_buffer_t buffer; { return(generic_gss_release_buffer(minor_status, buffer)); } +#endif /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_release_oid(minor_status, oid) +static OM_uint32 +k5glue_internal_release_oid(ctx, minor_status, oid) + void *ctx; OM_uint32 *minor_status; gss_OID *oid; { - return(krb5_gss_release_oid(minor_status, oid)); + return(krb5_gss_internal_release_oid(minor_status, oid)); } -OM_uint32 KRB5_CALLCONV -gss_release_oid_set(minor_status, set) +#if 0 +static OM_uint32 +k5glue_release_oid_set(ctx, minor_status, set) + void *ctx; OM_uint32 * minor_status; gss_OID_set *set; { return(generic_gss_release_oid_set(minor_status, set)); } +#endif /* V1 only */ -OM_uint32 KRB5_CALLCONV -gss_seal(minor_status, context_handle, conf_req_flag, qop_req, +static OM_uint32 +k5glue_seal(ctx, minor_status, context_handle, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; int conf_req_flag; @@ -410,10 +842,11 @@ gss_seal(minor_status, context_handle, conf_req_flag, qop_req, conf_state, output_message_buffer)); } -OM_uint32 KRB5_CALLCONV -gss_sign(minor_status, context_handle, +static OM_uint32 +k5glue_sign(ctx, minor_status, context_handle, qop_req, message_buffer, message_token) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; int qop_req; @@ -424,10 +857,12 @@ gss_sign(minor_status, context_handle, qop_req, message_buffer, message_token)); } +#if 0 /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_verify_mic(minor_status, context_handle, +static OM_uint32 +k5glue_verify_mic(ctx, minor_status, context_handle, message_buffer, token_buffer, qop_state) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_buffer_t message_buffer; @@ -439,9 +874,10 @@ gss_verify_mic(minor_status, context_handle, } /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_wrap(minor_status, context_handle, conf_req_flag, qop_req, +static OM_uint32 +k5glue_wrap(ctx, minor_status, context_handle, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; int conf_req_flag; @@ -456,8 +892,9 @@ gss_wrap(minor_status, context_handle, conf_req_flag, qop_req, } /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_str_to_oid(minor_status, oid_str, oid) +static OM_uint32 +k5glue_str_to_oid(ctx, minor_status, oid_str, oid) + void *ctx; OM_uint32 *minor_status; gss_buffer_t oid_str; gss_OID *oid; @@ -466,8 +903,9 @@ gss_str_to_oid(minor_status, oid_str, oid) } /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_test_oid_set_member(minor_status, member, set, present) +static OM_uint32 +k5glue_test_oid_set_member(ctx, minor_status, member, set, present) + void *ctx; OM_uint32 *minor_status; gss_OID member; gss_OID_set set; @@ -476,11 +914,13 @@ gss_test_oid_set_member(minor_status, member, set, present) return(generic_gss_test_oid_set_member(minor_status, member, set, present)); } +#endif /* V1 only */ -OM_uint32 KRB5_CALLCONV -gss_unseal(minor_status, context_handle, input_message_buffer, +static OM_uint32 +k5glue_unseal(ctx, minor_status, context_handle, input_message_buffer, output_message_buffer, conf_state, qop_state) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_buffer_t input_message_buffer; @@ -493,10 +933,12 @@ gss_unseal(minor_status, context_handle, input_message_buffer, conf_state, qop_state)); } +#if 0 /* V2 */ -OM_uint32 KRB5_CALLCONV -gss_unwrap(minor_status, context_handle, input_message_buffer, +static OM_uint32 +k5glue_unwrap(ctx, minor_status, context_handle, input_message_buffer, output_message_buffer, conf_state, qop_state) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_buffer_t input_message_buffer; @@ -507,11 +949,13 @@ gss_unwrap(minor_status, context_handle, input_message_buffer, return(krb5_gss_unwrap(minor_status, context_handle, input_message_buffer, output_message_buffer, conf_state, qop_state)); } +#endif /* V1 only */ -OM_uint32 KRB5_CALLCONV -gss_verify(minor_status, context_handle, message_buffer, +static OM_uint32 +k5glue_verify(ctx, minor_status, context_handle, message_buffer, token_buffer, qop_state) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_buffer_t message_buffer; @@ -526,9 +970,10 @@ gss_verify(minor_status, context_handle, message_buffer, } /* V2 interface */ -OM_uint32 KRB5_CALLCONV -gss_wrap_size_limit(minor_status, context_handle, conf_req_flag, +static OM_uint32 +k5glue_wrap_size_limit(ctx, minor_status, context_handle, conf_req_flag, qop_req, req_output_size, max_input_size) + void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; int conf_req_flag; @@ -541,9 +986,11 @@ gss_wrap_size_limit(minor_status, context_handle, conf_req_flag, req_output_size, max_input_size)); } +#if 0 /* V2 interface */ -OM_uint32 KRB5_CALLCONV -gss_canonicalize_name(minor_status, input_name, mech_type, output_name) +static OM_uint32 +k5glue_canonicalize_name(ctx, minor_status, input_name, mech_type, output_name) + void *ctx; OM_uint32 *minor_status; const gss_name_t input_name; const gss_OID mech_type; @@ -552,11 +999,12 @@ gss_canonicalize_name(minor_status, input_name, mech_type, output_name) return krb5_gss_canonicalize_name(minor_status, input_name, mech_type, output_name); } - +#endif /* V2 interface */ -OM_uint32 KRB5_CALLCONV -gss_export_name(minor_status, input_name, exported_name) +static OM_uint32 +k5glue_export_name(ctx, minor_status, input_name, exported_name) + void *ctx; OM_uint32 *minor_status; const gss_name_t input_name; gss_buffer_t exported_name; @@ -564,15 +1012,96 @@ gss_export_name(minor_status, input_name, exported_name) return krb5_gss_export_name(minor_status, input_name, exported_name); } +#if 0 /* V2 interface */ -OM_uint32 KRB5_CALLCONV -gss_duplicate_name(minor_status, input_name, dest_name) +static OM_uint32 +k5glue_duplicate_name(ctx, minor_status, input_name, dest_name) + void *ctx; OM_uint32 *minor_status; const gss_name_t input_name; gss_name_t *dest_name; { return krb5_gss_duplicate_name(minor_status, input_name, dest_name); } +#endif + +OM_uint32 KRB5_CALLCONV +gss_krb5_get_tkt_flags( + OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + krb5_flags *ticket_flags) +{ + gss_union_ctx_id_t uctx; + + uctx = (gss_union_ctx_id_t)context_handle; + if (!g_OID_equal(uctx->mech_type, &krb5_mechanism.mech_type) && + !g_OID_equal(uctx->mech_type, &krb5_mechanism_old.mech_type)) + return GSS_S_BAD_MECH; + return gss_krb5int_get_tkt_flags(minor_status, uctx->internal_ctx_id, + ticket_flags); +} + +OM_uint32 KRB5_CALLCONV +gss_krb5_copy_ccache( + OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + krb5_ccache out_ccache) +{ + gss_union_cred_t ucred; + gss_cred_id_t mcred; + + ucred = (gss_union_cred_t)cred_handle; + + mcred = gssint_get_mechanism_cred(ucred, &krb5_mechanism.mech_type); + if (mcred != GSS_C_NO_CREDENTIAL) + return gss_krb5int_copy_ccache(minor_status, mcred, out_ccache); + + mcred = gssint_get_mechanism_cred(ucred, &krb5_mechanism_old.mech_type); + if (mcred != GSS_C_NO_CREDENTIAL) + return gss_krb5int_copy_ccache(minor_status, mcred, out_ccache); + + return GSS_S_DEFECTIVE_CREDENTIAL; +} + +/* XXX need to delete mechglue ctx too */ +OM_uint32 KRB5_CALLCONV +gss_krb5_export_lucid_sec_context( + OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + OM_uint32 version, + void **kctx) +{ + gss_union_ctx_id_t uctx; + + uctx = (gss_union_ctx_id_t)*context_handle; + if (!g_OID_equal(uctx->mech_type, &krb5_mechanism.mech_type) && + !g_OID_equal(uctx->mech_type, &krb5_mechanism_old.mech_type)) + return GSS_S_BAD_MECH; + return gss_krb5int_export_lucid_sec_context(minor_status, + &uctx->internal_ctx_id, + version, kctx); +} +OM_uint32 KRB5_CALLCONV +gss_krb5_set_allowable_enctypes( + OM_uint32 *minor_status, + gss_cred_id_t cred, + OM_uint32 num_ktypes, + krb5_enctype *ktypes) +{ + gss_union_cred_t ucred; + gss_cred_id_t mcred; + + ucred = (gss_union_cred_t)cred; + mcred = gssint_get_mechanism_cred(ucred, &krb5_mechanism.mech_type); + if (mcred != GSS_C_NO_CREDENTIAL) + return gss_krb5int_set_allowable_enctypes(minor_status, mcred, + num_ktypes, ktypes); + mcred = gssint_get_mechanism_cred(ucred, &krb5_mechanism_old.mech_type); + if (mcred != GSS_C_NO_CREDENTIAL) + return gss_krb5int_set_allowable_enctypes(minor_status, mcred, + num_ktypes, ktypes); + return GSS_S_DEFECTIVE_CREDENTIAL; +} diff --git a/src/lib/gssapi/krb5/lucid_context.c b/src/lib/gssapi/krb5/lucid_context.c index ac81fff60..a1679a93d 100644 --- a/src/lib/gssapi/krb5/lucid_context.c +++ b/src/lib/gssapi/krb5/lucid_context.c @@ -60,7 +60,7 @@ make_external_lucid_ctx_v1( */ OM_uint32 KRB5_CALLCONV -gss_krb5_export_lucid_sec_context( +gss_krb5int_export_lucid_sec_context( OM_uint32 *minor_status, gss_ctx_id_t *context_handle, OM_uint32 version, diff --git a/src/lib/gssapi/krb5/rel_oid.c b/src/lib/gssapi/krb5/rel_oid.c index 01921c02f..dcb1fe97a 100644 --- a/src/lib/gssapi/krb5/rel_oid.c +++ b/src/lib/gssapi/krb5/rel_oid.c @@ -30,10 +30,11 @@ */ #include "gssapiP_krb5.h" -static OM_uint32 krb5_gss_internal_release_oid (OM_uint32 *, /* minor_status */ - gss_OID * /* oid */ +OM_uint32 krb5_gss_internal_release_oid (OM_uint32 *, /* minor_status */ + gss_OID * /* oid */ ); +#if 0 OM_uint32 krb5_gss_release_oid(minor_status, oid) OM_uint32 *minor_status; @@ -58,8 +59,9 @@ krb5_gss_release_oid(minor_status, oid) return(GSS_S_COMPLETE); } } +#endif -static OM_uint32 +OM_uint32 krb5_gss_internal_release_oid(minor_status, oid) OM_uint32 *minor_status; gss_OID *oid; @@ -71,6 +73,7 @@ krb5_gss_internal_release_oid(minor_status, oid) if ((*oid != gss_mech_krb5) && (*oid != gss_mech_krb5_old) && + (*oid != gss_mech_krb5_wrong) && (*oid != gss_nt_krb5_name) && (*oid != gss_nt_krb5_principal)) { /* We don't know about this OID */ diff --git a/src/lib/gssapi/krb5/set_allowable_enctypes.c b/src/lib/gssapi/krb5/set_allowable_enctypes.c index 2bc2090fa..f573d7dfc 100644 --- a/src/lib/gssapi/krb5/set_allowable_enctypes.c +++ b/src/lib/gssapi/krb5/set_allowable_enctypes.c @@ -59,10 +59,10 @@ #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; diff --git a/src/lib/gssapi/mechglue/Makefile.in b/src/lib/gssapi/mechglue/Makefile.in index afb6ef35f..d757de428 100644 --- a/src/lib/gssapi/mechglue/Makefile.in +++ b/src/lib/gssapi/mechglue/Makefile.in @@ -1,8 +1,8 @@ -thisconfigdir=.. +thisconfigdir=../../.. myfulldir=lib/gssapi/mechglue -mydir=. +mydir=mechglue BUILDTOP=$(REL)..$(S)..$(S).. -LOCALINCLUDES = -I. -I$(srcdir) +LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic DEFS= ##DOSBUILDTOP = ..\..\.. @@ -10,111 +10,86 @@ DEFS= ##DOS##DLL_EXP_TYPE=GSS -LIBDONE=DONE -LIB_SUBDIRS=. -DEPLIBS= -SHLIB_LDFLAGS= $(LDFLAGS) @SHLIB_RPATH_DIRS@ \ - $(LD_UNRESOLVED_PREFIX)krb5_gss_initialize - - -SHLIB_LIBDIRS= @SHLIB_LIBDIRS@ - -SRCS = $(srcdir)/g_acquire_cred.c \ - $(srcdir)/g_rel_cred.c \ - $(srcdir)/g_init_sec_context.c \ - $(srcdir)/g_accept_sec_context.c \ - $(srcdir)/g_process_context.c \ - $(srcdir)/g_delete_sec_context.c \ - $(srcdir)/g_imp_sec_context.c \ - $(srcdir)/g_exp_sec_context.c \ - $(srcdir)/g_context_time.c \ - $(srcdir)/g_sign.c \ - $(srcdir)/g_verify.c \ - $(srcdir)/g_seal.c \ - $(srcdir)/g_unseal.c \ - $(srcdir)/g_dsp_status.c \ - $(srcdir)/g_indicate_mechs.c \ - $(srcdir)/g_compare_name.c \ - $(srcdir)/g_dsp_name.c \ - $(srcdir)/g_imp_name.c \ - $(srcdir)/g_rel_name.c \ - $(srcdir)/g_rel_buffer.c \ - $(srcdir)/g_rel_oid_set.c \ - $(srcdir)/g_oid_ops.c \ - $(srcdir)/g_inq_cred.c \ - $(srcdir)/g_inq_context.c \ - $(srcdir)/g_inq_names.c \ - $(srcdir)/g_initialize.c \ - $(srcdir)/g_glue.c \ - $(srcdir)/gssd_pname_to_uid.c \ - $(srcdir)/gen_oids.c \ - $(srcdir)/oid_ops.c \ - $(srcdir)/g_mechname.c - -OBJS = $(OUTPRE)g_acquire_cred.$(OBJEXT) \ - $(OUTPRE)g_rel_cred.$(OBJEXT) \ - $(OUTPRE)g_init_sec_context.$(OBJEXT) \ - $(OUTPRE)g_accept_sec_context.$(OBJEXT) \ - $(OUTPRE)g_process_context.$(OBJEXT) \ - $(OUTPRE)g_delete_sec_context.$(OBJEXT) \ - $(OUTPRE)g_imp_sec_context.$(OBJEXT) \ - $(OUTPRE)g_exp_sec_context.$(OBJEXT) \ - $(OUTPRE)g_context_time.$(OBJEXT) \ - $(OUTPRE)g_sign.$(OBJEXT) \ - $(OUTPRE)g_verify.$(OBJEXT) \ - $(OUTPRE)g_seal.$(OBJEXT) \ - $(OUTPRE)g_unseal.$(OBJEXT) \ - $(OUTPRE)g_dsp_status.$(OBJEXT) \ - $(OUTPRE)g_indicate_mechs.$(OBJEXT) \ - $(OUTPRE)g_compare_name.$(OBJEXT) \ - $(OUTPRE)g_dsp_name.$(OBJEXT) \ - $(OUTPRE)g_imp_name.$(OBJEXT) \ - $(OUTPRE)g_rel_name.$(OBJEXT) \ - $(OUTPRE)g_rel_buffer.$(OBJEXT) \ - $(OUTPRE)g_rel_oid_set.$(OBJEXT) \ - $(OUTPRE)g_oid_ops.$(OBJEXT) \ - $(OUTPRE)g_inq_cred.$(OBJEXT) \ - $(OUTPRE)g_inq_context.$(OBJEXT) \ - $(OUTPRE)g_inq_names.$(OBJEXT) \ - $(OUTPRE)g_initialize.$(OBJEXT) \ - $(OUTPRE)g_glue.$(OBJEXT) \ - $(OUTPRE)gssd_pname_to_uid.$(OBJEXT) \ - $(OUTPRE)gen_oids.$(OBJEXT) \ - $(OUTPRE)oid_ops.$(OBJEXT) \ - $(OUTPRE)g_mechname.$(OBJEXT) +SRCS = \ + $(srcdir)/g_accept_sec_context.c \ + $(srcdir)/g_acquire_cred.c \ + $(srcdir)/g_canon_name.c \ + $(srcdir)/g_compare_name.c \ + $(srcdir)/g_context_time.c \ + $(srcdir)/g_delete_sec_context.c \ + $(srcdir)/g_dsp_name.c \ + $(srcdir)/g_dsp_status.c \ + $(srcdir)/g_dup_name.c \ + $(srcdir)/g_exp_sec_context.c \ + $(srcdir)/g_export_name.c \ + $(srcdir)/g_glue.c \ + $(srcdir)/g_imp_name.c \ + $(srcdir)/g_imp_sec_context.c \ + $(srcdir)/g_init_sec_context.c \ + $(srcdir)/g_initialize.c \ + $(srcdir)/g_inq_context.c \ + $(srcdir)/g_inq_cred.c \ + $(srcdir)/g_inq_names.c \ + $(srcdir)/g_mechname.c \ + $(srcdir)/g_oid_ops.c \ + $(srcdir)/g_process_context.c \ + $(srcdir)/g_rel_buffer.c \ + $(srcdir)/g_rel_cred.c \ + $(srcdir)/g_rel_name.c \ + $(srcdir)/g_rel_oid_set.c \ + $(srcdir)/g_seal.c \ + $(srcdir)/g_sign.c \ + $(srcdir)/g_store_cred.c \ + $(srcdir)/g_unseal.c \ + $(srcdir)/g_userok.c \ + $(srcdir)/g_utils.c \ + $(srcdir)/g_verify.c \ + $(srcdir)/gssd_pname_to_uid.c \ + $(srcdir)/oid_ops.c + +STLIBOBJS = \ + g_accept_sec_context.o \ + g_acquire_cred.o \ + g_canon_name.o \ + g_compare_name.o \ + g_context_time.o \ + g_delete_sec_context.o \ + g_dsp_name.o \ + g_dsp_status.o \ + g_dup_name.o \ + g_exp_sec_context.o \ + g_export_name.o \ + g_glue.o \ + g_imp_name.o \ + g_imp_sec_context.o \ + g_init_sec_context.o \ + g_initialize.o \ + g_inq_context.o \ + g_inq_cred.o \ + g_inq_names.o \ + g_mechname.o \ + g_oid_ops.o \ + g_process_context.o \ + g_rel_buffer.o \ + g_rel_cred.o \ + g_rel_name.o \ + g_rel_oid_set.o \ + g_seal.o \ + g_sign.o \ + g_store_cred.o \ + g_unseal.o \ + g_userok.o \ + g_utils.o \ + g_verify.o \ + gssd_pname_to_uid.o \ + oid_ops.o EHDRDIR= $(BUILDTOP)$(S)include$(S)gssapi EXPORTED_HEADERS = mechglue.h -all:: all-$(WHAT) - -all-unix:: shared includes $(OBJS) - -all-windows:: includes $(OBJS) - if not exist $(EHDRDIR)\nul mkdir $(EHDRDIR) - copy mechglue.h $(EHDRDIR) - -shared: - mkdir shared +all-unix:: all-libobjs -libgssapi.$(STEXT): $(OBJS) - $(RM) $@ - $(ARADD) $@ $(OBJS) - $(RANLIB) $@ - - -#libgssapi.$(LIBEXT): $(OBJS) -# $(ARCHIVE) $@ $(OBJS) -# $(RANLIB) $@ - -clean:: clean-$(WHAT) - -clean-unix:: - $(RM) shared/* - -clean-windows:: - $(RM) $(EHDRDIR)\gssapi.h $(EHDRDIR)\gssapi_generic.h - if exist $(EHDRDIR)\nul rmdir $(EHDRDIR) +clean-unix:: clean-libobjs # Krb5InstallHeaders($(EXPORTED_HEADERS), $(KRB5_INCDIR)/krb5) install:: @@ -124,3 +99,5 @@ install:: done includes:: + +# @libobj_frag@ diff --git a/src/lib/gssapi/mechglue/g_accept_sec_context.c b/src/lib/gssapi/mechglue/g_accept_sec_context.c index 8cc752fe7..e0be15093 100644 --- a/src/lib/gssapi/mechglue/g_accept_sec_context.c +++ b/src/lib/gssapi/mechglue/g_accept_sec_context.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_accept_sec_context.c 1.19 95/08/07 SMI" */ +/* #pragma ident "@(#)g_accept_sec_context.c 1.19 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -44,7 +44,7 @@ gss_accept_sec_context (minor_status, output_token, ret_flags, time_rec, - delegated_cred_handle) + d_cred) OM_uint32 * minor_status; gss_ctx_id_t * context_handle; @@ -56,23 +56,39 @@ gss_OID * mech_type; gss_buffer_t output_token; OM_uint32 * ret_flags; OM_uint32 * time_rec; -gss_cred_id_t * delegated_cred_handle; +gss_cred_id_t * d_cred; { OM_uint32 status, temp_status, temp_minor_status; gss_union_ctx_id_t union_ctx_id; gss_union_cred_t union_cred; gss_cred_id_t input_cred_handle = GSS_C_NO_CREDENTIAL; - gss_name_t internal_name; + gss_cred_id_t tmp_d_cred = GSS_C_NO_CREDENTIAL; + gss_name_t internal_name = GSS_C_NO_NAME; + gss_name_t tmp_src_name = GSS_C_NO_NAME; gss_OID_desc token_mech_type_desc; gss_OID token_mech_type = &token_mech_type_desc; gss_mechanism mech; - gss_initialize(); + /* check parameters first */ + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; + + if (context_handle == NULL || output_token == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + /* clear optional fields */ + output_token->value = NULL; + output_token->length = 0; + if (src_name) + *src_name = NULL; - if (context_handle == NULL) - return GSS_S_NO_CONTEXT; + if (mech_type) + *mech_type = NULL; + if (d_cred) + *d_cred = NULL; /* * if context_handle is GSS_C_NO_CONTEXT, allocate a union context * descriptor to hold the mech type information as well as the @@ -82,42 +98,33 @@ gss_cred_id_t * delegated_cred_handle; if(*context_handle == GSS_C_NO_CONTEXT) { + if (GSS_EMPTY_BUFFER(input_token_buffer)) + return (GSS_S_CALL_INACCESSIBLE_READ); + /* Get the token mech type */ - status = __gss_get_mech_type(token_mech_type, input_token_buffer); + status = gssint_get_mech_type(token_mech_type, input_token_buffer); if (status) return status; status = GSS_S_FAILURE; union_ctx_id = (gss_union_ctx_id_t) malloc(sizeof(gss_union_ctx_id_desc)); - if (!union_ctx_id) { - *minor_status = ENOMEM; - goto error_out; - } + if (!union_ctx_id) + return (GSS_S_FAILURE); - union_ctx_id->mech_type = (gss_OID) malloc(sizeof(gss_OID_desc)); - if (!union_ctx_id->mech_type) { - *minor_status = ENOMEM; - goto error_out; + union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT; + status = generic_gss_copy_oid(&temp_minor_status, + token_mech_type, + &union_ctx_id->mech_type); + if (status != GSS_S_COMPLETE) { + free(union_ctx_id); + return (status); } - - union_ctx_id->mech_type->elements = (void *) - malloc(token_mech_type->length); - if (!union_ctx_id->mech_type->elements) { - *minor_status = ENOMEM; - goto error_out; - } - - union_ctx_id->mech_type->length = token_mech_type->length; - memcpy(union_ctx_id->mech_type->elements, - token_mech_type->elements, - token_mech_type->length); - /* copy the supplied context handle */ - - union_ctx_id->internal_ctx_id = *context_handle; + /* set the new context handle to caller's data */ + *context_handle = (gss_ctx_id_t)union_ctx_id; } else { - union_ctx_id = *context_handle; + union_ctx_id = (gss_union_ctx_id_t)*context_handle; token_mech_type = union_ctx_id->mech_type; } @@ -127,14 +134,14 @@ gss_cred_id_t * delegated_cred_handle; * use the default credential. */ union_cred = (gss_union_cred_t) verifier_cred_handle; - input_cred_handle = __gss_get_mechanism_cred(union_cred, token_mech_type); + input_cred_handle = gssint_get_mechanism_cred(union_cred, token_mech_type); /* * now select the approprate underlying mechanism routine and * call it. */ - mech = __gss_get_mechanism (token_mech_type); + mech = gssint_get_mechanism (token_mech_type); if (mech && mech->gss_accept_sec_context) { status = mech->gss_accept_sec_context( @@ -149,7 +156,7 @@ gss_cred_id_t * delegated_cred_handle; output_token, ret_flags, time_rec, - delegated_cred_handle); + d_cred ? &tmp_d_cred : NULL); /* If there's more work to do, keep going... */ if (status == GSS_S_CONTINUE_NEEDED) @@ -166,36 +173,140 @@ gss_cred_id_t * delegated_cred_handle; * then call gss_import_name() to create * the union name struct cast to src_name */ - if (src_name != NULL && status == GSS_S_COMPLETE) { - temp_status = __gss_convert_name_to_union_name( - &temp_minor_status, mech, internal_name, src_name); + if (internal_name != NULL) { + temp_status = gssint_convert_name_to_union_name( + &temp_minor_status, mech, + internal_name, &tmp_src_name); if (temp_status != GSS_S_COMPLETE) { - if (minor_status) - *minor_status = temp_minor_status; - gss_release_buffer(&temp_minor_status, output_token); - __gss_release_internal_name(&temp_minor_status, - &mech->mech_type, &internal_name); + *minor_status = temp_minor_status; + if (output_token->length) + (void) gss_release_buffer(&temp_minor_status, + output_token); + if (internal_name != GSS_C_NO_NAME) + mech->gss_release_name( + mech->context, + &temp_minor_status, + &internal_name); return (temp_status); } + if (src_name != NULL) { + *src_name = tmp_src_name; + } + } else if (src_name != NULL) { + *src_name = GSS_C_NO_NAME; + } + + /* Ensure we're returning correct creds format */ + if ((ret_flags && GSS_C_DELEG_FLAG) && + tmp_d_cred != GSS_C_NO_CREDENTIAL) { + gss_union_cred_t d_u_cred = NULL; + + d_u_cred = malloc(sizeof (gss_union_cred_desc)); + if (d_u_cred == NULL) { + status = GSS_S_FAILURE; + goto error_out; + } + (void) memset(d_u_cred, 0, + sizeof (gss_union_cred_desc)); + + d_u_cred->count = 1; + + status = generic_gss_copy_oid(&temp_minor_status, + token_mech_type, + &d_u_cred->mechs_array); + + if (status != GSS_S_COMPLETE) { + free(d_u_cred); + goto error_out; + } + + d_u_cred->cred_array = malloc(sizeof (gss_cred_id_t)); + if (d_u_cred->cred_array != NULL) { + d_u_cred->cred_array[0] = tmp_d_cred; + } else { + free(d_u_cred); + status = GSS_S_FAILURE; + goto error_out; + } + + if (status != GSS_S_COMPLETE) { + free(d_u_cred->cred_array); + free(d_u_cred); + goto error_out; + } + + internal_name = GSS_C_NO_NAME; + + d_u_cred->auxinfo.creation_time = time(0); + d_u_cred->auxinfo.time_rec = 0; + + if (mech->gss_inquire_cred) { + status = mech->gss_inquire_cred(mech->context, + minor_status, + tmp_d_cred, + &internal_name, + &d_u_cred->auxinfo.time_rec, + &d_u_cred->auxinfo.cred_usage, + NULL); + } + + if (internal_name != NULL) { + temp_status = gssint_convert_name_to_union_name( + &temp_minor_status, mech, + internal_name, &tmp_src_name); + if (temp_status != GSS_S_COMPLETE) { + *minor_status = temp_minor_status; + if (output_token->length) + (void) gss_release_buffer( + &temp_minor_status, + output_token); + free(d_u_cred->cred_array); + free(d_u_cred); + return (temp_status); + } + } + + if (tmp_src_name != NULL) { + status = gss_display_name( + &temp_minor_status, + tmp_src_name, + &d_u_cred->auxinfo.name, + &d_u_cred->auxinfo.name_type); + } + + *d_cred = (gss_cred_id_t)d_u_cred; } - if(*context_handle == GSS_C_NO_CONTEXT) - *context_handle = (gss_ctx_id_t *) union_ctx_id; + if (src_name == NULL && tmp_src_name != NULL) + (void) gss_release_name(&temp_minor_status, + &tmp_src_name); + return (status); + } else { - return(status); + status = GSS_S_BAD_MECH; } - return(GSS_S_BAD_MECH); - error_out: if (union_ctx_id) { if (union_ctx_id->mech_type) { if (union_ctx_id->mech_type->elements) free(union_ctx_id->mech_type->elements); free(union_ctx_id->mech_type); + *context_handle = GSS_C_NO_CONTEXT; } free(union_ctx_id); } + + if (output_token->length) + (void) gss_release_buffer(&temp_minor_status, output_token); + + if (src_name) + *src_name = GSS_C_NO_NAME; + + if (tmp_src_name != GSS_C_NO_NAME) + (void) gss_release_buffer(&temp_minor_status, + (gss_buffer_t)tmp_src_name); + return (status); } diff --git a/src/lib/gssapi/mechglue/g_acquire_cred.c b/src/lib/gssapi/mechglue/g_acquire_cred.c index 8ecf55f31..ca3060791 100644 --- a/src/lib/gssapi/mechglue/g_acquire_cred.c +++ b/src/lib/gssapi/mechglue/g_acquire_cred.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_acquire_cred.c 1.19 95/08/07 SMI" */ +/* #pragma ident "@(#)g_acquire_cred.c 1.22 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -35,36 +35,37 @@ #include #include -#define g_OID_equal(o1,o2) \ - (((o1)->length == (o2)->length) && \ - (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0)) - static gss_OID_set -create_actual_mechs(creds) - gss_union_cred_t creds; +create_actual_mechs(mechs_array, count) + const gss_OID mechs_array; + int count; { gss_OID_set actual_mechs; int i; + OM_uint32 minor; actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)); if (!actual_mechs) return NULL; actual_mechs->elements = (gss_OID) - malloc(sizeof(gss_OID_desc) * creds->count); + malloc(sizeof (gss_OID_desc) * count); if (!actual_mechs->elements) { free(actual_mechs); return NULL; } - actual_mechs->count = creds->count; + actual_mechs->count = 0; - for (i=0; i < creds->count; i++) { - actual_mechs->elements[i].length = creds->mechs_array[i].length; + for (i = 0; i < count; i++) { actual_mechs->elements[i].elements = (void *) - malloc(creds->mechs_array[i].length); - memcpy(actual_mechs->elements[i].elements, - creds->mechs_array[i].elements, creds->mechs_array[i].length); + malloc(mechs_array[i].length); + if (actual_mechs->elements[i].elements == NULL) { + (void) gss_release_oid_set(&minor, &actual_mechs); + return (NULL); + } + g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]); + actual_mechs->count++; } return actual_mechs; @@ -91,291 +92,118 @@ gss_OID_set * actual_mechs; OM_uint32 * time_rec; { - OM_uint32 status, temp_minor_status, temp_time_rec = ~0; - unsigned int i, j, creds_acquired = 0; - int k; - gss_union_name_t union_name; - gss_name_t internal_name; - gss_union_cred_t creds; - gss_OID_set_desc default_OID_set; - gss_OID_desc default_OID; - gss_OID specific_mech_type = 0; - gss_mechanism mech; - - /* - * This struct is used to keep track of which mech_types are - * actually available and to store the credentials returned - * from them by each mechanism specific gss_acquire_cred() call. - * The results are used to construct the final union_cred - * structure returned by the glue layer gss_acquire_cred() call - * and the actual_mechs gss_OID_set returned. - */ - - struct creds_returned { - unsigned char available; - gss_cred_id_t cred; - } *creds_returned; + OM_uint32 major = GSS_S_FAILURE; + OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE; + gss_OID_set_desc default_OID_set; + gss_OID_set mechs; + gss_OID_desc default_OID; + gss_mechanism mech; + int i; + gss_union_cred_t creds; + + /* start by checking parameters */ + if (!minor_status) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; - gss_initialize(); + if (!output_cred_handle) + return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED); - /* Set this to NULL for now */ + *output_cred_handle = GSS_C_NO_CREDENTIAL; + /* Set output parameters to NULL for now */ if (actual_mechs) *actual_mechs = GSS_C_NULL_OID_SET; - if (minor_status) - *minor_status = 0; - - /* No need to continue if we don't have a place to store the creds */ - if (output_cred_handle == NULL) - return GSS_S_COMPLETE; - - /* get desired_name cast as a union_name type */ - - union_name = (gss_union_name_t) desired_name; + if (time_rec) + *time_rec = 0; - if (union_name) - specific_mech_type = union_name->mech_type; - /* * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an - * appropriate default. + * appropriate default. We use the first mechanism in the + * mechansim list as the default. This set is created with + * statics thus needs not be freed */ if(desired_mechs == GSS_C_NULL_OID_SET) { - /* - * If union_name->mech_type is NULL then we get the default - * mechanism; otherwise, we get the mechanism for the - * mechanism-specific name. - */ - mech = __gss_get_mechanism(specific_mech_type); + mech = gssint_get_mechanism(NULL); if (mech == NULL) return (GSS_S_BAD_MECH); - - desired_mechs = &default_OID_set; - default_OID_set.count = 1 ; + + mechs = &default_OID_set; + default_OID_set.count = 1; default_OID_set.elements = &default_OID; default_OID.length = mech->mech_type.length; default_OID.elements = mech->mech_type.elements; - } - - /* - * Now allocate the creds returned array. There is one element - * for each member of the desired_mechs argument. - */ - - creds_returned = (struct creds_returned *) - malloc(sizeof(struct creds_returned) * desired_mechs->count); - - /* - * For each requested mechanism in desired_mechs, determine if it - * is supported. If so, mark the corresponding element in - * creds_returned->available as 1 and call the mechanism - * specific gss_acquire_cred(), placing the returned cred in - * creds_returned->cred. If not, mark creds_returned->available as - * 0. - */ - status = GSS_S_BAD_MECH; - for (j=0; j < desired_mechs->count; j++) { - creds_returned[j].available = 0; - - mech = __gss_get_mechanism (&desired_mechs->elements[j]); - if (!mech || !mech->gss_acquire_cred) - continue; - /* - * If this is a mechanism-specific name, then only use the - * mechanism of the name. - */ - if (specific_mech_type && !g_OID_equal(specific_mech_type, - &mech->mech_type)) - continue; - /* - * If this is not a mechanism-specific name, then we need to - * do an import the external name in union_name first. - */ - if (union_name == 0) - internal_name = (gss_name_t) 0; - else if (!union_name->mech_type) { - if (__gss_import_internal_name(&temp_minor_status, - &mech->mech_type, - union_name, &internal_name)) { - continue; + } else + mechs = desired_mechs; + + if (mechs->count == 0) + return (GSS_S_BAD_MECH); + + /* allocate the output credential structure */ + creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc)); + if (creds == NULL) + return (GSS_S_FAILURE); + + /* initialize to 0s */ + (void) memset(creds, 0, sizeof (gss_union_cred_desc)); + + /* for each requested mech attempt to obtain a credential */ + for (i = 0; i < mechs->count; i++) { + major = gss_add_cred(minor_status, (gss_cred_id_t)creds, + desired_name, + &mechs->elements[i], + cred_usage, time_req, time_req, NULL, + NULL, &initTimeOut, &acceptTimeOut); + if (major == GSS_S_COMPLETE) { + /* update the credential's time */ + if (cred_usage == GSS_C_ACCEPT) { + if (outTime > acceptTimeOut) + outTime = acceptTimeOut; + } else if (cred_usage == GSS_C_INITIATE) { + if (outTime > initTimeOut) + outTime = initTimeOut; + } else { + /* + * time_rec is the lesser of the + * init/accept times + */ + if (initTimeOut > acceptTimeOut) + outTime = (outTime > acceptTimeOut) ? + acceptTimeOut : outTime; + else + outTime = (outTime > initTimeOut) ? + initTimeOut : outTime; } - } else - internal_name = union_name->mech_name; - - status = mech->gss_acquire_cred(mech->context, minor_status, - internal_name, time_req, - desired_mechs, cred_usage, - &creds_returned[j].cred, - NULL, &temp_time_rec); - - /* Release the internal name, if allocated above */ - if (union_name && !union_name->mech_type) { - (void) __gss_release_internal_name(&temp_minor_status, - &mech->mech_type, - &internal_name); } + } /* for */ - if (status != GSS_S_COMPLETE) - continue; - - /* - * Add this into the creds_returned structure, if we got - * a good credential for this mechanism. - */ - if (time_rec) { - *time_rec = *time_rec > temp_time_rec ? temp_time_rec : *time_rec; - temp_time_rec = *time_rec; - } - - creds_returned[j].available = 1; - creds_acquired++; - - /* - * If union_name is set, then we're done. Continue, and - * declare success. Otherwise, if do an inquire credentials - * from the first mechanism that succeeds and use that as the - * union name. - */ - if (union_name) - continue; - - status = mech->gss_inquire_cred(mech->context, &temp_minor_status, - creds_returned[j].cred, - &internal_name, 0, 0, 0); - if (status) { - /* Should never happen */ - creds_returned[j].available = 0; - creds_acquired--; - if (mech->gss_release_cred) - mech->gss_release_cred(mech->context, minor_status, - &creds_returned[j].cred); - continue; - } - - status = __gss_convert_name_to_union_name(&temp_minor_status, mech, - internal_name, - (gss_name_t *) &union_name); + /* ensure that we have at least one credential element */ + if (creds->count < 1) { + free(creds); + return (major); } - - /* - * Now allocate the creds struct, which will be cast as a gss_cred_id_t - * and returned in the output_cred_handle argument. If there were - * no credentials found, return an error. Also, allocate the - * actual_mechs data. - */ - if (creds_acquired == 0) { - free (creds_returned); - return (status); - } - - creds = (gss_union_cred_t) malloc(sizeof(gss_union_cred_desc)); - - creds->count = creds_acquired; - - creds->mechs_array = (gss_OID) - malloc(sizeof(gss_OID_desc) * creds_acquired); - - creds->cred_array = (gss_cred_id_t *) - malloc(sizeof(gss_cred_id_t) * creds_acquired); - - if(actual_mechs != NULL) { - *actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)); - - (*actual_mechs)->count = creds_acquired; - (*actual_mechs)->elements = (gss_OID) - malloc(sizeof(gss_OID_desc) * creds_acquired); - } - - /* - * copy the mechanisms found and their allocated credentials into the - * creds structure. At the same time, build up the actual_mechs - * data. - */ - - j = 0; - - for (i=0; icount; i++) { - if(creds_returned[i].available) { - - creds->mechs_array[j].length = - desired_mechs->elements[i].length; - creds->mechs_array[j].elements = (void *) - malloc(desired_mechs->elements[i].length); - memcpy(creds->mechs_array[j].elements, - desired_mechs->elements[i].elements, - desired_mechs->elements[i].length); - creds->cred_array[j] = creds_returned[i].cred; - if (actual_mechs) { - (*actual_mechs)->elements[j].length = - desired_mechs->elements[i].length; - (*actual_mechs)->elements[j].elements = (void *) - malloc(desired_mechs->elements[i].length); - memcpy((*actual_mechs)->elements[j].elements, - desired_mechs->elements[i].elements, - desired_mechs->elements[i].length); - } - j++; - } - } - - /* free the creds_returned struct, since we are done with it. */ - - free(creds_returned); - - /* record the information needed for gss_inquire_cred() */ - - creds->auxinfo.creation_time = time(0); - creds->auxinfo.time_rec = temp_time_rec; - creds->auxinfo.cred_usage = cred_usage; - /* - * we can't just record the internal name, desired_name, since - * it may be destroyed between now and the time gss_inquire_cred() - * is called. So we must record the printable name in a - * gss_buffer_t, calling gss_display_name() to fill it in. When - * gss_inquire_name() is called, we must then call gss_import_name() - * to get the internal name that is required at that point. + * fill in output parameters + * setup the actual mechs output parameter */ - if (desired_name) { - status = gss_display_name(&temp_minor_status, desired_name, - &creds->auxinfo.name, - &creds->auxinfo.name_type); - if (status) { - status = GSS_S_BAD_NAME; - goto error_out; + if (actual_mechs != NULL) { + if ((*actual_mechs = create_actual_mechs(creds->mechs_array, + creds->count)) == NULL) { + (void) gss_release_cred(minor_status, + (gss_cred_id_t *)&creds); + *minor_status = 0; + return (GSS_S_FAILURE); } - } else { - status = gss_display_name(&temp_minor_status, union_name, - &creds->auxinfo.name, - &creds->auxinfo.name_type); - if (status) { - status = GSS_S_BAD_NAME; - goto error_out; - } - } - - *output_cred_handle = (gss_cred_id_t) creds; - return(GSS_S_COMPLETE); - -error_out: - for (k=0; k < creds->count; k++) { - free(creds->mechs_array[k].elements); - if (actual_mechs) - free((*actual_mechs)->elements[k].elements); } - - if (actual_mechs) { - free((*actual_mechs)->elements); - free(*actual_mechs); - *actual_mechs = GSS_C_NULL_OID_SET; - } - free(creds->cred_array); - free(creds->mechs_array); - free(creds); - - return(status); + + if (time_rec) + *time_rec = outTime; + + + *output_cred_handle = (gss_cred_id_t)creds; + return (GSS_S_COMPLETE); } /* V2 KRB5_CALLCONV */ @@ -401,36 +229,73 @@ gss_add_cred(minor_status, input_cred_handle, OM_uint32 time_req, time_rec; gss_union_name_t union_name; gss_union_cred_t new_union_cred, union_cred; - gss_name_t internal_name; + gss_name_t internal_name = GSS_C_NO_NAME; + gss_name_t allocated_name = GSS_C_NO_NAME; gss_mechanism mech; - gss_cred_id_t cred; - gss_OID new_mechs_array; - gss_cred_id_t * new_cred_array; + gss_cred_id_t cred = NULL; + gss_OID new_mechs_array = NULL; + gss_cred_id_t * new_cred_array = NULL; + + /* check input parameters */ + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; + + if (input_cred_handle == GSS_C_NO_CREDENTIAL && + output_cred_handle == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED); + + if (output_cred_handle) + *output_cred_handle = GSS_C_NO_CREDENTIAL; - if (input_cred_handle == GSS_C_NO_CREDENTIAL) - return GSS_S_NO_CRED; + if (actual_mechs) + *actual_mechs = NULL; + + if (acceptor_time_rec) + *acceptor_time_rec = 0; - union_cred = (gss_union_cred_t) input_cred_handle; + if (initiator_time_rec) + *initiator_time_rec = 0; - mech = __gss_get_mechanism(desired_mech); + mech = gssint_get_mechanism(desired_mech); if (!mech) return GSS_S_BAD_MECH; + else if (!mech->gss_acquire_cred) + return (GSS_S_UNAVAILABLE); - if (__gss_get_mechanism_cred(union_cred, desired_mech) != - GSS_C_NO_CREDENTIAL) - return GSS_S_DUPLICATE_ELEMENT; + if (input_cred_handle == GSS_C_NO_CREDENTIAL) { + union_cred = malloc(sizeof (gss_union_cred_desc)); + if (union_cred == NULL) + return (GSS_S_FAILURE); - union_name = (gss_union_name_t) desired_name; - if (union_name->mech_type) { - if (!g_OID_equal(desired_mech, union_name->mech_type)) - return GSS_S_BAD_NAMETYPE; - internal_name = union_name->mech_name; + (void) memset(union_cred, 0, sizeof (gss_union_cred_desc)); + + /* for default credentials we will use GSS_C_NO_NAME */ + internal_name = GSS_C_NO_NAME; } else { - if (__gss_import_internal_name(minor_status, desired_mech, - union_name, &internal_name)) - return (GSS_S_BAD_NAME); + union_cred = (gss_union_cred_t)input_cred_handle; + if (gssint_get_mechanism_cred(union_cred, desired_mech) != + GSS_C_NO_CREDENTIAL) + return (GSS_S_DUPLICATE_ELEMENT); + + /* may need to create a mechanism specific name */ + if (desired_name) { + union_name = (gss_union_name_t)desired_name; + if (union_name->mech_type && + g_OID_equal(union_name->mech_type, + &mech->mech_type)) + internal_name = union_name->mech_name; + else { + if (gssint_import_internal_name(minor_status, + &mech->mech_type, union_name, + &allocated_name) != GSS_S_COMPLETE) + return (GSS_S_BAD_NAME); + internal_name = allocated_name; + } + } } + if (cred_usage == GSS_C_ACCEPT) time_req = acceptor_time_req; else if (cred_usage == GSS_C_INITIATE) @@ -443,22 +308,54 @@ gss_add_cred(minor_status, input_cred_handle, internal_name, time_req, GSS_C_NULL_OID_SET, cred_usage, &cred, NULL, &time_rec); + if (status != GSS_S_COMPLETE) goto errout; + /* may need to set credential auxinfo strucutre */ + if (union_cred->auxinfo.creation_time == 0) { + union_cred->auxinfo.creation_time = time(NULL); + union_cred->auxinfo.time_rec = time_rec; + union_cred->auxinfo.cred_usage = cred_usage; + + /* + * we must set the name; if name is not supplied + * we must do inquire cred to get it + */ + if (internal_name == NULL) { + if (mech->gss_inquire_cred == NULL || + ((status = mech->gss_inquire_cred( + mech->context, + &temp_minor_status, cred, + &allocated_name, NULL, NULL, + NULL)) != GSS_S_COMPLETE)) + goto errout; + internal_name = allocated_name; + } + + if (internal_name != GSS_C_NO_NAME) { + status = mech->gss_display_name(mech->context, + &temp_minor_status, internal_name, + &union_cred->auxinfo.name, + &union_cred->auxinfo.name_type); + + if (status != GSS_S_COMPLETE) + goto errout; + } + } + + /* now add the new credential elements */ new_mechs_array = (gss_OID) - malloc(sizeof(gss_OID_desc) * (union_cred->count+1)); - + malloc(sizeof (gss_OID_desc) * (union_cred->count+1)); + new_cred_array = (gss_cred_id_t *) - malloc(sizeof(gss_cred_id_t) * (union_cred->count+1)); + malloc(sizeof (gss_cred_id_t) * (union_cred->count+1)); if (!new_mechs_array || !new_cred_array) { - *minor_status = ENOMEM; status = GSS_S_FAILURE; goto errout; } - if (acceptor_time_rec) if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) *acceptor_time_rec = time_rec; @@ -467,57 +364,77 @@ gss_add_cred(minor_status, input_cred_handle, *initiator_time_rec = time_rec; /* - * OK, expand the mechanism array in the union credentials - * (Look for the union label...) + * OK, expand the mechanism array and the credential array */ - memcpy(new_mechs_array, union_cred->mechs_array, - sizeof(gss_OID_desc) * union_cred->count); - memcpy(new_cred_array, union_cred->cred_array, - sizeof(gss_cred_id_t) * union_cred->count); - + (void) memcpy(new_mechs_array, union_cred->mechs_array, + sizeof (gss_OID_desc) * union_cred->count); + (void) memcpy(new_cred_array, union_cred->cred_array, + sizeof (gss_cred_id_t) * union_cred->count); + new_cred_array[union_cred->count] = cred; - new_mechs_array[union_cred->count].length = desired_mech->length; - new_mechs_array[union_cred->count].elements = malloc(desired_mech->length); - if (!new_mechs_array[union_cred->count].elements) { - *minor_status = ENOMEM; + if ((new_mechs_array[union_cred->count].elements = + malloc(mech->mech_type.length)) == NULL) goto errout; + + g_OID_copy(&new_mechs_array[union_cred->count], + &mech->mech_type); + + if (actual_mechs) { + *actual_mechs = create_actual_mechs(new_mechs_array, + union_cred->count + 1); + if (*actual_mechs == NULL) { + free(new_mechs_array[union_cred->count].elements); + goto errout; + } } - memcpy(new_mechs_array[union_cred->count].elements, desired_mech->elements, - desired_mech->length); if (output_cred_handle == NULL) { free(union_cred->mechs_array); free(union_cred->cred_array); new_union_cred = union_cred; } else { - new_union_cred = malloc(sizeof(gss_union_cred_desc)); + new_union_cred = malloc(sizeof (gss_union_cred_desc)); if (new_union_cred == NULL) { - *minor_status = ENOMEM; + free(new_mechs_array[union_cred->count].elements); goto errout; } *new_union_cred = *union_cred; - *output_cred_handle = new_union_cred; + *output_cred_handle = (gss_cred_id_t)new_union_cred; } + new_union_cred->mechs_array = new_mechs_array; new_union_cred->cred_array = new_cred_array; new_union_cred->count++; - new_mechs_array = 0; - new_cred_array = 0; - if (actual_mechs) - *actual_mechs = create_actual_mechs(new_union_cred); - - status = GSS_S_COMPLETE; - + /* We're done with the internal name. Free it if we allocated it. */ + + if (allocated_name) + (void) gssint_release_internal_name(&temp_minor_status, + &mech->mech_type, + &allocated_name); + + return (GSS_S_COMPLETE); + errout: if (new_mechs_array) free(new_mechs_array); if (new_cred_array) free(new_cred_array); - if (!union_name->mech_type) { - (void) __gss_release_internal_name(&temp_minor_status, - desired_mech, &internal_name); + + if (cred != NULL && mech->gss_release_cred) + mech->gss_release_cred(mech->context, + &temp_minor_status, &cred); + + if (allocated_name) + (void) gssint_release_internal_name(&temp_minor_status, + &mech->mech_type, + &allocated_name); + + if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) { + if (union_cred->auxinfo.name.value) + free(union_cred->auxinfo.name.value); + free(union_cred); } - return(status); + return (status); } diff --git a/src/lib/gssapi/mechglue/g_canon_name.c b/src/lib/gssapi/mechglue/g_canon_name.c new file mode 100644 index 000000000..a726fefd0 --- /dev/null +++ b/src/lib/gssapi/mechglue/g_canon_name.c @@ -0,0 +1,155 @@ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* #pragma ident "@(#)g_canon_name.c 1.15 04/02/23 SMI" */ + +/* + * routine gss_canonicalize_name + * + * This routine is used to produce a mechanism specific + * representation of name that has been previously + * imported with gss_import_name. The routine uses the mechanism + * specific implementation of gss_import_name to implement this + * function. + * + * We allow a NULL output_name, in which case we modify the + * input_name to include the mechanism specific name. + */ + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include + +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 ********/ diff --git a/src/lib/gssapi/mechglue/g_compare_name.c b/src/lib/gssapi/mechglue/g_compare_name.c index 851be4a85..0a6db1c16 100644 --- a/src/lib/gssapi/mechglue/g_compare_name.c +++ b/src/lib/gssapi/mechglue/g_compare_name.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_compare_name.c 1.13 95/08/02 SMI" */ +/* #pragma ident "@(#)g_compare_name.c 1.16 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -33,10 +33,6 @@ #endif #include -#define g_OID_equal(o1,o2) \ - (((o1)->length == (o2)->length) && \ - (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0)) - OM_uint32 KRB5_CALLCONV gss_compare_name (minor_status, name1, @@ -54,13 +50,15 @@ int * name_equal; gss_mechanism mech; gss_name_t internal_name; - gss_initialize(); + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; - if (name1 == 0 || name2 == 0) { - if (name_equal) - *name_equal = 0; - return GSS_S_BAD_NAME; - } + if (name1 == 0 || name2 == 0) + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME); + + if (name_equal == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); union_name1 = (gss_union_name_t) name1; union_name2 = (gss_union_name_t) name2; @@ -78,16 +76,13 @@ int * name_equal; * information. */ if (union_name1->mech_type) { - mech = __gss_get_mechanism (union_name1->mech_type); + mech = gssint_get_mechanism (union_name1->mech_type); if (!mech) return (GSS_S_BAD_MECH); if (!mech->gss_compare_name) - return (GSS_S_BAD_BINDINGS); + return (GSS_S_UNAVAILABLE); } - if (name_equal == NULL) - return GSS_S_COMPLETE; - *name_equal = 0; /* Default to *not* equal.... */ /* @@ -116,8 +111,32 @@ int * name_equal; * gss_import_name(). */ if (!union_name1->mech_type && !union_name2->mech_type) { - if (!g_OID_equal(union_name1->name_type, union_name2->name_type)) + /* + * Second case, first sub-case... one name has null + * name_type, the other doesn't. + * + * Not knowing a mech_type we can't import the name with + * null name_type so we can't compare. + */ + if ((union_name1->name_type == GSS_C_NULL_OID && + union_name2->name_type != GSS_C_NULL_OID) || + (union_name1->name_type != GSS_C_NULL_OID && + union_name2->name_type == GSS_C_NULL_OID)) + return (GSS_S_COMPLETE); + /* + * Second case, second sub-case... both names have + * name_types, but they are different. + */ + if ((union_name1->name_type != GSS_C_NULL_OID && + union_name2->name_type != GSS_C_NULL_OID) && + !g_OID_equal(union_name1->name_type, + union_name2->name_type)) return (GSS_S_COMPLETE); + /* + * Second case, third sub-case... both names have equal + * name_types (and both have no mech_types) so we just + * compare the external_names. + */ if ((union_name1->external_name->length != union_name2->external_name->length) || (memcmp(union_name1->external_name->value, @@ -141,16 +160,17 @@ int * name_equal; union_name1 = (gss_union_name_t) name2; union_name2 = (gss_union_name_t) name1; } - major_status = __gss_import_internal_name(minor_status, + major_status = gssint_import_internal_name(minor_status, union_name1->mech_type, union_name2, &internal_name); if (major_status != GSS_S_COMPLETE) - return (GSS_S_COMPLETE); + return (GSS_S_COMPLETE); /* return complete, but not equal */ + major_status = mech->gss_compare_name(mech->context, minor_status, union_name1->mech_name, internal_name, name_equal); - __gss_release_internal_name(&temp_minor, union_name1->mech_type, + gssint_release_internal_name(&temp_minor, union_name1->mech_type, &internal_name); return (major_status); diff --git a/src/lib/gssapi/mechglue/g_context_time.c b/src/lib/gssapi/mechglue/g_context_time.c index 6f08c9224..5ce6b56d8 100644 --- a/src/lib/gssapi/mechglue/g_context_time.c +++ b/src/lib/gssapi/mechglue/g_context_time.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_context_time.c 1.8 95/08/07 SMI" */ +/* #pragma ident "@(#)g_context_time.c 1.12 98/01/22 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -42,18 +42,23 @@ OM_uint32 * time_rec; gss_union_ctx_id_t ctx; gss_mechanism mech; - gss_initialize(); + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; + + if (time_rec == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); if (context_handle == GSS_C_NO_CONTEXT) - return GSS_S_NO_CONTEXT; - + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT); + /* * select the approprate underlying mechanism routine and * call it. */ ctx = (gss_union_ctx_id_t) context_handle; - mech = __gss_get_mechanism (ctx->mech_type); + mech = gssint_get_mechanism (ctx->mech_type); if (mech) { @@ -64,10 +69,10 @@ OM_uint32 * time_rec; ctx->internal_ctx_id, time_rec); else - status = GSS_S_BAD_BINDINGS; + status = GSS_S_UNAVAILABLE; return(status); } - return(GSS_S_NO_CONTEXT); + return (GSS_S_BAD_MECH); } diff --git a/src/lib/gssapi/mechglue/g_delete_sec_context.c b/src/lib/gssapi/mechglue/g_delete_sec_context.c index fae0b0ac3..de70b8fb7 100644 --- a/src/lib/gssapi/mechglue/g_delete_sec_context.c +++ b/src/lib/gssapi/mechglue/g_delete_sec_context.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_delete_sec_context.c 1.10 95/08/07 SMI" */ +/* #pragma ident "@(#)g_delete_sec_context.c 1.11 97/11/09 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -46,20 +46,25 @@ gss_buffer_t output_token; gss_union_ctx_id_t ctx; gss_mechanism mech; - gss_initialize(); + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + if (output_token != GSS_C_NO_BUFFER) { + output_token->length = 0; + output_token->value = NULL; + } /* if the context_handle is Null, return NO_CONTEXT error */ - if(context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) - return(GSS_S_NO_CONTEXT); - + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT); + /* * select the approprate underlying mechanism routine and * call it. */ ctx = (gss_union_ctx_id_t) *context_handle; - mech = __gss_get_mechanism (ctx->mech_type); + mech = gssint_get_mechanism (ctx->mech_type); if (mech) { @@ -70,10 +75,9 @@ gss_buffer_t output_token; &ctx->internal_ctx_id, output_token); else - status = GSS_S_BAD_BINDINGS; + status = GSS_S_UNAVAILABLE; /* now free up the space for the union context structure */ - free(ctx->mech_type->elements); free(ctx->mech_type); free(*context_handle); @@ -81,6 +85,6 @@ gss_buffer_t output_token; return(status); } - - return(GSS_S_NO_CONTEXT); + + return (GSS_S_BAD_MECH); } diff --git a/src/lib/gssapi/mechglue/g_dsp_name.c b/src/lib/gssapi/mechglue/g_dsp_name.c index 8bd0426c3..161b2707e 100644 --- a/src/lib/gssapi/mechglue/g_dsp_name.c +++ b/src/lib/gssapi/mechglue/g_dsp_name.c @@ -1,4 +1,4 @@ -/* #ident "@(#)g_dsp_name.c 1.2 96/02/06 SMI" */ +/* #pragma ident "@(#)g_dsp_name.c 1.13 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -49,8 +49,18 @@ gss_OID * output_name_type; OM_uint32 major_status; gss_union_name_t union_name; + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; + if (input_name == 0) - return GSS_S_BAD_NAME; + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME); + + if (output_name_buffer == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + if (output_name_type) + *output_name_type = NULL; union_name = (gss_union_name_t) input_name; @@ -58,7 +68,7 @@ gss_OID * output_name_type; /* * OK, we have a mechanism-specific name; let's use it! */ - return (__gss_display_internal_name(minor_status, + return (gssint_display_internal_name(minor_status, union_name->mech_type, union_name->mech_name, output_name_buffer, @@ -70,27 +80,29 @@ gss_OID * output_name_type; * name into the output_name_buffer and point the output_name_type * to the name_type component of union_name */ - if (output_name_type != NULL) { + if (output_name_type != NULL && + union_name->name_type != GSS_C_NULL_OID) { major_status = generic_gss_copy_oid(minor_status, union_name->name_type, output_name_type); - if (major_status) + if (major_status != GSS_S_COMPLETE) return (major_status); } - - if (output_name_buffer != NULL) { - output_name_buffer->length = union_name->external_name->length; - - output_name_buffer->value = - (void *) malloc(output_name_buffer->length); - memcpy(output_name_buffer->value, - union_name->external_name->value, - output_name_buffer->length); + if ((output_name_buffer->value = + malloc(union_name->external_name->length + 1)) == NULL) { + if (output_name_type && *output_name_type != GSS_C_NULL_OID) { + (void) generic_gss_release_oid(minor_status, + output_name_type); + *output_name_type = NULL; + } + return (GSS_S_FAILURE); } - - if (minor_status) - *minor_status = 0; + output_name_buffer->length = union_name->external_name->length; + (void) memcpy(output_name_buffer->value, + union_name->external_name->value, + union_name->external_name->length); + ((char *)output_name_buffer->value)[output_name_buffer->length] = '\0'; return(GSS_S_COMPLETE); } diff --git a/src/lib/gssapi/mechglue/g_dsp_status.c b/src/lib/gssapi/mechglue/g_dsp_status.c index 4b58c38f7..83583035f 100644 --- a/src/lib/gssapi/mechglue/g_dsp_status.c +++ b/src/lib/gssapi/mechglue/g_dsp_status.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_display_status.c 1.8 95/08/07 SMI" */ +/* #pragma ident "@(#)g_dsp_status.c 1.17 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -29,9 +29,11 @@ #include "mglueP.h" #include -#ifdef HAVE_STDLIB_H #include -#endif +#include + +/* local function */ +static OM_uint32 displayMajor(OM_uint32, OM_uint32 *, gss_buffer_t); OM_uint32 KRB5_CALLCONV gss_display_status (minor_status, @@ -49,36 +51,275 @@ OM_uint32 * message_context; gss_buffer_t status_string; { - OM_uint32 status; gss_OID mech_type = (gss_OID) req_mech_type; gss_mechanism mech; - gss_initialize(); + /* check the input parameters */ + if (!minor_status) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + *minor_status = 0; + + if (!message_context || status_string == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + status_string->length = 0; + status_string->value = NULL; + + /* we handle major status codes, and the mechs do the minor */ + if (status_type == GSS_C_GSS_CODE) + return (displayMajor(status_value, message_context, + status_string)); /* - * select the approprate underlying mechanism routine and + * must be the minor status - let mechs do the work + * select the appropriate underlying mechanism routine and * call it. */ - mech = __gss_get_mechanism (mech_type); + mech = gssint_get_mechanism (mech_type); + + if (mech && mech->gss_display_status) { + if (mech_type == GSS_C_NULL_OID) + mech_type = &mech->mech_type; - if (mech == NULL) + return (mech->gss_display_status(mech->context, minor_status, + status_value, status_type, mech_type, + message_context, status_string)); + } + + if (!mech) return (GSS_S_BAD_MECH); - if (mech_type == GSS_C_NULL_OID) - mech_type = &mech->mech_type; - - if (mech->gss_display_status) - status = mech->gss_display_status( - mech->context, - minor_status, - status_value, - status_type, - mech_type, - message_context, - status_string); - else - status = GSS_S_BAD_BINDINGS; - - return(status); + return (GSS_S_UNAVAILABLE); } + +/* + * function to map the major error codes + * it uses case statements so that the strings could be wrapped by gettext + * msgCtxt is interpreted as: + * 0 - first call + * 1 - routine error + * >= 2 - the supplementary error code bit shifted by 1 + */ +static OM_uint32 +displayMajor(status, msgCtxt, outStr) +OM_uint32 status; +OM_uint32 *msgCtxt; +gss_buffer_t outStr; +{ + OM_uint32 oneVal, mask = 0x1, currErr; + char *errStr = NULL; + int i, haveErr = 0; + + /* take care of the success value first */ + if (status == GSS_S_COMPLETE) + errStr = "The routine completed successfully"; + else if (*msgCtxt == 0 && (oneVal = GSS_CALLING_ERROR(status))) { + switch (oneVal) { + case GSS_S_CALL_INACCESSIBLE_READ: + errStr = "A required input parameter" + " could not be read"; + break; + + case GSS_S_CALL_INACCESSIBLE_WRITE: + errStr = "A required output parameter" + " could not be written"; + break; + + case GSS_S_CALL_BAD_STRUCTURE: + errStr = "A parameter was malformed"; + break; + + default: + errStr = "An invalid status code was supplied"; + break; + } + + /* we now need to determine new value of msgCtxt */ + if (GSS_ROUTINE_ERROR(status)) + *msgCtxt = 1; + else if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0) + *msgCtxt = (OM_uint32)(oneVal << 1); + else + *msgCtxt = 0; + + } else if ((*msgCtxt == 0 || *msgCtxt == 1) && + (oneVal = GSS_ROUTINE_ERROR(status))) { + switch (oneVal) { + case GSS_S_BAD_MECH: + errStr = "An unsupported mechanism" + " was requested"; + break; + + case GSS_S_BAD_NAME: + errStr = "An invalid name was supplied"; + break; + + case GSS_S_BAD_NAMETYPE: + errStr = "A supplied name was of an" + " unsupported type"; + break; + + case GSS_S_BAD_BINDINGS: + errStr = "Incorrect channel bindings" + " were supplied"; + break; + + case GSS_S_BAD_SIG: /* same as GSS_S_BAD_MIC: */ + errStr = "A token had an invalid Message" + " Integrity Check (MIC)"; + break; + + case GSS_S_NO_CRED: + errStr = "No credentials were supplied, or the" + " credentials were unavailable or" + " inaccessible"; + break; + + case GSS_S_NO_CONTEXT: + errStr = "No context has been established"; + break; + + case GSS_S_DEFECTIVE_TOKEN: + errStr = "Invalid token was supplied"; + break; + + case GSS_S_DEFECTIVE_CREDENTIAL: + errStr = "Invalid credential was supplied"; + break; + + case GSS_S_CREDENTIALS_EXPIRED: + errStr = "The referenced credential has" + " expired"; + break; + + case GSS_S_CONTEXT_EXPIRED: + errStr = "The referenced context has expired"; + break; + + case GSS_S_FAILURE: + errStr = "Unspecified GSS failure. Minor code" + " may provide more information"; + break; + + case GSS_S_BAD_QOP: + errStr = "The quality-of-protection (QOP) " + "requested could not be provided"; + break; + + case GSS_S_UNAUTHORIZED: + errStr = "The operation is forbidden by local" + " security policy"; + break; + + case GSS_S_UNAVAILABLE: + errStr = "The operation or option is not" + " available or unsupported"; + break; + + case GSS_S_DUPLICATE_ELEMENT: + errStr = "The requested credential element" + " already exists"; + break; + + case GSS_S_NAME_NOT_MN: + errStr = "The provided name was not mechanism" + " specific (MN)"; + break; + + case GSS_S_BAD_STATUS: + default: + errStr = "An invalid status code was supplied"; + } + + /* we must determine if the caller should call us again */ + if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0) + *msgCtxt = (OM_uint32)(oneVal << 1); + else + *msgCtxt = 0; + + } else if ((*msgCtxt == 0 || *msgCtxt >= 2) && + (oneVal = GSS_SUPPLEMENTARY_INFO(status))) { + /* + * if msgCtxt is not 0, then it should encode + * the supplementary error code we should be printing + */ + if (*msgCtxt >= 2) + oneVal = (OM_uint32) (*msgCtxt) >> 1; + else + oneVal = GSS_SUPPLEMENTARY_INFO(status); + + /* we display the errors LSB first */ + for (i = 0; i < 16; i++) { + if (oneVal & mask) { + haveErr = 1; + break; + } + mask <<= 1; + } + + /* isolate the bit or if not found set to illegal value */ + if (haveErr) + currErr = oneVal & mask; + else + currErr = 1 << 17; /* illegal value */ + + switch (currErr) { + case GSS_S_CONTINUE_NEEDED: + errStr = "The routine must be called again to" + " complete its function"; + break; + + case GSS_S_DUPLICATE_TOKEN: + errStr = "The token was a duplicate of an" + " earlier token"; + break; + + case GSS_S_OLD_TOKEN: + errStr = "The token's validity period" + " has expired"; + break; + + case GSS_S_UNSEQ_TOKEN: + errStr = "A later token has already been" + " processed"; + break; + + case GSS_S_GAP_TOKEN: + errStr = "An expected per-message token was" + " not received"; + break; + + default: + errStr = "An invalid status code was supplied"; + } + + /* + * we must check if there is any other supplementary errors + * if found, then turn off current bit, and store next value + * in msgCtxt shifted by 1 bit + */ + if (!haveErr) + *msgCtxt = 0; + else if (GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) + *msgCtxt = (OM_uint32) + ((GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) << 1); + else + *msgCtxt = 0; + } + + if (errStr == NULL) + errStr = "An invalid status code was supplied"; + + /* now copy the status code and return to caller */ + outStr->length = strlen(errStr); + outStr->value = malloc((size_t)outStr->length+1); + if (outStr->value == NULL) { + outStr->length = 0; + return (GSS_S_FAILURE); + } + + (void) strcpy((char *)outStr->value, errStr); + return (GSS_S_COMPLETE); +} /* displayMajor */ diff --git a/src/lib/gssapi/mechglue/g_dup_name.c b/src/lib/gssapi/mechglue/g_dup_name.c new file mode 100644 index 000000000..1f8815f9d --- /dev/null +++ b/src/lib/gssapi/mechglue/g_dup_name.c @@ -0,0 +1,118 @@ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* #pragma ident "@(#)g_dup_name.c 1.14 04/02/23 SMI" */ + +/* + * routine gss_duplicate_name + * + * This routine does not rely on mechanism implementation of this + * name, but instead uses mechanism specific gss_import_name routine. + */ + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include + +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 */ diff --git a/src/lib/gssapi/mechglue/g_exp_sec_context.c b/src/lib/gssapi/mechglue/g_exp_sec_context.c index 958553b49..539920b49 100644 --- a/src/lib/gssapi/mechglue/g_exp_sec_context.c +++ b/src/lib/gssapi/mechglue/g_exp_sec_context.c @@ -1,4 +1,4 @@ -/* #ident "@(#)g_exp_sec_context.c 1.2 96/01/18 SMI" */ +/* #pragma ident "@(#)g_exp_sec_context.c 1.14 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -45,16 +45,21 @@ gss_buffer_t interprocess_token; { OM_uint32 status; - size_t length; + OM_uint32 length; gss_union_ctx_id_t ctx; gss_mechanism mech; gss_buffer_desc token; char *buf; - gss_initialize(); + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) - return GSS_S_NO_CONTEXT; + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT); + + if (interprocess_token == NULL) + return (GSS_S_CALL_INACCESSIBLE_READ); /* * select the approprate underlying mechanism routine and @@ -62,11 +67,11 @@ gss_buffer_t interprocess_token; */ ctx = (gss_union_ctx_id_t) *context_handle; - mech = __gss_get_mechanism (ctx->mech_type); + mech = gssint_get_mechanism (ctx->mech_type); if (!mech) return GSS_S_BAD_MECH; if (!mech->gss_export_sec_context) - return GSS_S_BAD_BINDINGS; + return (GSS_S_UNAVAILABLE); status = mech->gss_export_sec_context(mech->context, minor_status, &ctx->internal_ctx_id, &token); @@ -78,7 +83,6 @@ gss_buffer_t interprocess_token; interprocess_token->value = malloc(length); if (interprocess_token->value == 0) { (void) gss_release_buffer(minor_status, &token); - *minor_status = ENOMEM; return (GSS_S_FAILURE); } buf = interprocess_token->value; diff --git a/src/lib/gssapi/mechglue/g_export_name.c b/src/lib/gssapi/mechglue/g_export_name.c new file mode 100644 index 000000000..a6aab3ad9 --- /dev/null +++ b/src/lib/gssapi/mechglue/g_export_name.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1996,1997, by Sun Microsystems, Inc. + * All rights reserved. + */ + +/* #pragma ident "@(#)g_export_name.c 1.11 00/07/17 SMI" */ + +/* + * glue routine gss_export_name + * + * Will either call the mechanism defined gss_export_name, or if one is + * not defined will call a generic_gss_export_name routine. + */ + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include + +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); +} diff --git a/src/lib/gssapi/mechglue/g_glue.c b/src/lib/gssapi/mechglue/g_glue.c index 6aecab7fb..030fbfdfa 100644 --- a/src/lib/gssapi/mechglue/g_glue.c +++ b/src/lib/gssapi/mechglue/g_glue.c @@ -1,4 +1,4 @@ -/* #ident "@(#)g_glue.c 1.1 96/02/06 SMI" */ +/* #pragma ident "@(#)g_glue.c 1.25 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -30,40 +30,150 @@ #include #include -#define g_OID_equal(o1,o2) \ - (((o1)->length == (o2)->length) && \ - (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0)) +#define MSO_BIT (8*(sizeof (int) - 1)) /* Most significant octet bit */ -extern gss_mechanism *__gss_mechs_array; +extern gss_mechanism *gssint_mechs_array; /* * This file contains the support routines for the glue layer. */ /* - * given the mechs_array and a mechanism OID, return the - * pointer to the mechanism, or NULL if that mechanism is - * not supported. If the requested OID is NULL, then return - * the first mechanism. + * get_der_length: Givin a pointer to a buffer that contains a DER encoded + * length, decode the length updating the buffer to point to the character + * after the DER encoding. The parameter bytes will point to the number of + * bytes that made up the DER encoding of the length originally pointed to + * by the buffer. Note we return -1 on error. */ +int +gssint_get_der_length(unsigned char **buf, unsigned int buf_len, unsigned int *bytes) +{ + /* p points to the beginning of the buffer */ + unsigned char *p = *buf; + int length, new_length; + int octets; + + if (buf_len < 1) + return (-1); + + /* We should have at least one byte */ + *bytes = 1; + + /* + * If the High order bit is not set then the length is just the value + * of *p. + */ + if (*p < 128) { + *buf = p+1; /* Advance the buffer */ + return (*p); /* return the length */ + } + + /* + * if the High order bit is set, then the low order bits represent + * the number of bytes that contain the DER encoding of the length. + */ + + octets = *p++ & 0x7f; + *bytes += octets; -gss_mechanism __gss_get_mechanism (type) - gss_OID type; + /* See if the supplied buffer contains enough bytes for the length. */ + if (octets > buf_len - 1) + return (-1); + + /* + * Calculate a multibyte length. The length is encoded as an + * unsigned integer base 256. + */ + for (length = 0; octets; octets--) { + new_length = (length << 8) + *p++; + if (new_length < length) /* overflow */ + return (-1); + length = new_length; + } + + *buf = p; /* Advance the buffer */ + + return (length); +} + +/* + * der_length_size: Return the number of bytes to encode a given length. + */ +unsigned int +gssint_der_length_size(unsigned int len) { - int i; + int i; - if (type == GSS_C_NULL_OID) - return (__gss_mechs_array[0]); + if (len < 128) + return (1); - for (i=0; __gss_mechs_array[i]->mech_type.length != 0; i++) { - if ((__gss_mechs_array[i]->mech_type.length == type->length) && - (memcmp (__gss_mechs_array[i]->mech_type.elements, type->elements, - type->length) == 0)) { + for (i = 0; len; i++) { + len >>= 8; + } + + return (i+1); +} + +/* + * put_der_length: Encode the supplied length into the buffer pointed to + * by buf. max_length represents the maximum length of the buffer pointed + * to by buff. We will advance buf to point to the character after the newly + * DER encoded length. We return 0 on success or -l it the length cannot + * be encoded in max_len characters. + */ +int +gssint_put_der_length(unsigned int length, unsigned char **buf, unsigned int max_len) +{ + unsigned char *s = *buf, *p; + unsigned int buf_len = 0; + int i, first; + + /* Oops */ + if (buf == 0 || max_len < 1) + return (-1); + + /* Single byte is the length */ + if (length < 128) { + *s++ = length; + *buf = s; + return (0); + } + + /* First byte contains the number of octets */ + p = s + 1; + + /* Running total of the DER encoding length */ + buf_len = 0; - return (__gss_mechs_array[i]); + /* + * Encode MSB first. We do the encoding by setting a shift + * factor to MSO_BIT (24 for 32 bit words) and then shifting the length + * by the factor. We then encode the resulting low order byte. + * We subtract 8 from the shift factor and repeat to ecnode the next + * byte. We stop when the shift factor is zero or we've run out of + * buffer to encode into. + */ + first = 0; + for (i = MSO_BIT; i >= 0 && buf_len <= max_len; i -= 8) { + unsigned int v; + v = (length >> i) & 0xff; + if ((v) || first) { + buf_len += 1; + *p++ = v; + first = 1; } } - return NULL; + if (i >= 0) /* buffer overflow */ + return (-1); + + /* + * We go back now and set the first byte to be the length with + * the high order bit set. + */ + *s = buf_len | 0x80; + *buf = p; + + return (0); } @@ -72,7 +182,7 @@ gss_mechanism __gss_get_mechanism (type) * */ -OM_uint32 __gss_get_mech_type(OID, token) +OM_uint32 gssint_get_mech_type(OID, token) gss_OID OID; gss_buffer_t token; { @@ -102,7 +212,10 @@ OM_uint32 __gss_get_mech_type(OID, token) * The routine fills in the OID value and returns an error as necessary. */ - if (token == NULL) + if (OID == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + if ((token == NULL) || (token->value == NULL)) return (GSS_S_DEFECTIVE_TOKEN); /* Skip past the APP/Sequnce byte and the token length */ @@ -112,6 +225,11 @@ OM_uint32 __gss_get_mech_type(OID, token) if (*(buffer_ptr++) != 0x60) return (GSS_S_DEFECTIVE_TOKEN); length = *buffer_ptr++; + + /* check if token length is null */ + if (length == 0) + return (GSS_S_DEFECTIVE_TOKEN); + if (length & 0x80) { if ((length & 0x7f) > 4) return (GSS_S_DEFECTIVE_TOKEN); @@ -133,7 +251,7 @@ OM_uint32 __gss_get_mech_type(OID, token) #include "mglueP.h" -OM_uint32 __gss_import_internal_name (minor_status, mech_type, union_name, +OM_uint32 gssint_import_internal_name (minor_status, mech_type, union_name, internal_name) OM_uint32 *minor_status; gss_OID mech_type; @@ -143,7 +261,7 @@ gss_name_t *internal_name; OM_uint32 status; gss_mechanism mech; - mech = __gss_get_mechanism (mech_type); + mech = gssint_get_mechanism (mech_type); if (mech) { if (mech->gss_import_name) status = mech->gss_import_name ( @@ -153,7 +271,7 @@ gss_name_t *internal_name; union_name->name_type, internal_name); else - status = GSS_S_BAD_BINDINGS; + status = GSS_S_UNAVAILABLE; return (status); } @@ -161,7 +279,124 @@ gss_name_t *internal_name; return (GSS_S_BAD_MECH); } -OM_uint32 __gss_display_internal_name (minor_status, mech_type, internal_name, +OM_uint32 gssint_export_internal_name(minor_status, mech_type, + internal_name, name_buf) + OM_uint32 *minor_status; + const gss_OID mech_type; + const gss_name_t internal_name; + gss_buffer_t name_buf; +{ + OM_uint32 status; + gss_mechanism mech; + gss_buffer_desc dispName; + gss_OID nameOid; + unsigned char *buf = NULL; + const unsigned char tokId[] = "\x04\x01"; + const unsigned int tokIdLen = 2; + const int mechOidLenLen = 2, mechOidTagLen = 1, nameLenLen = 4; + int mechOidDERLen = 0; + int mechOidLen = 0; + + mech = gssint_get_mechanism(mech_type); + if (!mech) + return (GSS_S_BAD_MECH); + + if (mech->gss_export_name) + return (mech->gss_export_name(mech->context, + minor_status, + internal_name, + name_buf)); + + /* + * if we are here it is because the mechanism does not provide + * a gss_export_name so we will use our implementation. We + * do required that the mechanism define a gss_display_name. + */ + if (!mech->gss_display_name) + return (GSS_S_UNAVAILABLE); + + /* + * NOTE: RFC2743 (section 3.2) governs the format of the outer + * wrapper of exported names; the mechanisms' specs govern + * the format of the inner portion of the exported name + * and, for some (e.g., RFC1964, the Kerberos V mech), a + * generic default as implemented here will do. + * + * The outer wrapper of an exported MN is: 2-octet tok Id + * (0x0401) + 2-octet network-byte order mech OID length + mech + * oid (in DER format, including DER tag and DER length) + + * 4-octet network-byte order length of inner portion + inner + * portion. + * + * For the Kerberos V mechanism the inner portion of an exported + * MN is the display name string and ignores the name type OID + * altogether. And we hope this will be so for any future + * mechanisms also, so that factoring name export/import out of + * the mech and into libgss pays off. + */ + if ((status = mech->gss_display_name(mech->context, + minor_status, + internal_name, + &dispName, + &nameOid)) + != GSS_S_COMPLETE) + return (status); + + /* determine the size of the buffer needed */ + mechOidDERLen = gssint_der_length_size(mech_type->length); + name_buf->length = tokIdLen + mechOidLenLen + + mechOidTagLen + mechOidDERLen + + mech_type->length + + nameLenLen + dispName.length; + if ((name_buf->value = (void*)malloc(name_buf->length)) == + (void*)NULL) { + name_buf->length = 0; + (void) gss_release_buffer(&status, &dispName); + return (GSS_S_FAILURE); + } + + /* now create the name ..... */ + buf = (unsigned char *)name_buf->value; + (void) memset(name_buf->value, 0, name_buf->length); + (void) memcpy(buf, tokId, tokIdLen); + buf += tokIdLen; + + /* spec allows only 2 bytes for the mech oid length */ + mechOidLen = mechOidDERLen + mechOidTagLen + mech_type->length; + *buf++ = (mechOidLen & 0xFF00) >> 8; + *buf++ = (mechOidLen & 0x00FF); + + /* + * DER Encoding of mech OID contains OID Tag (0x06), length and + * mech OID value + */ + *buf++ = 0x06; + if (gssint_put_der_length(mech_type->length, &buf, + (name_buf->length - tokIdLen -2)) != 0) { + name_buf->length = 0; + free(name_buf->value); + (void) gss_release_buffer(&status, &dispName); + return (GSS_S_FAILURE); + } + + (void) memcpy(buf, mech_type->elements, mech_type->length); + buf += mech_type->length; + + /* spec designates the next 4 bytes for the name length */ + *buf++ = (dispName.length & 0xFF000000) >> 24; + *buf++ = (dispName.length & 0x00FF0000) >> 16; + *buf++ = (dispName.length & 0x0000FF00) >> 8; + *buf++ = (dispName.length & 0X000000FF); + + /* for the final ingredient - add the name from gss_display_name */ + (void) memcpy(buf, dispName.value, dispName.length); + + /* release the buffer obtained from gss_display_name */ + (void) gss_release_buffer(minor_status, &dispName); + return (GSS_S_COMPLETE); +} /* gssint_export_internal_name */ + +OM_uint32 gssint_display_internal_name (minor_status, mech_type, internal_name, external_name, name_type) OM_uint32 *minor_status; gss_OID mech_type; @@ -172,7 +407,7 @@ gss_OID *name_type; OM_uint32 status; gss_mechanism mech; - mech = __gss_get_mechanism (mech_type); + mech = gssint_get_mechanism (mech_type); if (mech) { if (mech->gss_display_name) status = mech->gss_display_name ( @@ -182,7 +417,7 @@ gss_OID *name_type; external_name, name_type); else - status = GSS_S_BAD_BINDINGS; + status = GSS_S_UNAVAILABLE; return (status); } @@ -190,7 +425,7 @@ gss_OID *name_type; return (GSS_S_BAD_MECH); } -OM_uint32 __gss_release_internal_name (minor_status, mech_type, internal_name) +OM_uint32 gssint_release_internal_name (minor_status, mech_type, internal_name) OM_uint32 *minor_status; gss_OID mech_type; gss_name_t *internal_name; @@ -198,7 +433,7 @@ gss_name_t *internal_name; OM_uint32 status; gss_mechanism mech; - mech = __gss_get_mechanism (mech_type); + mech = gssint_get_mechanism (mech_type); if (mech) { if (mech->gss_release_name) status = mech->gss_release_name ( @@ -206,7 +441,7 @@ gss_name_t *internal_name; minor_status, internal_name); else - status = GSS_S_BAD_BINDINGS; + status = GSS_S_UNAVAILABLE; return (status); } @@ -220,7 +455,7 @@ gss_name_t *internal_name; * name. Note that internal_name should be considered "consumed" by * this call, whether or not we return an error. */ -OM_uint32 __gss_convert_name_to_union_name(minor_status, mech, +OM_uint32 gssint_convert_name_to_union_name(minor_status, mech, internal_name, external_name) OM_uint32 *minor_status; gss_mechanism mech; @@ -232,7 +467,6 @@ OM_uint32 __gss_convert_name_to_union_name(minor_status, mech, union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc)); if (!union_name) { - *minor_status = ENOMEM; goto allocation_failure; } union_name->mech_type = 0; @@ -248,7 +482,6 @@ OM_uint32 __gss_convert_name_to_union_name(minor_status, mech, union_name->external_name = (gss_buffer_t) malloc(sizeof(gss_buffer_desc)); if (!union_name->external_name) { - *minor_status = ENOMEM; goto allocation_failure; } @@ -271,13 +504,17 @@ allocation_failure: } if (union_name->name_type) gss_release_oid(&tmp, &union_name->name_type); - if (union_name->mech_name) - __gss_release_internal_name(minor_status, union_name->mech_type, - &union_name->mech_name); if (union_name->mech_type) gss_release_oid(&tmp, &union_name->mech_type); free(union_name); } + /* + * do as the top comment says - since we are now owners of + * internal_name, we must clean it up + */ + if (internal_name) + (void) gssint_release_internal_name(&tmp, &mech->mech_type, + &internal_name); return (major_status); } @@ -286,7 +523,7 @@ allocation_failure: * external union credential. */ gss_cred_id_t -__gss_get_mechanism_cred(union_cred, mech_type) +gssint_get_mechanism_cred(union_cred, mech_type) gss_union_cred_t union_cred; gss_OID mech_type; { @@ -302,4 +539,46 @@ __gss_get_mechanism_cred(union_cred, mech_type) return GSS_C_NO_CREDENTIAL; } - +/* + * Routine to create and copy the gss_buffer_desc structure. + * Both space for the structure and the data is allocated. + */ +OM_uint32 +gssint_create_copy_buffer(srcBuf, destBuf, addNullChar) + const gss_buffer_t srcBuf; + gss_buffer_t *destBuf; + int addNullChar; +{ + gss_buffer_t aBuf; + unsigned int len; + + if (destBuf == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + *destBuf = 0; + + aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc)); + if (!aBuf) + return (GSS_S_FAILURE); + + if (addNullChar) + len = srcBuf->length + 1; + else + len = srcBuf->length; + + if (!(aBuf->value = (void*)malloc(len))) { + free(aBuf); + return (GSS_S_FAILURE); + } + + + (void) memcpy(aBuf->value, srcBuf->value, srcBuf->length); + aBuf->length = srcBuf->length; + *destBuf = aBuf; + + /* optionally add a NULL character */ + if (addNullChar) + ((char *)aBuf->value)[aBuf->length] = '\0'; + + return (GSS_S_COMPLETE); +} /* ****** gssint_create_copy_buffer ****** */ diff --git a/src/lib/gssapi/mechglue/g_imp_name.c b/src/lib/gssapi/mechglue/g_imp_name.c index e93b4c9ac..48815b361 100644 --- a/src/lib/gssapi/mechglue/g_imp_name.c +++ b/src/lib/gssapi/mechglue/g_imp_name.c @@ -1,4 +1,4 @@ -/* #ident "@(#)g_imp_name.c 1.2 96/02/06 SMI" */ +/* #pragma ident "@(#)g_imp_name.c 1.26 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -35,6 +35,9 @@ #include #include +/* local function to import GSS_C_EXPORT_NAME names */ +static OM_uint32 importExportName(OM_uint32 *, gss_union_name_t); + OM_uint32 KRB5_CALLCONV gss_import_name(minor_status, input_name_buffer, @@ -49,33 +52,32 @@ gss_name_t * output_name; { gss_union_name_t union_name; OM_uint32 tmp, major_status = GSS_S_FAILURE; - gss_OID mech; - - gss_initialize(); - if (minor_status) - *minor_status = 0; + /* check output parameters */ + if (!minor_status) + return (GSS_S_CALL_INACCESSIBLE_WRITE); - /* if output_name is NULL, simply return */ + *minor_status = 0; - if(output_name == NULL) - return (GSS_S_COMPLETE); + if (output_name == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); *output_name = 0; if (input_name_buffer == GSS_C_NO_BUFFER) return (GSS_S_BAD_NAME); + if (GSS_EMPTY_BUFFER(input_name_buffer)) + return (GSS_S_BAD_NAME); + /* * First create the union name struct that will hold the external * name and the name type. */ - union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc)); - if (!union_name) { - *minor_status = ENOMEM; - goto allocation_failure; - } + if (!union_name) + return (GSS_S_FAILURE); + union_name->mech_type = 0; union_name->mech_name = 0; union_name->name_type = 0; @@ -84,61 +86,43 @@ gss_name_t * output_name; /* * All we do here is record the external name and name_type. * When the name is actually used, the underlying gss_import_name() - * is called for the appropriate mechanism. Note that the name type - * is assumed to be constant, so only a pointer to it is stored in - * union_name + * is called for the appropriate mechanism. The exception to this + * rule is when the name of GSS_C_NT_EXPORT_NAME type. If that is + * the case, then we make it MN in this call. */ - union_name->external_name = - (gss_buffer_t) malloc(sizeof(gss_buffer_desc)); - if (!union_name->external_name) { - *minor_status = ENOMEM; - goto allocation_failure; - } - - union_name->external_name->length = input_name_buffer->length; - /* we malloc length+1 to stick a NULL on the end, just in case */ - /* Note that this NULL is not included in ->length for a reason! */ - union_name->external_name->value = - (void *) malloc(input_name_buffer->length+1); - if (!union_name->external_name->value) { - *minor_status = ENOMEM; - goto allocation_failure; + major_status = gssint_create_copy_buffer(input_name_buffer, + &union_name->external_name, 0); + if (major_status != GSS_S_COMPLETE) { + free(union_name); + return (major_status); } - - memcpy(union_name->external_name->value, input_name_buffer->value, - input_name_buffer->length); - - /* add NULL to end of external_name->value, just in case... */ - ((char *)union_name->external_name->value) - [input_name_buffer->length] = '\0'; - major_status = generic_gss_copy_oid(minor_status, input_name_type, - &union_name->name_type); - if (major_status != GSS_S_COMPLETE) - goto allocation_failure; + if (input_name_type != GSS_C_NULL_OID) { + major_status = generic_gss_copy_oid(minor_status, + input_name_type, + &union_name->name_type); + if (major_status != GSS_S_COMPLETE) + goto allocation_failure; + } /* - * See if this is a mechanism-specific name. If so, let's import - * it now so we can get any error messages, and to avoid trouble - * later... + * In MIT Distribution the mechanism is determined from the nametype; + * This is not a good idea - first mechanism that supports a given + * name type is picked up; later on the caller can request a + * different mechanism. So we don't determine the mechanism here. Now + * the user level and kernel level import_name routine looks similar + * except the kernel routine makes a copy of the nametype structure. We + * do however make this an MN for names of GSS_C_NT_EXPORT_NAME type. */ - mech = gss_find_mechanism_from_name_type(input_name_type); - if (mech) { - major_status = generic_gss_copy_oid(minor_status, mech, - &union_name->mech_type); + if (input_name_type != GSS_C_NULL_OID && + g_OID_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) { + major_status = importExportName(minor_status, union_name); if (major_status != GSS_S_COMPLETE) goto allocation_failure; - - major_status = __gss_import_internal_name(minor_status, mech, - union_name, - &union_name->mech_name); - if (major_status) - goto allocation_failure; } - *output_name = (gss_name_t) union_name; - - return(GSS_S_COMPLETE); + *output_name = (gss_name_t)union_name; + return (GSS_S_COMPLETE); allocation_failure: if (union_name) { @@ -150,7 +134,7 @@ allocation_failure: if (union_name->name_type) generic_gss_release_oid(&tmp, &union_name->name_type); if (union_name->mech_name) - __gss_release_internal_name(minor_status, union_name->mech_type, + gssint_release_internal_name(minor_status, union_name->mech_type, &union_name->mech_name); if (union_name->mech_type) generic_gss_release_oid(&tmp, &union_name->mech_type); @@ -158,3 +142,187 @@ allocation_failure: } return (major_status); } + +/* + * GSS export name constants + */ +static const char *expNameTokId = "\x04\x01"; +static const unsigned int expNameTokIdLen = 2; +static const unsigned int mechOidLenLen = 2; +static const unsigned int nameTypeLenLen = 2; + +static OM_uint32 +importExportName(minor, unionName) + OM_uint32 *minor; + gss_union_name_t unionName; +{ + gss_OID_desc mechOid; + gss_buffer_desc expName; + unsigned char *buf; + gss_mechanism mech; + OM_uint32 major, mechOidLen, nameLen, curLength; + unsigned int bytes; + + expName.value = unionName->external_name->value; + expName.length = unionName->external_name->length; + + curLength = expNameTokIdLen + mechOidLenLen; + if (expName.length < curLength) + return (GSS_S_DEFECTIVE_TOKEN); + + buf = (unsigned char *)expName.value; + if (memcmp(expNameTokId, buf, expNameTokIdLen) != 0) + return (GSS_S_DEFECTIVE_TOKEN); + + buf += expNameTokIdLen; + + /* extract the mechanism oid length */ + mechOidLen = (*buf++ << 8); + mechOidLen |= (*buf++); + curLength += mechOidLen; + if (expName.length < curLength) + return (GSS_S_DEFECTIVE_TOKEN); + /* + * The mechOid itself is encoded in DER format, OID Tag (0x06) + * length and the value of mech_OID + */ + if (*buf++ != 0x06) + return (GSS_S_DEFECTIVE_TOKEN); + + /* + * mechoid Length is encoded twice; once in 2 bytes as + * explained in RFC2743 (under mechanism independent exported + * name object format) and once using DER encoding + * + * We verify both lengths. + */ + + mechOid.length = gssint_get_der_length(&buf, + (expName.length - curLength), &bytes); + mechOid.elements = (void *)buf; + + /* + * 'bytes' is the length of the DER length, '1' is for the DER + * tag for OID + */ + if ((bytes + mechOid.length + 1) != mechOidLen) + return (GSS_S_DEFECTIVE_TOKEN); + + buf += mechOid.length; + if ((mech = gssint_get_mechanism(&mechOid)) == NULL) + return (GSS_S_BAD_MECH); + + if (mech->gss_import_name == NULL) + return (GSS_S_UNAVAILABLE); + + /* + * we must now determine if we should unwrap the name ourselves + * or make the mechanism do it - we should only unwrap it + * if we create it; so if mech->gss_export_name == NULL, we must + * have created it. + */ + if (mech->gss_export_name) { + if ((major = mech->gss_import_name(mech->context, minor, + &expName, (gss_OID)GSS_C_NT_EXPORT_NAME, + &unionName->mech_name)) != GSS_S_COMPLETE || + (major = generic_gss_copy_oid(minor, &mechOid, + &unionName->mech_type)) != + GSS_S_COMPLETE) { + return (major); + } + return (major); + } + /* + * we must have exported the name - so we now need to reconstruct it + * and call the mechanism to create it + * + * WARNING: Older versions of gssint_export_internal_name() did + * not export names correctly, but now it does. In + * order to stay compatible with existing exported + * names we must support names exported the broken + * way. + * + * Specifically, gssint_export_internal_name() used to include + * the name type OID in the encoding of the exported MN. + * Additionally, the Kerberos V mech used to make display names + * that included a null terminator which was counted in the + * display name gss_buffer_desc. + */ + curLength += 4; /* 4 bytes for name len */ + if (expName.length < curLength) + return (GSS_S_DEFECTIVE_TOKEN); + + /* next 4 bytes in the name are the name length */ + nameLen = (*buf++) << 24; + nameLen |= (*buf++ << 16); + nameLen |= (*buf++ << 8); + nameLen |= (*buf++); + + /* + * we use < here because bad code in rpcsec_gss rounds up exported + * name token lengths and pads with nulls, otherwise != would be + * appropriate + */ + curLength += nameLen; /* this is the total length */ + if (expName.length < curLength) + return (GSS_S_DEFECTIVE_TOKEN); + + /* + * We detect broken exported names here: they always start with + * a two-octet network-byte order OID length, which is always + * less than 256 bytes, so the first octet of the length is + * always '\0', which is not allowed in GSS-API display names + * (or never occurs in them anyways). Of course, the OID + * shouldn't be there, but it is. After the OID (sans DER tag + * and length) there's the name itself, though null-terminated; + * this null terminator should also not be there, but it is. + */ + if (nameLen > 0 && *buf == '\0') { + OM_uint32 nameTypeLen; + /* next two bytes are the name oid */ + if (nameLen < nameTypeLenLen) + return (GSS_S_DEFECTIVE_TOKEN); + + nameLen -= nameTypeLenLen; + + nameTypeLen = (*buf++) << 8; + nameTypeLen |= (*buf++); + + if (nameLen < nameTypeLen) + return (GSS_S_DEFECTIVE_TOKEN); + + buf += nameTypeLen; + nameLen -= nameTypeLen; + + /* + * adjust for expected null terminator that should + * really not be there + */ + if (nameLen > 0 && *(buf + nameLen - 1) == '\0') + nameLen--; + } + + /* + * Can a name be null? Let the mech decide. + * + * NOTE: We use GSS_C_NULL_OID as the name type when importing + * the unwrapped name. Presumably the exported name had, + * prior to being exported been obtained in such a way + * that it has been properly perpared ("canonicalized," in + * GSS-API terms) accroding to some name type; we cannot + * tell what that name type was now, but the name should + * need no further preparation other than the lowest + * common denominator afforded by the mech to names + * imported with GSS_C_NULL_OID. For the Kerberos V mech + * this means doing less busywork too (particularly once + * IDN is thrown in with Kerberos V extensions). + */ + expName.length = nameLen; + expName.value = nameLen ? (void *)buf : NULL; + major = mech->gss_import_name(mech->context, minor, &expName, + GSS_C_NULL_OID, &unionName->mech_name); + if (major != GSS_S_COMPLETE) + return (major); + + return (generic_gss_copy_oid(minor, &mechOid, &unionName->mech_type)); +} /* importExportName */ diff --git a/src/lib/gssapi/mechglue/g_imp_sec_context.c b/src/lib/gssapi/mechglue/g_imp_sec_context.c index eed9bbeda..533b0175c 100644 --- a/src/lib/gssapi/mechglue/g_imp_sec_context.c +++ b/src/lib/gssapi/mechglue/g_imp_sec_context.c @@ -1,4 +1,4 @@ -/* #ident "@(#)g_imp_sec_context.c 1.2 96/01/18 SMI" */ +/* #pragma ident "@(#)g_imp_sec_context.c 1.18 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -44,48 +44,59 @@ gss_buffer_t interprocess_token; gss_ctx_id_t * context_handle; { - size_t length; + OM_uint32 length = 0; OM_uint32 status; char *p; gss_union_ctx_id_t ctx; gss_buffer_desc token; gss_mechanism mech; - gss_initialize(); - + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); *minor_status = 0; - if (interprocess_token->length == 0 || interprocess_token->value == 0) - return (GSS_S_DEFECTIVE_TOKEN); + if (context_handle == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CONTEXT); + *context_handle = GSS_C_NO_CONTEXT; + + if (GSS_EMPTY_BUFFER(interprocess_token)) + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_DEFECTIVE_TOKEN); status = GSS_S_FAILURE; ctx = (gss_union_ctx_id_t) malloc(sizeof(gss_union_ctx_id_desc)); - if (!ctx) { - *minor_status = ENOMEM; - goto error_out; - } + if (!ctx) + return (GSS_S_FAILURE); + ctx->mech_type = (gss_OID) malloc(sizeof(gss_OID_desc)); if (!ctx->mech_type) { - *minor_status = ENOMEM; - goto error_out; + free(ctx); + return (GSS_S_FAILURE); + } + + if (interprocess_token->length >= sizeof (OM_uint32)) { + p = interprocess_token->value; + length = (OM_uint32)*p++; + length = (OM_uint32)(length << 8) + *p++; + length = (OM_uint32)(length << 8) + *p++; + length = (OM_uint32)(length << 8) + *p++; + } + + if (length == 0 || + length > (interprocess_token->length - sizeof (OM_uint32))) { + free(ctx); + return (GSS_S_CALL_BAD_STRUCTURE | GSS_S_DEFECTIVE_TOKEN); } - p = interprocess_token->value; - length = *p++; - length = (length << 8) + *p++; - length = (length << 8) + *p++; - length = (length << 8) + *p++; ctx->mech_type->length = length; ctx->mech_type->elements = malloc(length); if (!ctx->mech_type->elements) { - *minor_status = ENOMEM; goto error_out; } memcpy(ctx->mech_type->elements, p, length); p += length; - token.length = interprocess_token->length - 4 - length; + token.length = interprocess_token->length - sizeof (OM_uint32) - length; token.value = p; /* @@ -93,13 +104,13 @@ gss_ctx_id_t * context_handle; * call it. */ - mech = __gss_get_mechanism (ctx->mech_type); + mech = gssint_get_mechanism (ctx->mech_type); if (!mech) { status = GSS_S_BAD_MECH; goto error_out; } if (!mech->gss_import_sec_context) { - status = GSS_S_BAD_BINDINGS; + status = GSS_S_UNAVAILABLE; goto error_out; } diff --git a/src/lib/gssapi/mechglue/g_indicate_mechs.c b/src/lib/gssapi/mechglue/g_indicate_mechs.c index 334f7c1b9..e2c8d414f 100644 --- a/src/lib/gssapi/mechglue/g_indicate_mechs.c +++ b/src/lib/gssapi/mechglue/g_indicate_mechs.c @@ -33,7 +33,7 @@ #endif #include -extern gss_mechanism *__gss_mechs_array; +extern gss_mechanism *gssint_mechs_array; static gss_OID_set_desc supported_mechs_desc; static gss_OID_set supported_mechs = NULL; @@ -65,7 +65,7 @@ gss_OID_set * mech_set; /* Build the mech_set from the OIDs in mechs_array. */ - for(i=0; __gss_mechs_array[i]->mech_type.length != 0; i++) + for(i=0; gssint_mechs_array[i]->mech_type.length != 0; i++) supported_mechs->count++; supported_mechs->elements = @@ -74,12 +74,12 @@ gss_OID_set * mech_set; for(i=0; i < supported_mechs->count; i++) { supported_mechs->elements[i].length = - __gss_mechs_array[i]->mech_type.length; + gssint_mechs_array[i]->mech_type.length; supported_mechs->elements[i].elements = (void *) - malloc(__gss_mechs_array[i]->mech_type.length); + malloc(gssint_mechs_array[i]->mech_type.length); memcpy(supported_mechs->elements[i].elements, - __gss_mechs_array[i]->mech_type.elements, - __gss_mechs_array[i]->mech_type.length); + gssint_mechs_array[i]->mech_type.elements, + gssint_mechs_array[i]->mech_type.length); } } diff --git a/src/lib/gssapi/mechglue/g_init_sec_context.c b/src/lib/gssapi/mechglue/g_init_sec_context.c index 8f55ac5f4..53252f798 100644 --- a/src/lib/gssapi/mechglue/g_init_sec_context.c +++ b/src/lib/gssapi/mechglue/g_init_sec_context.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_init_sec_context.c 1.20 95/08/07 SMI" */ +/* #pragma ident "@(#)g_init_sec_context.c 1.20 03/10/24 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -33,10 +33,6 @@ #endif #include -#define g_OID_equal(o1,o2) \ - (((o1)->length == (o2)->length) && \ - (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0)) - OM_uint32 KRB5_CALLCONV gss_init_sec_context (minor_status, claimant_cred_handle, @@ -67,7 +63,7 @@ OM_uint32 * ret_flags; OM_uint32 * time_rec; { - OM_uint32 status, temp_status, temp_minor_status; + OM_uint32 status, temp_minor_status; gss_union_name_t union_name; gss_union_cred_t union_cred; gss_name_t internal_name; @@ -76,32 +72,48 @@ OM_uint32 * time_rec; gss_mechanism mech; gss_cred_id_t input_cred_handle; - gss_initialize(); + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; output_token->length = 0; output_token->value = NULL; + /* clear output values */ + if (actual_mech_type) + *actual_mech_type = NULL; + if (context_handle == NULL) - return GSS_S_NO_CONTEXT; + return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CONTEXT); union_name = (gss_union_name_t) target_name; - /* - * If mech_type is NULL, and the target_name is - * mechanism-specific, then set it to the mech_type of - * target_name. - */ - if ((mech_type == GSS_C_NULL_OID) && union_name->mech_type) - mech_type = union_name->mech_type; + if (target_name == NULL) + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME); + + if (output_token == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + output_token->value = NULL; + output_token->length = 0; + + + if (req_mech_type) + mech_type = (gss_OID)req_mech_type; + + union_name = (gss_union_name_t)target_name; /* * obtain the gss mechanism information for the requested * mechanism. If mech_type is NULL, set it to the resultant * mechanism */ - mech = __gss_get_mechanism (mech_type); + mech = gssint_get_mechanism (mech_type); if (mech == NULL) return (GSS_S_BAD_MECH); + if (mech->gss_init_sec_context == NULL) + return (GSS_S_UNAVAILABLE); + if (mech_type == GSS_C_NULL_OID) mech_type = &mech->mech_type; @@ -110,15 +122,14 @@ OM_uint32 * time_rec; * mech_type that we're about to use. Otherwise, do an import on * the external_name form of the target name. */ - if (union_name->mech_type) { - if (!g_OID_equal(union_name->mech_type, mech_type)) - return (GSS_S_BAD_MECH); + if (union_name->mech_type && + g_OID_equal(union_name->mech_type, mech_type)) { internal_name = union_name->mech_name; } else { - if ((temp_status = __gss_import_internal_name(minor_status, mech_type, - union_name, - &internal_name))) - return (GSS_S_BAD_NAME); + if ((status = gssint_import_internal_name(minor_status, mech_type, + union_name, + &internal_name)) != GSS_S_COMPLETE) + return (status); } /* @@ -129,23 +140,22 @@ OM_uint32 * time_rec; */ if(*context_handle == GSS_C_NO_CONTEXT) { + status = GSS_S_FAILURE; union_ctx_id = (gss_union_ctx_id_t) malloc(sizeof(gss_union_ctx_id_desc)); + if (union_ctx_id == NULL) + goto end; union_ctx_id->mech_type = (gss_OID) malloc(sizeof(gss_OID_desc)); - /* copy in the mech type information */ - - union_ctx_id->mech_type->elements = (void *) - malloc(mech_type->length); - - union_ctx_id->mech_type->length = mech_type->length; - memcpy(union_ctx_id->mech_type->elements, mech_type->elements, - mech_type->length); + if (generic_gss_copy_oid(&temp_minor_status, mech_type, + &union_ctx_id->mech_type) != GSS_S_COMPLETE) { + free(union_ctx_id); + goto end; + } /* copy the supplied context handle */ - union_ctx_id->internal_ctx_id = *context_handle; } else union_ctx_id = *context_handle; @@ -156,37 +166,47 @@ OM_uint32 * time_rec; * use the default credential. */ union_cred = (gss_union_cred_t) claimant_cred_handle; - input_cred_handle = __gss_get_mechanism_cred(union_cred, mech_type); + input_cred_handle = gssint_get_mechanism_cred(union_cred, mech_type); /* * now call the approprate underlying mechanism routine */ - if (mech->gss_init_sec_context) { - status = mech->gss_init_sec_context( - mech->context, - minor_status, - input_cred_handle, - &union_ctx_id->internal_ctx_id, - internal_name, - mech_type, - req_flags, - time_req, - input_chan_bindings, - input_token, - actual_mech_type, - output_token, - ret_flags, - time_rec); - - if (*context_handle == GSS_C_NO_CONTEXT) - *context_handle = (gss_ctx_id_t) union_ctx_id; - - } else - status = GSS_S_BAD_BINDINGS; - - if (!union_name->mech_type) { - (void) __gss_release_internal_name(&temp_minor_status, + status = mech->gss_init_sec_context( + mech->context, + minor_status, + input_cred_handle, + &union_ctx_id->internal_ctx_id, + internal_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + + if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) { + /* + * the spec says (the preferred) method is to delete all + * context info on the first call to init, and on all + * subsequent calls make the caller responsible for + * calling gss_delete_sec_context + */ + if (*context_handle == GSS_C_NO_CONTEXT) { + free(union_ctx_id->mech_type->elements); + free(union_ctx_id->mech_type); + free(union_ctx_id); + } + } else if (*context_handle == GSS_C_NO_CONTEXT) + *context_handle = (gss_ctx_id_t)union_ctx_id; + +end: + if (union_name->mech_name == NULL || + union_name->mech_name != internal_name) { + (void) gssint_release_internal_name(&temp_minor_status, mech_type, &internal_name); } diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c index 09e14deed..216775627 100644 --- a/src/lib/gssapi/mechglue/g_initialize.c +++ b/src/lib/gssapi/mechglue/g_initialize.c @@ -1,4 +1,4 @@ -/* #ident "@(#)g_initialize.c 1.2 96/02/06 SMI" */ +/* #pragma ident "@(#)g_initialize.c 1.36 05/02/02 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -36,201 +36,950 @@ #include #include -#ifdef USE_SOLARIS_SHARED_LIBRARIES #include -#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 + +#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, "", NULL); + } + cflist = spnego_gss_get_mech_configs(); + if (cflist == NULL) + return; + for ( ; *cflist != NULL; cflist++) { + register_mech(*cflist, "", 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 */ diff --git a/src/lib/gssapi/mechglue/g_inq_context.c b/src/lib/gssapi/mechglue/g_inq_context.c index 3f28c484f..e717aa347 100644 --- a/src/lib/gssapi/mechglue/g_inq_context.c +++ b/src/lib/gssapi/mechglue/g_inq_context.c @@ -1,4 +1,4 @@ -/* #ident "@(#)g_inquire_context.c 1.2 96/01/18 SMI" */ +/* #pragma ident "@(#)g_inquire_context.c 1.15 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -59,13 +59,26 @@ int * open; gss_union_ctx_id_t ctx; gss_mechanism mech; OM_uint32 status, temp_minor; + gss_name_t localTargName = NULL, localSourceName = NULL; - gss_initialize(); + if (!minor_status) + return (GSS_S_CALL_INACCESSIBLE_WRITE); - /* if the context_handle is Null, return NO_CONTEXT error */ + *minor_status = 0; - if(context_handle == GSS_C_NO_CONTEXT) - return(GSS_S_NO_CONTEXT); + /* if the context_handle is Null, return NO_CONTEXT error */ + if (context_handle == GSS_C_NO_CONTEXT) + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT); + + /* set all output value to NULL */ + if (src_name) + *src_name = NULL; + + if (targ_name) + *targ_name = NULL; + + if (mech_type) + *mech_type = NULL; /* * select the approprate underlying mechanism routine and @@ -73,21 +86,21 @@ int * open; */ ctx = (gss_union_ctx_id_t) context_handle; - mech = __gss_get_mechanism (ctx->mech_type); + mech = gssint_get_mechanism (ctx->mech_type); - if (!mech || !mech->gss_inquire_context || !mech->gss_display_name) { - return(GSS_S_NO_CONTEXT); - + if (!mech || !mech->gss_inquire_context || !mech->gss_display_name || + !mech->gss_release_name) { + return (GSS_S_UNAVAILABLE); } status = mech->gss_inquire_context( mech->context, minor_status, ctx->internal_ctx_id, - src_name, - targ_name, + (src_name ? &localSourceName : NULL), + (targ_name ? &localTargName : NULL), lifetime_rec, - mech_type, + NULL, ctx_flags, locally_initiated, open); @@ -99,34 +112,33 @@ int * open; /* need to convert names */ if (src_name) { - status = __gss_convert_name_to_union_name(minor_status, mech, - *src_name, src_name); + status = gssint_convert_name_to_union_name(minor_status, mech, + localSourceName, src_name); if (status != GSS_S_COMPLETE) { - (void) mech->gss_release_name(mech->context, - &temp_minor, src_name); - (void) mech->gss_release_name(mech->context, - &temp_minor, targ_name); - if (mech_type) { - gss_release_oid(&temp_minor, mech_type); - } - return (GSS_S_FAILURE); + if (localTargName) + mech->gss_release_name(mech->context, + &temp_minor, &localTargName); + return (status); } } if (targ_name) { - status = __gss_convert_name_to_union_name(minor_status, mech, - *targ_name, targ_name); + status = gssint_convert_name_to_union_name(minor_status, mech, + localTargName, targ_name); if (status != GSS_S_COMPLETE) { - if (mech_type) { - gss_release_oid(&temp_minor, mech_type); - } - return (GSS_S_FAILURE); + if (src_name) + (void) gss_release_name(&temp_minor, src_name); + + return (status); } } + /* spec says mech type must point to static storage */ + if (mech_type) + *mech_type = &mech->mech_type; return(GSS_S_COMPLETE); } diff --git a/src/lib/gssapi/mechglue/g_inq_cred.c b/src/lib/gssapi/mechglue/g_inq_cred.c index e0a2bc4a8..c4b59114d 100644 --- a/src/lib/gssapi/mechglue/g_inq_cred.c +++ b/src/lib/gssapi/mechglue/g_inq_cred.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_inquire_cred.c 1.9 95/08/02 SMI" */ +/* #pragma ident "@(#)g_inquire_cred.c 1.16 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -56,7 +56,16 @@ gss_OID_set * mechanisms; gss_name_t internal_name; int i; - gss_initialize(); + /* check parms and set to defaults */ + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; + + if (name) + *name = NULL; + + if (mechanisms) + *mechanisms = NULL; if (cred_handle == GSS_C_NO_CREDENTIAL) { /* @@ -67,11 +76,11 @@ gss_OID_set * mechanisms; * array, which becomes the default mechanism. */ - if ((mech = __gss_get_mechanism(GSS_C_NULL_OID)) == NULL) - return(GSS_S_NO_CRED); + if ((mech = gssint_get_mechanism(GSS_C_NULL_OID)) == NULL) + return (GSS_S_DEFECTIVE_CREDENTIAL); if (!mech->gss_inquire_cred) - return (GSS_S_FAILURE); + return (GSS_S_UNAVAILABLE); status = mech->gss_inquire_cred(mech->context, minor_status, GSS_C_NO_CREDENTIAL, @@ -85,14 +94,16 @@ gss_OID_set * mechanisms; /* * Convert internal_name into a union_name equivalent. */ - status = __gss_convert_name_to_union_name(&temp_minor_status, + status = gssint_convert_name_to_union_name(&temp_minor_status, mech, internal_name, name); if (status != GSS_S_COMPLETE) { - if (minor_status) - *minor_status = temp_minor_status; - __gss_release_internal_name(&temp_minor_status, - &mech->mech_type, &internal_name); + *minor_status = temp_minor_status; + if (mechanisms && *mechanisms) { + (void) gss_release_oid_set( + &temp_minor_status, + mechanisms); + } return (status); } } @@ -124,39 +135,68 @@ gss_OID_set * mechanisms; * caller. If this call fails, return failure to our caller. */ - if(name != NULL) - if(gss_import_name(&temp_minor_status, - &union_cred->auxinfo.name, - union_cred->auxinfo.name_type, - name) != GSS_S_COMPLETE) - return(GSS_S_DEFECTIVE_CREDENTIAL); - + if(name != NULL) { + if ((gss_import_name(&temp_minor_status, + &union_cred->auxinfo.name, + union_cred->auxinfo.name_type, + name) != GSS_S_COMPLETE) || + (gss_canonicalize_name(minor_status, *name, + &union_cred->mechs_array[0], + NULL) != GSS_S_COMPLETE)) { + status = GSS_S_DEFECTIVE_CREDENTIAL; + goto error; + } + } + /* * copy the mechanism set in union_cred into an OID set and return in * the mechanisms parameter. */ if(mechanisms != NULL) { - + status = GSS_S_FAILURE; *mechanisms = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)); + if (*mechanisms == NULL) + goto error; - (*mechanisms)->count = union_cred->count; + (*mechanisms)->count = 0; (*mechanisms)->elements = (gss_OID) malloc(sizeof(gss_OID_desc) * union_cred->count); + if ((*mechanisms)->elements == NULL) { + free(*mechanisms); + *mechanisms = NULL; + goto error; + } + for(i=0; i < union_cred->count; i++) { - (*mechanisms)->elements[i].length = - union_cred->mechs_array[i].length; (*mechanisms)->elements[i].elements = (void *) malloc(union_cred->mechs_array[i].length); - memcpy((*mechanisms)->elements[i].elements, - union_cred->mechs_array[i].elements, - union_cred->mechs_array[i].length); + if ((*mechanisms)->elements[i].elements == NULL) + goto error; + g_OID_copy(&(*mechanisms)->elements[i], + &union_cred->mechs_array[i]); + (*mechanisms)->count++; } } return(GSS_S_COMPLETE); + +error: + /* + * cleanup any allocated memory - we can just call + * gss_release_oid_set, because the set is constructed so that + * count always references the currently copied number of + * elements. + */ + if (mechanisms && *mechanisms != NULL) + (void) gss_release_oid_set(&temp_minor_status, mechanisms); + + if (name && *name != NULL) + (void) gss_release_name(&temp_minor_status, name); + + return (status); } OM_uint32 KRB5_CALLCONV @@ -173,19 +213,46 @@ gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name, gss_union_cred_t union_cred; gss_cred_id_t mech_cred; gss_mechanism mech; + OM_uint32 status, temp_minor_status; + gss_name_t internal_name; + - mech = __gss_get_mechanism (mech_type); + mech = gssint_get_mechanism (mech_type); if (!mech) return (GSS_S_BAD_MECH); if (!mech->gss_inquire_cred_by_mech) return (GSS_S_BAD_BINDINGS); union_cred = (gss_union_cred_t) cred_handle; - mech_cred = __gss_get_mechanism_cred(union_cred, mech_type); + mech_cred = gssint_get_mechanism_cred(union_cred, mech_type); + +#if 0 + if (mech_cred == NULL) + return (GSS_S_DEFECTIVE_CREDENTIAL); +#endif + + status = mech->gss_inquire_cred_by_mech(mech->context, minor_status, + mech_cred, mech_type, + name ? &internal_name : NULL, + initiator_lifetime, + acceptor_lifetime, cred_usage); + + if (status != GSS_S_COMPLETE) + return (status); + + if (name) { + /* + * Convert internal_name into a union_name equivalent. + */ + status = gssint_convert_name_to_union_name( + &temp_minor_status, mech, + internal_name, name); + if (status != GSS_S_COMPLETE) { + *minor_status = temp_minor_status; + return (status); + } + } - return (mech->gss_inquire_cred_by_mech(mech->context, minor_status, - mech_cred, mech_type, - name, initiator_lifetime, - acceptor_lifetime, cred_usage)); + return (GSS_S_COMPLETE); } diff --git a/src/lib/gssapi/mechglue/g_inq_names.c b/src/lib/gssapi/mechglue/g_inq_names.c index 7c07f44ed..4332e3e0c 100644 --- a/src/lib/gssapi/mechglue/g_inq_names.c +++ b/src/lib/gssapi/mechglue/g_inq_names.c @@ -1,4 +1,4 @@ -/* #ident "@(#)g_inquire_names.c 1.1 95/12/19 SMI" */ +/* #pragma ident "@(#)g_inquire_names.c 1.16 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -28,6 +28,8 @@ #include "mglueP.h" +#define MAX_MECH_OID_PAIRS 32 + /* Last argument new for V2 */ OM_uint32 KRB5_CALLCONV gss_inquire_names_for_mech(minor_status, mechanism, name_types) @@ -40,14 +42,19 @@ gss_OID_set * name_types; OM_uint32 status; gss_mechanism mech; - gss_initialize(); - + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; + + if (name_types == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + /* * select the approprate underlying mechanism routine and * call it. */ - mech = __gss_get_mechanism (mechanism); + mech = gssint_get_mechanism (mechanism); if (mech) { @@ -58,10 +65,93 @@ gss_OID_set * name_types; mechanism, name_types); else - status = GSS_S_BAD_BINDINGS; + status = GSS_S_UNAVAILABLE; return(status); } - return(GSS_S_NO_CONTEXT); + return (GSS_S_BAD_MECH); +} +OM_uint32 KRB5_CALLCONV +gss_inquire_mechs_for_name(minor_status, input_name, mech_set) + + OM_uint32 * minor_status; + const gss_name_t input_name; + gss_OID_set * mech_set; + +{ + OM_uint32 status; + static char *mech_list[MAX_MECH_OID_PAIRS+1]; + gss_OID_set mech_name_types; + int present; + char *mechanism; + gss_OID mechOid; + gss_OID name_type; + gss_buffer_desc name_buffer; + int i; + + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; + + if (input_name == NULL) + return (GSS_S_BAD_NAME); + + status = gss_create_empty_oid_set(minor_status, mech_set); + if (status != GSS_S_COMPLETE) + return (status); + *mech_list = NULL; + status = gssint_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1); + if (status != GSS_S_COMPLETE) + return (status); + for (i = 0; i < MAX_MECH_OID_PAIRS && mech_list[i] != NULL; i++) { + mechanism = mech_list[i]; + if (gssint_mech_to_oid(mechanism, &mechOid) == GSS_S_COMPLETE) { + status = gss_inquire_names_for_mech( + minor_status, + mechOid, + &mech_name_types); + if (status == GSS_S_COMPLETE) { + status = gss_display_name(minor_status, + input_name, + &name_buffer, + &name_type); + + (void) gss_release_buffer(NULL, &name_buffer); + + if (status == GSS_S_COMPLETE && name_type) { + status = gss_test_oid_set_member( + minor_status, + name_type, + mech_name_types, + &present); + if (status == GSS_S_COMPLETE && + present) { + status = gss_add_oid_set_member( + minor_status, + mechOid, + mech_set); + if (status != GSS_S_COMPLETE) { + (void) gss_release_oid_set( + minor_status, + &mech_name_types); + (void) gss_release_oid_set( + minor_status, + mech_set); + return (status); + } + } + } + (void) gss_release_oid_set( + minor_status, + &mech_name_types); + } + } else { + (void) gss_release_oid_set( + minor_status, + mech_set); + return (GSS_S_FAILURE); + } + } + return (GSS_S_COMPLETE); } diff --git a/src/lib/gssapi/mechglue/g_mechname.c b/src/lib/gssapi/mechglue/g_mechname.c index c013bdc15..0607c38f1 100644 --- a/src/lib/gssapi/mechglue/g_mechname.c +++ b/src/lib/gssapi/mechglue/g_mechname.c @@ -15,10 +15,6 @@ #include #include -#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; /* diff --git a/src/lib/gssapi/mechglue/g_oid_ops.c b/src/lib/gssapi/mechglue/g_oid_ops.c index 4a9d765f2..86e57972d 100644 --- a/src/lib/gssapi/mechglue/g_oid_ops.c +++ b/src/lib/gssapi/mechglue/g_oid_ops.c @@ -1,3 +1,4 @@ +/* #pragma ident "@(#)g_oid_ops.c 1.11 98/01/22 SMI" */ /* * lib/gssapi/mechglue/g_oid_ops.c * @@ -32,36 +33,13 @@ #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) diff --git a/src/lib/gssapi/mechglue/g_process_context.c b/src/lib/gssapi/mechglue/g_process_context.c index dcb4716bc..beb65a141 100644 --- a/src/lib/gssapi/mechglue/g_process_context.c +++ b/src/lib/gssapi/mechglue/g_process_context.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_process_context.c 1.9 95/08/07 SMI" */ +/* #pragma ident "@(#)g_process_context.c 1.12 98/01/22 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -42,10 +42,15 @@ gss_buffer_t token_buffer; gss_union_ctx_id_t ctx; gss_mechanism mech; - gss_initialize(); + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; if (context_handle == GSS_C_NO_CONTEXT) - return GSS_S_NO_CONTEXT; + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT); + + if (GSS_EMPTY_BUFFER(token_buffer)) + return (GSS_S_CALL_INACCESSIBLE_READ); /* * select the approprate underlying mechanism routine and @@ -53,7 +58,7 @@ gss_buffer_t token_buffer; */ ctx = (gss_union_ctx_id_t) context_handle; - mech = __gss_get_mechanism (ctx->mech_type); + mech = gssint_get_mechanism (ctx->mech_type); if (mech) { @@ -64,10 +69,10 @@ gss_buffer_t token_buffer; ctx->internal_ctx_id, token_buffer); else - status = GSS_S_BAD_BINDINGS; + status = GSS_S_UNAVAILABLE; return(status); } - return(GSS_S_NO_CONTEXT); + return (GSS_S_BAD_MECH); } diff --git a/src/lib/gssapi/mechglue/g_rel_cred.c b/src/lib/gssapi/mechglue/g_rel_cred.c index 44d82709e..ffcce2d7e 100644 --- a/src/lib/gssapi/mechglue/g_rel_cred.c +++ b/src/lib/gssapi/mechglue/g_rel_cred.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_release_cred.c 1.15 95/08/07 SMI" */ +/* #pragma ident "@(#)g_rel_cred.c 1.14 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -45,15 +45,13 @@ gss_cred_id_t * cred_handle; gss_union_cred_t union_cred; gss_mechanism mech; - gss_initialize(); + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); - if (minor_status) - *minor_status = 0; + *minor_status = 0; - /* if the cred_handle is null, return a NO_CRED error */ - - if (cred_handle == GSS_C_NO_CREDENTIAL) - return(GSS_S_NO_CRED); + if (cred_handle == NULL) + return (GSS_S_NO_CRED | GSS_S_CALL_INACCESSIBLE_READ); /* * Loop through the union_cred struct, selecting the approprate @@ -64,14 +62,14 @@ gss_cred_id_t * cred_handle; union_cred = (gss_union_cred_t) *cred_handle; *cred_handle = NULL; - if (union_cred == NULL) - return GSS_S_NO_CRED; + if (union_cred == (gss_union_cred_t)GSS_C_NO_CREDENTIAL) + return (GSS_S_COMPLETE); status = GSS_S_COMPLETE; for(j=0; j < union_cred->count; j++) { - mech = __gss_get_mechanism (&union_cred->mechs_array[j]); + mech = gssint_get_mechanism (&union_cred->mechs_array[j]); if (union_cred->mechs_array[j].elements) free(union_cred->mechs_array[j].elements); @@ -86,9 +84,9 @@ gss_cred_id_t * cred_handle; status = GSS_S_NO_CRED; } else - status = GSS_S_NO_CRED; + status = GSS_S_UNAVAILABLE; } else - status = GSS_S_NO_CRED; + status = GSS_S_DEFECTIVE_CREDENTIAL; } gss_release_buffer(minor_status, &union_cred->auxinfo.name); diff --git a/src/lib/gssapi/mechglue/g_rel_name.c b/src/lib/gssapi/mechglue/g_rel_name.c index 29c3f9819..ff3c4a10a 100644 --- a/src/lib/gssapi/mechglue/g_rel_name.c +++ b/src/lib/gssapi/mechglue/g_rel_name.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_release_name.c 1.2 95/05/09 SMI" */ +/* #pragma ident "@(#)g_rel_name.c 1.11 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -43,11 +43,17 @@ gss_name_t * input_name; { gss_union_name_t union_name; - /* if input_name is NULL, return error */ + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; + /* if input_name is NULL, return error */ if (input_name == 0) - return(GSS_S_BAD_NAME); - + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME); + + if (*input_name == GSS_C_NO_NAME) + return GSS_S_COMPLETE; + /* * free up the space for the external_name and then * free the union_name descriptor @@ -56,9 +62,6 @@ gss_name_t * input_name; union_name = (gss_union_name_t) *input_name; *input_name = 0; *minor_status = 0; - - if (union_name == NULL) - return GSS_S_BAD_NAME; if (union_name->name_type) gss_release_oid(minor_status, &union_name->name_type); @@ -67,7 +70,7 @@ gss_name_t * input_name; free(union_name->external_name); if (union_name->mech_type) { - __gss_release_internal_name(minor_status, union_name->mech_type, + gssint_release_internal_name(minor_status, union_name->mech_type, &union_name->mech_name); gss_release_oid(minor_status, &union_name->mech_type); } diff --git a/src/lib/gssapi/mechglue/g_rel_oid_set.c b/src/lib/gssapi/mechglue/g_rel_oid_set.c index 357c00e67..f712a891a 100644 --- a/src/lib/gssapi/mechglue/g_rel_oid_set.c +++ b/src/lib/gssapi/mechglue/g_rel_oid_set.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_release_oid_set.c 1.12 95/08/23 SMI" */ +/* #pragma ident "@(#)g_rel_oid_set.c 1.12 97/11/11 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -39,8 +39,8 @@ gss_release_oid_set (minor_status, OM_uint32 * minor_status; gss_OID_set * set; { - size_t index; - gss_OID oid; + OM_uint32 index; + gss_OID oid; if (minor_status) *minor_status = 0; diff --git a/src/lib/gssapi/mechglue/g_seal.c b/src/lib/gssapi/mechglue/g_seal.c index 7d66e469a..2b31c370f 100644 --- a/src/lib/gssapi/mechglue/g_seal.c +++ b/src/lib/gssapi/mechglue/g_seal.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_seal.c 1.10 95/08/07 SMI" */ +/* #pragma ident "@(#)g_seal.c 1.19 98/04/21 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -44,16 +44,25 @@ int qop_req; gss_buffer_t input_message_buffer; int * conf_state; gss_buffer_t output_message_buffer; - { + /* EXPORT DELETE START */ + OM_uint32 status; gss_union_ctx_id_t ctx; gss_mechanism mech; - gss_initialize(); - + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; + if (context_handle == GSS_C_NO_CONTEXT) - return GSS_S_NO_CONTEXT; + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT); + + if (input_message_buffer == NULL) + return (GSS_S_CALL_INACCESSIBLE_READ); + + if (output_message_buffer == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); /* * select the approprate underlying mechanism routine and @@ -61,7 +70,7 @@ gss_buffer_t output_message_buffer; */ ctx = (gss_union_ctx_id_t) context_handle; - mech = __gss_get_mechanism (ctx->mech_type); + mech = gssint_get_mechanism (ctx->mech_type); if (mech) { if (mech->gss_seal) @@ -75,12 +84,13 @@ gss_buffer_t output_message_buffer; conf_state, output_message_buffer); else - status = GSS_S_BAD_BINDINGS; + status = GSS_S_UNAVAILABLE; return(status); } - - return(GSS_S_NO_CONTEXT); + /* EXPORT DELETE END */ + + return (GSS_S_BAD_MECH); } OM_uint32 KRB5_CALLCONV @@ -101,9 +111,10 @@ int * conf_state; gss_buffer_t output_message_buffer; { - return gss_seal(minor_status, context_handle, conf_req_flag, - (int) qop_req, input_message_buffer, conf_state, - output_message_buffer); + return gss_seal(minor_status, (gss_ctx_id_t)context_handle, + conf_req_flag, (int) qop_req, + (gss_buffer_t)input_message_buffer, conf_state, + output_message_buffer); } /* @@ -119,14 +130,18 @@ gss_wrap_size_limit(minor_status, context_handle, conf_req_flag, OM_uint32 req_output_size; OM_uint32 *max_input_size; { - OM_uint32 status; gss_union_ctx_id_t ctx; gss_mechanism mech; - gss_initialize(); + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; if (context_handle == GSS_C_NO_CONTEXT) - return GSS_S_NO_CONTEXT; + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT); + + if (max_input_size == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); /* * select the approprate underlying mechanism routine and @@ -134,16 +149,15 @@ gss_wrap_size_limit(minor_status, context_handle, conf_req_flag, */ ctx = (gss_union_ctx_id_t) context_handle; - mech = __gss_get_mechanism (ctx->mech_type); + mech = gssint_get_mechanism (ctx->mech_type); if (!mech) - return (GSS_S_NO_CONTEXT); + return (GSS_S_BAD_MECH); if (!mech->gss_wrap_size_limit) - return (GSS_S_BAD_BINDINGS); + return (GSS_S_UNAVAILABLE); - status = mech->gss_wrap_size_limit(mech->context, minor_status, - context_handle, conf_req_flag, qop_req, - req_output_size, max_input_size); - return(status); + return (mech->gss_wrap_size_limit(mech->context, minor_status, + ctx->internal_ctx_id, conf_req_flag, qop_req, + req_output_size, max_input_size)); } diff --git a/src/lib/gssapi/mechglue/g_sign.c b/src/lib/gssapi/mechglue/g_sign.c index 4dfd3ec71..72e0ce742 100644 --- a/src/lib/gssapi/mechglue/g_sign.c +++ b/src/lib/gssapi/mechglue/g_sign.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_sign.c 1.10 95/08/07 SMI" */ +/* #pragma ident "@(#)g_sign.c 1.14 98/04/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -46,18 +46,28 @@ gss_buffer_t msg_token; gss_union_ctx_id_t ctx; gss_mechanism mech; - gss_initialize(); + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; if (context_handle == GSS_C_NO_CONTEXT) - return GSS_S_NO_CONTEXT; + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT); + if (message_buffer == NULL) + return (GSS_S_CALL_INACCESSIBLE_READ); + + if (msg_token == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + msg_token->value = NULL; + msg_token->length = 0; /* * select the approprate underlying mechanism routine and * call it. */ ctx = (gss_union_ctx_id_t) context_handle; - mech = __gss_get_mechanism (ctx->mech_type); + mech = gssint_get_mechanism (ctx->mech_type); if (mech) { if (mech->gss_sign) @@ -69,12 +79,12 @@ gss_buffer_t msg_token; message_buffer, msg_token); else - status = GSS_S_BAD_BINDINGS; + status = GSS_S_UNAVAILABLE; return(status); } - return(GSS_S_NO_CONTEXT); + return (GSS_S_BAD_MECH); } OM_uint32 KRB5_CALLCONV diff --git a/src/lib/gssapi/mechglue/g_store_cred.c b/src/lib/gssapi/mechglue/g_store_cred.c new file mode 100644 index 000000000..92581be85 --- /dev/null +++ b/src/lib/gssapi/mechglue/g_store_cred.c @@ -0,0 +1,136 @@ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* #pragma ident "@(#)g_store_cred.c 1.2 04/04/05 SMI" */ + +/* + * glue routine for gss_store_cred + */ + +#include + +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); +} diff --git a/src/lib/gssapi/mechglue/g_unseal.c b/src/lib/gssapi/mechglue/g_unseal.c index 9ca1c1512..c70c59beb 100644 --- a/src/lib/gssapi/mechglue/g_unseal.c +++ b/src/lib/gssapi/mechglue/g_unseal.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_unseal.c 1.10 95/08/07 SMI" */ +/* #pragma ident "@(#)g_unseal.c 1.13 98/01/22 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -44,14 +44,26 @@ int * conf_state; int * qop_state; { +/* EXPORT DELETE START */ OM_uint32 status; gss_union_ctx_id_t ctx; gss_mechanism mech; - gss_initialize(); + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; if (context_handle == GSS_C_NO_CONTEXT) - return GSS_S_NO_CONTEXT; + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT); + + if (GSS_EMPTY_BUFFER(input_message_buffer)) + return (GSS_S_CALL_INACCESSIBLE_READ); + + if (output_message_buffer == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + output_message_buffer->length = 0; + output_message_buffer->value = NULL; /* * select the approprate underlying mechanism routine and @@ -59,7 +71,7 @@ int * qop_state; */ ctx = (gss_union_ctx_id_t) context_handle; - mech = __gss_get_mechanism (ctx->mech_type); + mech = gssint_get_mechanism (ctx->mech_type); if (mech) { if (mech->gss_unseal) @@ -72,12 +84,14 @@ int * qop_state; conf_state, qop_state); else - status = GSS_S_BAD_BINDINGS; + status = GSS_S_UNAVAILABLE; return(status); } - return(GSS_S_NO_CONTEXT); +/* EXPORT DELETE END */ + + return (GSS_S_BAD_MECH); } OM_uint32 KRB5_CALLCONV @@ -89,15 +103,14 @@ gss_unwrap (minor_status, qop_state) OM_uint32 * minor_status; -gss_ctx_id_t context_handle; -gss_buffer_t input_message_buffer; +const gss_ctx_id_t context_handle; +const gss_buffer_t input_message_buffer; gss_buffer_t output_message_buffer; int * conf_state; gss_qop_t * qop_state; { - return (gss_unseal(minor_status, context_handle, - input_message_buffer, - output_message_buffer, - conf_state, (int *) qop_state)); + return (gss_unseal(minor_status, (gss_ctx_id_t)context_handle, + (gss_buffer_t)input_message_buffer, + output_message_buffer, conf_state, (int *) qop_state)); } diff --git a/src/lib/gssapi/mechglue/g_userok.c b/src/lib/gssapi/mechglue/g_userok.c new file mode 100644 index 000000000..4657b8eb1 --- /dev/null +++ b/src/lib/gssapi/mechglue/g_userok.c @@ -0,0 +1,110 @@ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* #pragma ident "@(#)g_userok.c 1.1 04/03/25 SMI" */ + +#include +#include +#include +#include +#include + + +static OM_uint32 +compare_names(OM_uint32 *minor, + const gss_OID mech_type, + const gss_name_t name, + const char *user, + int *user_ok) +{ + + OM_uint32 status, tmpMinor; + gss_name_t imported_name; + gss_name_t canon_name; + gss_buffer_desc gss_user; + int match = 0; + + *user_ok = 0; + + gss_user.value = (void *)user; + if (!gss_user.value || !name || !mech_type) + return (GSS_S_BAD_NAME); + gss_user.length = strlen(gss_user.value); + + status = gss_import_name(minor, + &gss_user, + GSS_C_NT_USER_NAME, + &imported_name); + if (status != GSS_S_COMPLETE) { + goto out; + } + + status = gss_canonicalize_name(minor, + imported_name, + mech_type, + &canon_name); + if (status != GSS_S_COMPLETE) { + (void) gss_release_name(&tmpMinor, &imported_name); + goto out; + } + + status = gss_compare_name(minor, + canon_name, + name, + &match); + (void) gss_release_name(&tmpMinor, &canon_name); + (void) gss_release_name(&tmpMinor, &imported_name); + if (status == GSS_S_COMPLETE) { + if (match) + *user_ok = 1; /* remote user is a-ok */ + } + +out: + return (status); +} + + +OM_uint32 +gssint_userok(OM_uint32 *minor, + const gss_name_t name, + const char *user, + int *user_ok) + +{ + gss_mechanism mech; + gss_union_name_t intName; + gss_name_t mechName = NULL; + OM_uint32 major; + + if (minor == NULL || user_ok == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + if (name == NULL || user == NULL) + return (GSS_S_CALL_INACCESSIBLE_READ); + + *user_ok = 0; + *minor = GSS_S_COMPLETE; + + intName = (gss_union_name_t)name; + + mech = gssint_get_mechanism(intName->mech_type); + if (mech == NULL) + return (GSS_S_UNAVAILABLE); + + /* may need to import the name if this is not MN */ + if (intName->mech_type == NULL) { + return (GSS_S_FAILURE); + } else + mechName = intName->mech_name; + + if (mech->gssint_userok) + major = mech->gssint_userok(mech->context, minor, mechName, + user, user_ok); + else + major = compare_names(minor, intName->mech_type, + name, user, user_ok); + + return (major); +} /* gss_userok */ diff --git a/src/lib/gssapi/mechglue/g_utils.c b/src/lib/gssapi/mechglue/g_utils.c new file mode 100644 index 000000000..82fe70d95 --- /dev/null +++ b/src/lib/gssapi/mechglue/g_utils.c @@ -0,0 +1,281 @@ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* #pragma ident "@(#)g_utils.c 1.8 04/02/23 SMI" */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 diff --git a/src/lib/gssapi/mechglue/g_verify.c b/src/lib/gssapi/mechglue/g_verify.c index 7fc86b448..e6a01282a 100644 --- a/src/lib/gssapi/mechglue/g_verify.c +++ b/src/lib/gssapi/mechglue/g_verify.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gss_verify.c 1.9 95/08/07 SMI" */ +/* #pragma ident "@(#)g_verify.c 1.13 98/04/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -46,10 +46,16 @@ int * qop_state; gss_union_ctx_id_t ctx; gss_mechanism mech; - gss_initialize(); + + if (minor_status == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + *minor_status = 0; if (context_handle == GSS_C_NO_CONTEXT) - return GSS_S_NO_CONTEXT; + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT); + + if ((message_buffer == NULL) || GSS_EMPTY_BUFFER(token_buffer)) + return (GSS_S_CALL_INACCESSIBLE_READ); /* * select the approprate underlying mechanism routine and @@ -57,7 +63,7 @@ int * qop_state; */ ctx = (gss_union_ctx_id_t) context_handle; - mech = __gss_get_mechanism (ctx->mech_type); + mech = gssint_get_mechanism (ctx->mech_type); if (mech) { if (mech->gss_verify) @@ -69,12 +75,12 @@ int * qop_state; token_buffer, qop_state); else - status = GSS_S_BAD_BINDINGS; + status = GSS_S_UNAVAILABLE; return(status); } - return(GSS_S_NO_CONTEXT); + return (GSS_S_BAD_MECH); } OM_uint32 KRB5_CALLCONV diff --git a/src/lib/gssapi/mechglue/gssd_pname_to_uid.c b/src/lib/gssapi/mechglue/gssd_pname_to_uid.c index eb7c051ac..f15b16c5d 100644 --- a/src/lib/gssapi/mechglue/gssd_pname_to_uid.c +++ b/src/lib/gssapi/mechglue/gssd_pname_to_uid.c @@ -1,4 +1,4 @@ -/* #ident "@(#)gssd_pname_to_uid.c 1.5 95/08/02 SMI" */ +/* #pragma ident "@(#)gssd_pname_to_uid.c 1.18 04/02/23 SMI" */ /* * Copyright 1996 by Sun Microsystems, Inc. @@ -42,14 +42,12 @@ uid_t * uid; int status; gss_mechanism mech; - gss_initialize(); - /* * find the appropriate mechanism specific pname_to_uid procedure and * call it. */ - mech = __gss_get_mechanism (mech_type); + mech = gssint_get_mechanism (mech_type); if (mech) { if (mech_type == GSS_C_NULL_OID) diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h index c9a7d4ee3..bfee2524a 100644 --- a/src/lib/gssapi/mechglue/mglueP.h +++ b/src/lib/gssapi/mechglue/mglueP.h @@ -10,7 +10,18 @@ #ifndef _GSS_MECHGLUEP_H #define _GSS_MECHGLUEP_H +#include "autoconf.h" #include "mechglue.h" +#include "gssapiP_generic.h" + +#define g_OID_copy(o1, o2) \ +do { \ + memcpy((o1)->elements, (o2)->elements, (o2)->length); \ + (o1)->length = (o2)->length; \ +} while (0) + +#define GSS_EMPTY_BUFFER(buf) ((buf) == NULL ||\ + (buf)->value == NULL || (buf)->length == 0) /* * Array of context IDs typed by mechanism OID @@ -50,7 +61,7 @@ typedef struct gss_mech_spec_name_t { typedef struct gss_union_cred_auxinfo { gss_buffer_desc name; gss_OID name_type; - time_t creation_time; + OM_uint32 creation_time; OM_uint32 time_rec; int cred_usage; } gss_union_cred_auxinfo; @@ -61,10 +72,23 @@ typedef struct gss_union_cred_auxinfo { typedef struct gss_union_cred_t { int count; gss_OID mechs_array; - gss_cred_id_t * cred_array; + gss_cred_id_t *cred_array; gss_union_cred_auxinfo auxinfo; } gss_union_cred_desc, *gss_union_cred_t; +typedef OM_uint32 (*gss_acquire_cred_with_password_sfct)( + void *, /* context */ + OM_uint32 *, /* minor_status */ + const gss_name_t, /* desired_name */ + const gss_buffer_t, /* password */ + OM_uint32, /* time_req */ + const gss_OID_set, /* desired_mechs */ + int, /* cred_usage */ + gss_cred_id_t *, /* output_cred_handle */ + gss_OID_set *, /* actual_mechs */ + OM_uint32 * /* time_rec */ + /* */); + /********************************************************/ /* The Mechanism Dispatch Table -- a mechanism needs to */ /* define one of these and provide a function to return */ @@ -82,6 +106,8 @@ typedef struct gss_union_cred_t { */ typedef struct gss_config { + OM_uint32 priority; + char * mechNameStr; gss_OID_desc mech_type; void * context; OM_uint32 (*gss_acquire_cred) @@ -334,79 +360,165 @@ typedef struct gss_config { gss_OID, /* mech type */ uid_t * /* uid */ ); - + OM_uint32 (*gssint_userok) + ( + void *, /* context */ + OM_uint32 *, /* minor_status */ + const gss_name_t, /* pname */ + const char *, /* local user */ + int * /* user ok? */ + /* */); + OM_uint32 (*gss_export_name) + ( + void *, /* context */ + OM_uint32 *, /* minor_status */ + const gss_name_t, /* input_name */ + gss_buffer_t /* exported_name */ + /* */); + OM_uint32 (*gss_store_cred) + ( + void *, /* context */ + OM_uint32 *, /* minor_status */ + const gss_cred_id_t, /* input_cred */ + gss_cred_usage_t, /* cred_usage */ + const gss_OID, /* desired_mech */ + OM_uint32, /* overwrite_cred */ + OM_uint32, /* default_cred */ + gss_OID_set *, /* elements_stored */ + gss_cred_usage_t * /* cred_usage_stored */ + /* */); } *gss_mechanism; +/* This structure MUST NOT be used by any code outside libgss */ +typedef struct gss_config_ext { + gss_acquire_cred_with_password_sfct gss_acquire_cred_with_password; +} *gss_mechanism_ext; + +/* + * In the user space we use a wrapper structure to encompass the + * mechanism entry points. The wrapper contain the mechanism + * entry points and other data which is only relevant to the gss-api + * layer. In the kernel we use only the gss_config strucutre because + * the kernal does not cantain any of the extra gss-api specific data. + */ +typedef struct gss_mech_config { + char *kmodName; /* kernel module name */ + char *uLibName; /* user library name */ + char *mechNameStr; /* mechanism string name */ + char *optionStr; /* optional mech parameters */ + void *dl_handle; /* RTLD object handle for the mech */ + gss_OID mech_type; /* mechanism oid */ + gss_mechanism mech; /* mechanism initialization struct */ + gss_mechanism_ext mech_ext; /* extensions */ + struct gss_mech_config *next; /* next element in the list */ +} *gss_mech_info; + /********************************************************/ /* Internal mechglue routines */ -gss_mechanism __gss_get_mechanism (gss_OID); -OM_uint32 __gss_get_mech_type (gss_OID, gss_buffer_t); -OM_uint32 __gss_import_internal_name (OM_uint32 *, gss_OID, gss_union_name_t, +int gssint_mechglue_init(void); +void gssint_mechglue_fini(void); + +gss_mechanism gssint_get_mechanism (gss_OID); +gss_mechanism_ext gssint_get_mechanism_ext(const gss_OID); +OM_uint32 gssint_get_mech_type (gss_OID, gss_buffer_t); +char *gssint_get_kmodName(const gss_OID); +char *gssint_get_modOptions(const gss_OID); +OM_uint32 gssint_import_internal_name (OM_uint32 *, gss_OID, gss_union_name_t, gss_name_t *); -OM_uint32 __gss_display_internal_name (OM_uint32 *, gss_OID, gss_name_t, +OM_uint32 gssint_export_internal_name(OM_uint32 *, const gss_OID, + const gss_name_t, gss_buffer_t); +OM_uint32 gssint_display_internal_name (OM_uint32 *, gss_OID, gss_name_t, gss_buffer_t, gss_OID *); -OM_uint32 __gss_release_internal_name (OM_uint32 *, gss_OID, gss_name_t *); +OM_uint32 gssint_release_internal_name (OM_uint32 *, gss_OID, gss_name_t *); -OM_uint32 __gss_convert_name_to_union_name +OM_uint32 gssint_convert_name_to_union_name (OM_uint32 *, /* minor_status */ gss_mechanism, /* mech */ gss_name_t, /* internal_name */ gss_name_t * /* external_name */ ); -gss_cred_id_t __gss_get_mechanism_cred +gss_cred_id_t gssint_get_mechanism_cred (gss_union_cred_t, /* union_cred */ gss_OID /* mech_type */ ); -OM_uint32 generic_gss_release_oid - (OM_uint32 *, /* minor_status */ - gss_OID * /* oid */ - ); +OM_uint32 gssint_create_copy_buffer( + const gss_buffer_t, /* src buffer */ + gss_buffer_t *, /* destination buffer */ + int /* NULL terminate buffer ? */ +); -OM_uint32 generic_gss_copy_oid - (OM_uint32 *, /* minor_status */ - gss_OID, /* oid */ - gss_OID * /* new_oid */ - ); +OM_uint32 gssint_copy_oid_set( + OM_uint32 *, /* minor_status */ + const gss_OID_set_desc *, /* oid set */ + gss_OID_set * /* new oid set */ +); -OM_uint32 generic_gss_create_empty_oid_set - (OM_uint32 *, /* minor_status */ - gss_OID_set * /* oid_set */ - ); +gss_OID gss_find_mechanism_from_name_type (gss_OID); /* name_type */ -OM_uint32 generic_gss_add_oid_set_member +OM_uint32 gss_add_mech_name_type (OM_uint32 *, /* minor_status */ - gss_OID, /* member_oid */ - gss_OID_set * /* oid_set */ - ); + gss_OID, /* name_type */ + gss_OID /* mech */ + ); -OM_uint32 generic_gss_test_oid_set_member - (OM_uint32 *, /* minor_status */ - gss_OID, /* member */ - gss_OID_set, /* set */ - int * /* present */ - ); +/* + * Sun extensions to GSS-API v2 + */ -OM_uint32 generic_gss_oid_to_str - (OM_uint32 *, /* minor_status */ - gss_OID, /* oid */ - gss_buffer_t /* oid_str */ - ); +OM_uint32 +gssint_mech_to_oid( + const char *mech, /* mechanism string name */ + gss_OID *oid /* mechanism oid */ +); -OM_uint32 generic_gss_str_to_oid - (OM_uint32 *, /* minor_status */ - gss_buffer_t, /* oid_str */ - gss_OID * /* oid */ - ); +const char * +gssint_oid_to_mech( + const gss_OID oid /* mechanism oid */ +); +OM_uint32 +gssint_get_mechanisms( + char *mechArray[], /* array to populate with mechs */ + int arrayLen /* length of passed in array */ +); -gss_OID gss_find_mechanism_from_name_type (gss_OID); /* name_type */ +OM_uint32 +gssint_userok( + OM_uint32 *, /* minor */ + const gss_name_t, /* name */ + const char *, /* user */ + int * /* user_ok */ +); -OM_uint32 gss_add_mech_name_type - (OM_uint32 *, /* minor_status */ - gss_OID, /* name_type */ - gss_OID /* mech */ - ); +OM_uint32 +gss_store_cred( + OM_uint32 *, /* minor_status */ + const gss_cred_id_t, /* input_cred_handle */ + gss_cred_usage_t, /* cred_usage */ + const gss_OID, /* desired_mech */ + OM_uint32, /* overwrite_cred */ + OM_uint32, /* default_cred */ + gss_OID_set *, /* elements_stored */ + gss_cred_usage_t * /* cred_usage_stored */ +); + +int +gssint_get_der_length( + unsigned char **, /* buf */ + unsigned int, /* buf_len */ + unsigned int * /* bytes */ +); + +unsigned int +gssint_der_length_size(unsigned int /* len */); + +int +gssint_put_der_length( + unsigned int, /* length */ + unsigned char **, /* buf */ + unsigned int /* max_len */ +); #endif /* _GSS_MECHGLUEP_H */ diff --git a/src/lib/gssapi/mechglue/oid_ops.c b/src/lib/gssapi/mechglue/oid_ops.c index 8e9da8852..ee981a507 100644 --- a/src/lib/gssapi/mechglue/oid_ops.c +++ b/src/lib/gssapi/mechglue/oid_ops.c @@ -1,3 +1,4 @@ +/* #pragma ident "@(#)oid_ops.c 1.19 04/02/23 SMI" */ /* * lib/gssapi/generic/oid_ops.c * @@ -45,7 +46,8 @@ generic_gss_release_oid(minor_status, oid) OM_uint32 *minor_status; gss_OID *oid; { - *minor_status = 0; + if (minor_status) + *minor_status = 0; if (*oid == GSS_C_NO_OID) return(GSS_S_COMPLETE); @@ -59,9 +61,20 @@ generic_gss_release_oid(minor_status, oid) * descriptor. This allows applications to freely mix their own heap- * allocated OID values with OIDs returned by GSS-API. */ - if ((*oid != gss_nt_user_name) && - (*oid != gss_nt_machine_uid_name) && - (*oid != gss_nt_string_uid_name) && + + /* + * We use the official OID definitions instead of the unofficial OID + * defintions. But we continue to support the unofficial OID + * gss_nt_service_name just in case if some gss applications use + * the old OID. + */ + + if ((*oid != GSS_C_NT_USER_NAME) && + (*oid != GSS_C_NT_MACHINE_UID_NAME) && + (*oid != GSS_C_NT_STRING_UID_NAME) && + (*oid != GSS_C_NT_HOSTBASED_SERVICE) && + (*oid != GSS_C_NT_ANONYMOUS) && + (*oid != GSS_C_NT_EXPORT_NAME) && (*oid != gss_nt_service_name)) { free((*oid)->elements); free(*oid); @@ -73,10 +86,13 @@ generic_gss_release_oid(minor_status, oid) OM_uint32 generic_gss_copy_oid(minor_status, oid, new_oid) OM_uint32 *minor_status; - gss_OID oid, *new_oid; + const gss_OID_desc * const oid; + gss_OID *new_oid; { gss_OID p; + *minor_status = 0; + p = (gss_OID) malloc(sizeof(gss_OID_desc)); if (!p) { *minor_status = ENOMEM; @@ -86,7 +102,6 @@ generic_gss_copy_oid(minor_status, oid, new_oid) p->elements = malloc(p->length); if (!p->elements) { free(p); - *minor_status = ENOMEM; return GSS_S_FAILURE; } memcpy(p->elements, oid->elements, p->length); @@ -100,9 +115,10 @@ generic_gss_create_empty_oid_set(minor_status, oid_set) OM_uint32 *minor_status; gss_OID_set *oid_set; { + *minor_status = 0; + if ((*oid_set = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)))) { memset(*oid_set, 0, sizeof(gss_OID_set_desc)); - *minor_status = 0; return(GSS_S_COMPLETE); } else { @@ -114,12 +130,18 @@ generic_gss_create_empty_oid_set(minor_status, oid_set) OM_uint32 generic_gss_add_oid_set_member(minor_status, member_oid, oid_set) OM_uint32 *minor_status; - gss_OID member_oid; + const gss_OID_desc * const member_oid; gss_OID_set *oid_set; { gss_OID elist; gss_OID lastel; + *minor_status = 0; + + if (member_oid == NULL || member_oid->length == 0 || + member_oid->elements == NULL) + return (GSS_S_CALL_INACCESSIBLE_READ); + elist = (*oid_set)->elements; /* Get an enlarged copy of the array */ if (((*oid_set)->elements = (gss_OID) malloc(((*oid_set)->count+1) * @@ -159,13 +181,21 @@ generic_gss_add_oid_set_member(minor_status, member_oid, oid_set) OM_uint32 generic_gss_test_oid_set_member(minor_status, member, set, present) OM_uint32 *minor_status; - gss_OID member; + const gss_OID_desc * const member; gss_OID_set set; int *present; { - size_t i; + OM_uint32 i; int result; + *minor_status = 0; + + if (member == NULL || set == NULL) + return (GSS_S_CALL_INACCESSIBLE_READ); + + if (present == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + result = 0; for (i=0; icount; i++) { if ((set->elements[i].length == member->length) && @@ -177,7 +207,6 @@ generic_gss_test_oid_set_member(minor_status, member, set, present) } } *present = result; - *minor_status = 0; return(GSS_S_COMPLETE); } @@ -187,17 +216,25 @@ generic_gss_test_oid_set_member(minor_status, member, set, present) OM_uint32 generic_gss_oid_to_str(minor_status, oid, oid_str) OM_uint32 *minor_status; - gss_OID oid; + const gss_OID_desc * const oid; gss_buffer_t oid_str; { char numstr[128]; - unsigned long number; + OM_uint32 number; int numshift; - size_t string_length; - size_t i; + OM_uint32 string_length; + OM_uint32 i; unsigned char *cp; char *bp; + *minor_status = 0; + + if (oid == NULL || oid->length == 0 || oid->elements == NULL) + return (GSS_S_CALL_INACCESSIBLE_READ); + + if (oid_str == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + /* Decoded according to krb5/gssapi_krb5.c */ /* First determine the size of the string */ @@ -206,21 +243,20 @@ generic_gss_oid_to_str(minor_status, oid, oid_str) numshift = 0; cp = (unsigned char *) oid->elements; number = (unsigned long) cp[0]; - sprintf(numstr, "%ld ", number/40); + sprintf(numstr, "%lu ", (unsigned long)number/40); string_length += strlen(numstr); - sprintf(numstr, "%ld ", number%40); + sprintf(numstr, "%lu ", (unsigned long)number%40); string_length += strlen(numstr); for (i=1; ilength; i++) { - if ( (size_t) (numshift+7) < (sizeof(unsigned long)*8)) { + if ((OM_uint32) (numshift+7) < (sizeof (OM_uint32)*8)) {/* XXX */ number = (number << 7) | (cp[i] & 0x7f); numshift += 7; } else { - *minor_status = EINVAL; return(GSS_S_FAILURE); } if ((cp[i] & 0x80) == 0) { - sprintf(numstr, "%ld ", number); + sprintf(numstr, "%lu ", (unsigned long)number); string_length += strlen(numstr); number = 0; numshift = 0; @@ -233,17 +269,17 @@ generic_gss_oid_to_str(minor_status, oid, oid_str) string_length += 4; if ((bp = (char *) malloc(string_length))) { strcpy(bp, "{ "); - number = (unsigned long) cp[0]; - sprintf(numstr, "%ld ", number/40); + number = (OM_uint32) cp[0]; + sprintf(numstr, "%lu ", (unsigned long)number/40); strcat(bp, numstr); - sprintf(numstr, "%ld ", number%40); + sprintf(numstr, "%lu ", (unsigned long)number%40); strcat(bp, numstr); number = 0; cp = (unsigned char *) oid->elements; for (i=1; ilength; i++) { number = (number << 7) | (cp[i] & 0x7f); if ((cp[i] & 0x80) == 0) { - sprintf(numstr, "%ld ", number); + sprintf(numstr, "%lu ", (unsigned long)number); strcat(bp, numstr); number = 0; } @@ -251,7 +287,6 @@ generic_gss_oid_to_str(minor_status, oid, oid_str) strcat(bp, "}"); oid_str->length = strlen(bp)+1; oid_str->value = (void *) bp; - *minor_status = 0; return(GSS_S_COMPLETE); } *minor_status = ENOMEM; @@ -264,7 +299,7 @@ generic_gss_str_to_oid(minor_status, oid_str, oid) gss_buffer_t oid_str; gss_OID *oid; { - char *cp, *bp, *startp; + unsigned char *cp, *bp, *startp; int brace; long numbuf; long onumbuf; @@ -272,8 +307,16 @@ generic_gss_str_to_oid(minor_status, oid_str, oid) int index; unsigned char *op; + *minor_status = 0; + + if (GSS_EMPTY_BUFFER(oid_str)) + return (GSS_S_CALL_INACCESSIBLE_READ); + + if (oid == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + brace = 0; - bp = (char *) oid_str->value; + bp = oid_str->value; cp = bp; /* Skip over leading space */ while ((bp < &cp[oid_str->length]) && isspace(*bp)) @@ -290,7 +333,7 @@ generic_gss_str_to_oid(minor_status, oid_str, oid) /* * The first two numbers are chewed up by the first octet. */ - if (sscanf(bp, "%ld", &numbuf) != 1) { + if (sscanf((char *)bp, "%ld", &numbuf) != 1) { *minor_status = EINVAL; return(GSS_S_FAILURE); } @@ -298,18 +341,18 @@ generic_gss_str_to_oid(minor_status, oid_str, oid) bp++; while ((bp < &cp[oid_str->length]) && isspace(*bp)) bp++; - if (sscanf(bp, "%ld", &numbuf) != 1) { + if (sscanf((char *)bp, "%ld", &numbuf) != 1) { *minor_status = EINVAL; return(GSS_S_FAILURE); } while ((bp < &cp[oid_str->length]) && isdigit(*bp)) bp++; - while ((bp < &cp[oid_str->length]) && isspace(*bp)) + while ((bp < &cp[oid_str->length]) && + (isspace(*bp) || *bp == '.')) bp++; nbytes++; while (isdigit(*bp)) { - if (sscanf(bp, "%ld", &numbuf) != 1) { - *minor_status = EINVAL; + if (sscanf((char *)bp, "%ld", &numbuf) != 1) { return(GSS_S_FAILURE); } while (numbuf) { @@ -318,11 +361,11 @@ generic_gss_str_to_oid(minor_status, oid_str, oid) } while ((bp < &cp[oid_str->length]) && isdigit(*bp)) bp++; - while ((bp < &cp[oid_str->length]) && isspace(*bp)) + while ((bp < &cp[oid_str->length]) && + (isspace(*bp) || *bp == '.')) bp++; } if (brace && (*bp != '}')) { - *minor_status = EINVAL; return(GSS_S_FAILURE); } @@ -330,26 +373,26 @@ generic_gss_str_to_oid(minor_status, oid_str, oid) * Phew! We've come this far, so the syntax is good. */ if ((*oid = (gss_OID) malloc(sizeof(gss_OID_desc)))) { - if (((*oid)->elements = (void *) malloc((size_t) nbytes))) { + if (((*oid)->elements = (void *) malloc(nbytes))) { (*oid)->length = nbytes; op = (unsigned char *) (*oid)->elements; bp = startp; - sscanf(bp, "%ld", &numbuf); + (void) sscanf((char *)bp, "%ld", &numbuf); while (isdigit(*bp)) bp++; - while (isspace(*bp)) + while (isspace(*bp) || *bp == '.') bp++; onumbuf = 40*numbuf; - sscanf(bp, "%ld", &numbuf); + (void) sscanf((char *)bp, "%ld", &numbuf); onumbuf += numbuf; *op = (unsigned char) onumbuf; op++; while (isdigit(*bp)) bp++; - while (isspace(*bp)) + while (isspace(*bp) || *bp == '.') bp++; while (isdigit(*bp)) { - sscanf(bp, "%ld", &numbuf); + (void) sscanf((char *)bp, "%ld", &numbuf); nbytes = 0; /* Have to fill in the bytes msb-first */ onumbuf = numbuf; @@ -369,10 +412,9 @@ generic_gss_str_to_oid(minor_status, oid_str, oid) } while (isdigit(*bp)) bp++; - while (isspace(*bp)) + while (isspace(*bp) || *bp == '.') bp++; } - *minor_status = 0; return(GSS_S_COMPLETE); } else { @@ -380,7 +422,82 @@ generic_gss_str_to_oid(minor_status, oid_str, oid) *oid = GSS_C_NO_OID; } } - *minor_status = ENOMEM; return(GSS_S_FAILURE); } +/* + * Copyright 1993 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +OM_uint32 +gssint_copy_oid_set( + OM_uint32 *minor_status, + const gss_OID_set_desc * const oidset, + gss_OID_set *new_oidset + ) +{ + gss_OID_set_desc *copy; + OM_uint32 minor = 0; + OM_uint32 major = GSS_S_COMPLETE; + OM_uint32 index; + + if (minor_status) + *minor_status = 0; + + if (oidset == NULL) + return (GSS_S_CALL_INACCESSIBLE_READ); + + if (new_oidset == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + *new_oidset = NULL; + + if ((copy = (gss_OID_set_desc *) calloc(1, sizeof (*copy))) == NULL) { + major = GSS_S_FAILURE; + goto done; + } + + if ((copy->elements = (gss_OID_desc *) + calloc(oidset->count, sizeof (*copy->elements))) == NULL) { + major = GSS_S_FAILURE; + goto done; + } + copy->count = oidset->count; + + for (index = 0; index < copy->count; index++) { + gss_OID_desc *out = ©->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); +} diff --git a/src/lib/gssapi/spnego/Makefile.in b/src/lib/gssapi/spnego/Makefile.in new file mode 100644 index 000000000..631f474e9 --- /dev/null +++ b/src/lib/gssapi/spnego/Makefile.in @@ -0,0 +1,23 @@ +thisconfigdir=../../.. +myfulldir=lib/gssapi/spnego +mydir=spnego +BUILDTOP=$(REL)..$(S)..$(S).. +LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic -I../mechglue -I$(srcdir)/../mechglue + +##DOS##BUILDTOP = ..\..\.. +##DOS##PREFIXDIR=spnego +##DOS##OBJFILE = ..\$(OUTPRE)spnego.lst + +##DOS##DLL_EXP_TYPE=GSS + +SRCS = $(srcdir)/spnego_mech.c + +OBJS = $(OUTPRE)spnego_mech.$(OBJEXT) + +STLIBOBJS = spnego_mech.o + +all-unix:: all-libobjs + +clean-unix:: clean-libobjs + +# @libobj_frag@ diff --git a/src/lib/gssapi/spnego/gssapiP_spnego.h b/src/lib/gssapi/spnego/gssapiP_spnego.h new file mode 100644 index 000000000..2d3e5e20b --- /dev/null +++ b/src/lib/gssapi/spnego/gssapiP_spnego.h @@ -0,0 +1,349 @@ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _GSSAPIP_SPNEGO_H_ +#define _GSSAPIP_SPNEGO_H_ + +/* #pragma ident "@(#)gssapiP_spnego.h 1.3 03/09/18 SMI" */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define SEC_CONTEXT_TOKEN 1 +#define SPNEGO_SIZE_OF_INT 4 + +#define ACCEPT_COMPLETE 0 +#define ACCEPT_INCOMPLETE 1 +#define REJECT 2 +#define REQUEST_MIC 3 +#define ACCEPT_DEFECTIVE_TOKEN 0xffffffffUL + +/* + * constants for der encoding/decoding routines. + */ + +#define MECH_OID 0x06 +#define OCTET_STRING 0x04 +#define CONTEXT 0xa0 +#define SEQUENCE 0x30 +#define SEQUENCE_OF 0x30 +#define BIT_STRING 0x03 +#define BIT_STRING_LENGTH 0x02 +#define BIT_STRING_PADDING 0x01 +#define ENUMERATED 0x0a +#define ENUMERATION_LENGTH 1 +#define HEADER_ID 0x60 + +/* + * SPNEGO specific error codes (minor status codes) + */ +#define ERR_SPNEGO_NO_MECHS_AVAILABLE 0x20000001 +#define ERR_SPNEGO_NO_CREDS_ACQUIRED 0x20000002 +#define ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR 0x20000003 +#define ERR_SPNEGO_NEGOTIATION_FAILED 0x20000004 +#define ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR 0x20000005 + +/* + * send_token_flag is used to indicate in later steps what type + * of token, if any should be sent or processed. + * NO_TOKEN_SEND = no token should be sent + * INIT_TOKEN_SEND = initial token will be sent + * CONT_TOKEN_SEND = continuing tokens to be sent + * CHECK_MIC = no token to be sent, but have a MIC to check. + * ERROR_TOKEN_SEND = error token from peer needs to be sent. + */ + +typedef enum {NO_TOKEN_SEND, INIT_TOKEN_SEND, CONT_TOKEN_SEND, + CHECK_MIC, ERROR_TOKEN_SEND} send_token_flag; + +/* + * The Mech OID: + * { iso(1) org(3) dod(6) internet(1) security(5) + * mechanism(5) spnego(2) } + */ + +#define SPNEGO_OID_LENGTH 6 +#define SPNEGO_OID "\053\006\001\005\005\002" + +typedef void *spnego_token_t; + +/* spnego name structure for internal representation. */ +typedef struct { + gss_OID type; + gss_buffer_t buffer; + gss_OID mech_type; + gss_name_t mech_name; +} spnego_name_desc, *spnego_name_t; + +/* Structure for context handle */ +typedef struct { + OM_uint32 magic_num; + gss_buffer_desc DER_mechTypes; + gss_OID internal_mech; + gss_ctx_id_t ctx_handle; + char *optionStr; + gss_cred_id_t default_cred; + int mic_reqd; + int mic_sent; + int mic_rcvd; + int firstpass; + int mech_complete; + int nego_done; + OM_uint32 ctx_flags; + gss_name_t internal_name; + gss_OID actual_mech; +} spnego_gss_ctx_id_rec, *spnego_gss_ctx_id_t; + +/* + * The magic number must be less than a standard pagesize + * to avoid a possible collision with a real address. + */ +#define SPNEGO_MAGIC_ID 0x00000fed + +/* SPNEGO oid structure */ +static const gss_OID_desc spnego_oids[] = { + {SPNEGO_OID_LENGTH, SPNEGO_OID}, +}; + +const gss_OID_desc * const gss_mech_spnego = spnego_oids+0; +static const gss_OID_set_desc spnego_oidsets[] = { + {1, (gss_OID) spnego_oids+0}, +}; +const gss_OID_set_desc * const gss_mech_set_spnego = spnego_oidsets+0; + +#define TWRITE_STR(ptr, str, len) \ + memcpy((ptr), (char *)(str), (len)); \ + (ptr) += (len); + +#ifdef DEBUG +#define dsyslog(a) syslog(LOG_DEBUG, a) +#else +#define dsyslog(a) +#define SPNEGO_STATIC +#endif /* DEBUG */ + +/* + * declarations of internal name mechanism functions + */ + +OM_uint32 spnego_gss_acquire_cred +( + void *, /* spnego context */ + OM_uint32 *, /* minor_status */ + gss_name_t, /* desired_name */ + OM_uint32, /* time_req */ + gss_OID_set, /* desired_mechs */ + gss_cred_usage_t, /* cred_usage */ + gss_cred_id_t *, /* output_cred_handle */ + gss_OID_set *, /* actual_mechs */ + OM_uint32 * /* time_rec */ +); + +OM_uint32 spnego_gss_release_cred +( + void *, /* spnego context */ + OM_uint32 *, /* minor_status */ + /* CSTYLED */ + gss_cred_id_t * /* cred_handle */ +); + +OM_uint32 spnego_gss_init_sec_context +( + void *, /* spnego context */ + OM_uint32 *, /* minor_status */ + gss_cred_id_t, /* claimant_cred_handle */ + gss_ctx_id_t *, /* context_handle */ + gss_name_t, /* target_name */ + gss_OID, /* mech_type */ + OM_uint32, /* req_flags */ + OM_uint32, /* time_req */ + gss_channel_bindings_t, /* input_chan_bindings */ + gss_buffer_t, /* input_token */ + gss_OID *, /* actual_mech_type */ + gss_buffer_t, /* output_token */ + OM_uint32 *, /* ret_flags */ + OM_uint32 * /* time_rec */ +); + +OM_uint32 spnego_gss_accept_sec_context +( + void *, /* spnego context */ + OM_uint32 *, /* minor_status */ + gss_ctx_id_t *, /* context_handle */ + gss_cred_id_t, /* verifier_cred_handle */ + gss_buffer_t, /* input_token_buffer */ + gss_channel_bindings_t, /* input_chan_bindings */ + gss_name_t *, /* src_name */ + gss_OID *, /* mech_type */ + gss_buffer_t, /* output_token */ + OM_uint32 *, /* ret_flags */ + OM_uint32 *, /* time_rec */ + /* CSTYLED */ + gss_cred_id_t * /* delegated_cred_handle */ +); + +OM_uint32 spnego_gss_display_name +( + void *, + OM_uint32 *, /* minor_status */ + gss_name_t, /* input_name */ + gss_buffer_t, /* output_name_buffer */ + gss_OID * /* output_name_type */ +); + +OM_uint32 spnego_gss_display_status +( + void *, /* spnego context */ + OM_uint32 *, /* minor_status */ + OM_uint32, /* status_value */ + int, /* status_type */ + gss_OID, /* mech_type */ + OM_uint32 *, /* message_context */ + gss_buffer_t /* status_string */ +); + +OM_uint32 spnego_gss_import_name +( + void *, /* spnego context */ + OM_uint32 *, /* minor_status */ + gss_buffer_t, /* input_name_buffer */ + gss_OID, /* input_name_type */ + /* CSTYLED */ + gss_name_t * /* output_name */ +); + +OM_uint32 spnego_gss_release_name +( + void *, /* spnego context */ + OM_uint32 *, /* minor_status */ + /* CSTYLED */ + gss_name_t * /* input_name */ +); + +OM_uint32 spnego_gss_inquire_names_for_mech +( + void *, /* spnego context */ + OM_uint32 *, /* minor_status */ + gss_OID, /* mechanism */ + gss_OID_set * /* name_types */ +); + +OM_uint32 spnego_gss_unseal +( + void *context, + OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + int *qop_state +); + +OM_uint32 spnego_gss_seal +( + void *context, + OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + int qop_req, + gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer +); + +OM_uint32 spnego_gss_process_context_token +( + void *context, + OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t token_buffer +); + +OM_uint32 spnego_gss_delete_sec_context +( + void *context, + OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token +); + +OM_uint32 spnego_gss_context_time +( + void *context, + OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + OM_uint32 *time_rec +); + +OM_uint32 spnego_gss_export_sec_context +( + void *context, + OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t interprocess_token +); + +OM_uint32 spnego_gss_import_sec_context +( + void *context, + OM_uint32 *minor_status, + const gss_buffer_t interprocess_token, + gss_ctx_id_t *context_handle +); + +OM_uint32 spnego_gss_inquire_context +( + void *context, + OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + gss_name_t *src_name, + gss_name_t *targ_name, + OM_uint32 *lifetime_rec, + gss_OID *mech_type, + OM_uint32 *ctx_flags, + int *locally_initiated, + int *open +); + +OM_uint32 spnego_gss_wrap_size_limit +( + void *context, + OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size +); + +OM_uint32 spnego_gss_sign +( + void *context, + OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + int qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token +); + +OM_uint32 spnego_gss_verify +( + void *context, + OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t msg_buffer, + const gss_buffer_t token_buffer, + int *qop_state +); + +#ifdef __cplusplus +} +#endif + +#endif /* _GSSAPIP_SPNEGO_H_ */ diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c new file mode 100644 index 000000000..ec8b6083a --- /dev/null +++ b/src/lib/gssapi/spnego/spnego_mech.c @@ -0,0 +1,2843 @@ +/* + * Copyright (C) 2006 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * A module that implements the spnego security mechanism. + * It is used to negotiate the security mechanism between + * peers using the GSS-API. + * + */ + +/* #pragma ident "@(#)spnego_mech.c 1.7 04/09/28 SMI" */ + +#include +#include +#include +#include +#include +#include "gssapiP_spnego.h" +#include +#include + +#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); +} diff --git a/src/lib/rpc/svc_auth_gssapi.c b/src/lib/rpc/svc_auth_gssapi.c index 7ddefe5e8..ec2410331 100644 --- a/src/lib/rpc/svc_auth_gssapi.c +++ b/src/lib/rpc/svc_auth_gssapi.c @@ -972,7 +972,6 @@ void svcauth_gssapi_unset_names(void) gss_release_cred(&minor_stat, &server_creds_list[i]); free(server_creds_list); server_creds_list = NULL; - server_creds_count = 0; } if (server_name_list) { @@ -981,8 +980,8 @@ void svcauth_gssapi_unset_names(void) gss_release_name(&minor_stat, &server_name_list[i]); free(server_name_list); server_name_list = NULL; - server_creds_count = 0; } + server_creds_count = 0; } diff --git a/src/lib/rpc/unit-test/rpc_test.0/expire.exp b/src/lib/rpc/unit-test/rpc_test.0/expire.exp index 5c33ffde5..f5841011f 100644 --- a/src/lib/rpc/unit-test/rpc_test.0/expire.exp +++ b/src/lib/rpc/unit-test/rpc_test.0/expire.exp @@ -12,7 +12,7 @@ proc expired {} { expect { -i $server_id - -re "rpc_test server: Authen.*failed: .* referenced credentials have expired" { pass "expired" } + -re "rpc_test server: Authen.*failed:.*credential.*expired" { pass "expired" } timeout { fail "expired: timeout waiting for expired creds error" } } diff --git a/src/tests/dejagnu/krb-standalone/v4gssftp.exp b/src/tests/dejagnu/krb-standalone/v4gssftp.exp index e739e9bd9..6353dc41f 100644 --- a/src/tests/dejagnu/krb-standalone/v4gssftp.exp +++ b/src/tests/dejagnu/krb-standalone/v4gssftp.exp @@ -249,7 +249,7 @@ proc v4ftp_test { } { expect -nocase -re "$localhostname.*ftp server .version \[0-9.\]*. ready." expect -re "Using authentication type GSSAPI; ADAT must follow" expect "GSSAPI accepted as authentication type" - expect "GSSAPI error major: Miscellaneous failure" + expect -re "GSSAPI error major: (Unspecified GSS|Miscellaneous) failure" expect { "GSSAPI error minor: Unsupported credentials cache format version number" {} "GSSAPI error minor: No credentials cache found" {}