From: Ken Raeburn Date: Thu, 16 Aug 2007 22:55:06 +0000 (+0000) Subject: remap mechanism-specific status codes in mechglue/spnego X-Git-Tag: krb5-1.7-alpha1~954 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=c15ec7751a7d7c1d97dbeb1dd88dda2a328515e0;p=krb5.git remap mechanism-specific status codes in mechglue/spnego This patch creates a mapping in the mechglue/spnego code to modify mechanism status codes when passing them back to the application, so that mechglue's display_status dispatcher can determine the correct mechanism to dispatch to. This is part of the "get enhanced error messages from gssapi applications" project; ticket 5590 has updates to the Kerberos 5 mechanism to extract enhanced error messages (when there are any) from the Kerberos library. util/gen.pl, util/t_*.pm: New code generation script and templates. lib/gssapi/generic: Add a new, global mapping that enumerates the {mechOID,status} pairs as they're seen, allowing a magic mechOID value to indicate com_err error codes from mechglue and spnego, and reserving status code 0 for unknown errors. Preload the Kerberos "wrong principal" error code once for each mechanism OID used for Kerberos, so the entries get fixed positions (1-3) in the table. lib/gssapi/gss_libinit.c: Call the initializer and destructor functions. lib/gssapi/mechglue, lib/gssapi/spnego: Enter all mechanism-generated or locally-generated status codes into the mapping table, and return the table index to the application. Do the reverse in display_status, to get the messages from the mechanism.. lib/rpc: Define new function gssrpcint_printf to use for debugging instead of printf, to redirect output away from dejagnu; add a couple more debugging calls. Check for minor status codes 1-3 now instead of KRB5KRB_AP_WRONG_PRINC. tests/dejagnu/krb-standalone/gssftp.exp: Test getting more detailed error messages back, by having the ftp client attempt to authenticate to a non-existent service, and examining the error message for the service principal name. ticket: new git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@19831 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/gssapi/generic/Makefile.in b/src/lib/gssapi/generic/Makefile.in index e63be6b78..6d66396be 100644 --- a/src/lib/gssapi/generic/Makefile.in +++ b/src/lib/gssapi/generic/Makefile.in @@ -70,6 +70,7 @@ SRCS = \ $(srcdir)/rel_buffer.c \ $(srcdir)/rel_oid_set.c \ $(srcdir)/util_buffer.c \ + $(srcdir)/util_errmap.c \ $(srcdir)/util_ordering.c \ $(srcdir)/util_set.c \ $(srcdir)/util_token.c \ @@ -83,6 +84,7 @@ OBJS = \ $(OUTPRE)rel_buffer.$(OBJEXT) \ $(OUTPRE)rel_oid_set.$(OBJEXT) \ $(OUTPRE)util_buffer.$(OBJEXT) \ + $(OUTPRE)util_errmap.$(OBJEXT) \ $(OUTPRE)util_ordering.$(OBJEXT) \ $(OUTPRE)util_set.$(OBJEXT) \ $(OUTPRE)util_token.$(OBJEXT) \ @@ -96,6 +98,7 @@ STLIBOBJS = \ rel_buffer.o \ rel_oid_set.o \ util_buffer.o \ + util_errmap.o \ util_ordering.o \ util_set.o \ util_token.o \ @@ -110,6 +113,19 @@ $(OBJS): $(EXPORTED_HEADERS) $(ETHDRS) all-unix:: $(EXPORTED_HEADERS) $(ETHDRS) $(HDRS) all-unix:: all-libobjs +errmap.h: $(SRCTOP)/util/gen.pl $(SRCTOP)/util/t_array.pm \ + $(SRCTOP)/util/t_enum.pm $(SRCTOP)/util/t_tsenum.pm + $(PERL) -w -I$(SRCTOP)/util $(SRCTOP)/util/gen.pl tsenum errmap.h \ + NAME=mecherrmap TYPE="struct mecherror" COMPARE=mecherror_cmp \ + COPY=mecherror_copy PRINT=mecherror_print + +maptest.h: $(SRCTOP)/util/gen.pl $(SRCTOP)/util/t_array.pm \ + $(SRCTOP)/util/t_enum.pm $(SRCTOP)/util/t_tsenum.pm + $(PERL) -w -I$(SRCTOP)/util $(SRCTOP)/util/gen.pl tsenum maptest.h \ + NAME=foo TYPE=elt COMPARE=eltcmp COPY=eltcp PRINT=eltprt +maptest.o: maptest.c maptest.h +maptest: maptest.o + $(CC_LINK) -o maptest maptest.o $(SUPPORT_LIB) ##DOS##LIBOBJS = $(OBJS) @@ -180,6 +196,11 @@ util_buffer.so util_buffer.po $(OUTPRE)util_buffer.$(OBJEXT): \ $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \ gssapiP_generic.h gssapi_err_generic.h gssapi_generic.h \ util_buffer.c +util_errmap.so util_errmap.po $(OUTPRE)util_errmap.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \ + errmap.h gssapiP_generic.h gssapi_err_generic.h gssapi_generic.h \ + util_errmap.c util_ordering.so util_ordering.po $(OUTPRE)util_ordering.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \ diff --git a/src/lib/gssapi/generic/gssapiP_generic.h b/src/lib/gssapi/generic/gssapiP_generic.h index e34055b6c..1ec5417ba 100644 --- a/src/lib/gssapi/generic/gssapiP_generic.h +++ b/src/lib/gssapi/generic/gssapiP_generic.h @@ -255,4 +255,9 @@ OM_uint32 generic_gss_str_to_oid gss_OID * /* oid */ ); +OM_uint32 gssint_mecherrmap_map(OM_uint32 minor, const gss_OID_desc *oid); +int gssint_mecherrmap_get(OM_uint32 minor, gss_OID mech_oid, + OM_uint32 *mech_minor); +OM_uint32 gssint_mecherrmap_map_errcode(OM_uint32 errcode); + #endif /* _GSSAPIP_GENERIC_H_ */ diff --git a/src/lib/gssapi/generic/maptest.c b/src/lib/gssapi/generic/maptest.c new file mode 100644 index 000000000..b884eed8b --- /dev/null +++ b/src/lib/gssapi/generic/maptest.c @@ -0,0 +1,54 @@ +#include +#include +#include + +typedef struct { int a, b; } elt; +static int eltcp(elt *dest, elt src) +{ + *dest = src; + return 0; +} +static int eltcmp(elt left, elt right) +{ + if (left.a < right.a) + return -1; + if (left.a > right.a) + return 1; + if (left.b < right.b) + return -1; + if (left.b > right.b) + return 1; + return 0; +} +static void eltprt(elt v, FILE *f) +{ + fprintf(f, "{%d,%d}", v.a, v.b); +} + +#include "maptest.h" + +foo foo1; + +int main () +{ + int err; + elt v1 = { 1, 2 }, v2 = { 3, 4 }; + long idx; + int added; + + err = foo_init(&foo1); + assert(err == 0); + err = foo_find_or_append(&foo1, v1, &idx, &added); + assert(err == 0); + printf("v1: idx=%ld added=%d\n", idx, added); + err = foo_find_or_append(&foo1, v2, &idx, &added); + assert(err == 0); + printf("v2: idx=%ld added=%d\n", idx, added); + err = foo_find_or_append(&foo1, v2, &idx, &added); + assert(err == 0); + printf("v2: idx=%ld added=%d\n", idx, added); + err = foo_find_or_append(&foo1, v1, &idx, &added); + assert(err == 0); + printf("v1: idx=%ld added=%d\n", idx, added); + return 0; +} diff --git a/src/lib/gssapi/generic/util_errmap.c b/src/lib/gssapi/generic/util_errmap.c new file mode 100644 index 000000000..24975cc45 --- /dev/null +++ b/src/lib/gssapi/generic/util_errmap.c @@ -0,0 +1,190 @@ +#include "gssapiP_generic.h" +#include +#include + +/* The mapping table is 0-based, but let's export codes that are + 1-based, keeping 0 for errors or unknown errors. + + The elements in the mapping table currently have separate copies of + each OID stored. This is a bit wasteful, but we are assuming the + table isn't likely to grow very large. */ + +struct mecherror { + gss_OID_desc mech; + OM_uint32 code; +}; + +static inline int +mecherror_cmp(struct mecherror m1, struct mecherror m2) +{ + if (m1.code < m2.code) + return -1; + if (m1.code > m2.code) + return 1; + if (m1.mech.length < m2.mech.length) + return -1; + if (m1.mech.length > m2.mech.length) + return 1; + if (m1.mech.length == 0) + return 0; + return memcmp(m1.mech.elements, m2.mech.elements, m1.mech.length); +} + +static inline int +mecherror_copy(struct mecherror *dest, struct mecherror src) +{ + *dest = src; + if (src.mech.length) { + dest->mech.elements = malloc(src.mech.length); + if (dest->mech.elements == NULL) + return ENOMEM; + } + memcpy(dest->mech.elements, src.mech.elements, src.mech.length); + return 0; +} + +static void +mecherror_print(struct mecherror value, FILE *f) +{ + OM_uint32 minor; + gss_buffer_desc str; + static const struct { + const char *oidstr, *name; + } mechnames[] = { + { "{ 1 2 840 113554 1 2 2 }", "krb5-new" }, + { "{ 1 3 5 1 5 2 }", "krb5-old" }, + { "{ 1 2 840 48018 1 2 2 }", "krb5-microsoft" }, + { "{ 1 3 6 1 5 5 2 }", "spnego" }, + }; + int i; + + fprintf(f, "%lu@", (unsigned long) value.code); + + if (value.mech.length == 0) { + fprintf(f, "(com_err)"); + return; + } + if (generic_gss_oid_to_str(&minor, &value.mech, &str)) { + fprintf(f, "(error in conversion)"); + return; + } + /* Note: generic_gss_oid_to_str returns a null-terminated string. */ + for (i = 0; i < sizeof(mechnames)/sizeof(mechnames[0]); i++) { + if (!strcmp(str.value, mechnames[i].oidstr) && mechnames[i].name != 0) { + fprintf(f, "%s", mechnames[i].name); + break; + } + } + if (i == sizeof(mechnames)/sizeof(mechnames[0])) + fprintf(f, "%s", (char *) str.value); + generic_gss_release_buffer(&minor, &str); +} + +#include "errmap.h" +#include "krb5.h" /* for KRB5KRB_AP_WRONG_PRINC */ + +static mecherrmap m; + +int gssint_mecherrmap_init(void) +{ + int err; + OM_uint32 n; + + err = mecherrmap_init(&m); + if (err) + return err; + + /* This is *so* gross. + + The RPC code depends on being able to recognize the "wrong + principal" minor status return from the Kerberos mechanism. + But a totally generic enumeration of status codes as they come + up makes that impossible. So "register" that status code + early, and always with the same value. + + Of course, to make things worse, we're treating each mechanism + OID separately, and there are three for Kerberos. */ + { + /* Declare here to avoid including header files not generated + yet. */ + extern const gss_OID_desc *const gss_mech_krb5; + extern const gss_OID_desc *const gss_mech_krb5_old; + extern const gss_OID_desc *const gss_mech_krb5_wrong; + + const OM_uint32 wrong_princ = (OM_uint32) KRB5KRB_AP_WRONG_PRINC; + + n = gssint_mecherrmap_map(wrong_princ, gss_mech_krb5); + if (n <= 0) + return ENOMEM; + n = gssint_mecherrmap_map(wrong_princ, gss_mech_krb5_old); + if (n <= 0) + return ENOMEM; + n = gssint_mecherrmap_map(wrong_princ, gss_mech_krb5_wrong); + if (n <= 0) + return ENOMEM; + } + + return 0; +} + +/* Currently the enumeration template doesn't handle freeing + element storage when destroying the collection. */ +static int free_one(size_t i, struct mecherror value, void *p) +{ + if (value.mech.length && value.mech.elements) + free(value.mech.elements); + return 0; +} + +void gssint_mecherrmap_destroy(void) +{ + mecherrmap_foreach(&m, free_one, NULL); + mecherrmap_destroy(&m); +} + +OM_uint32 gssint_mecherrmap_map(OM_uint32 minor, const gss_OID_desc * oid) +{ + struct mecherror me; + int err, added; + long idx; + + me.code = minor; + me.mech = *oid; + err = mecherrmap_find_or_append(&m, me, &idx, &added); + if (err) { + return 0; + } + return idx+1; +} + +static gss_OID_desc no_oid = { 0, 0 }; +OM_uint32 gssint_mecherrmap_map_errcode(OM_uint32 errcode) +{ + return gssint_mecherrmap_map(errcode, &no_oid); +} + +int gssint_mecherrmap_get(OM_uint32 minor, gss_OID mech_oid, + OM_uint32 *mech_minor) +{ + struct mecherror me; + int err; + long size; + + if (minor == 0) { + return EINVAL; + } + err = mecherrmap_size(&m, &size); + if (err) { + return err; + } + if (minor > size) { + return EINVAL; + } + err = mecherrmap_get(&m, minor-1, &me); + if (err) { + return err; + } + *mech_oid = me.mech; + *mech_minor = me.code; + return 0; +} diff --git a/src/lib/gssapi/gss_libinit.c b/src/lib/gssapi/gss_libinit.c index b96eb9e7a..bb9085713 100644 --- a/src/lib/gssapi/gss_libinit.c +++ b/src/lib/gssapi/gss_libinit.c @@ -44,6 +44,9 @@ int gssint_lib_init(void) krb5_gss_delete_error_info); if (err) return err; + err = gssint_mecherrmap_init(); + if (err) + return err; #ifndef _WIN32 err = k5_mutex_finish_init(&kg_kdc_flag_mutex); if (err) @@ -74,6 +77,7 @@ void gssint_lib_fini(void) k5_mutex_destroy(&kg_kdc_flag_mutex); #endif k5_mutex_destroy(&gssint_krb5_keytab_lock); + gssint_mecherrmap_destroy(); gssint_mechglue_fini(); } diff --git a/src/lib/gssapi/mechglue/g_accept_sec_context.c b/src/lib/gssapi/mechglue/g_accept_sec_context.c index 0e8506a49..9b5562967 100644 --- a/src/lib/gssapi/mechglue/g_accept_sec_context.c +++ b/src/lib/gssapi/mechglue/g_accept_sec_context.c @@ -211,8 +211,10 @@ gss_cred_id_t * d_cred; return GSS_S_CONTINUE_NEEDED; /* if the call failed, return with failure */ - if (status != GSS_S_COMPLETE) + if (status != GSS_S_COMPLETE) { + map_error(minor_status, mech); goto error_out; + } /* * if src_name is non-NULL, @@ -227,6 +229,7 @@ gss_cred_id_t * d_cred; internal_name, &tmp_src_name); if (temp_status != GSS_S_COMPLETE) { *minor_status = temp_minor_status; + map_error(minor_status, mech); if (output_token->length) (void) gss_release_buffer(&temp_minor_status, output_token); @@ -297,6 +300,8 @@ gss_cred_id_t * d_cred; &d_u_cred->auxinfo.time_rec, &d_u_cred->auxinfo.cred_usage, NULL); + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); } if (internal_name != NULL) { @@ -305,6 +310,7 @@ gss_cred_id_t * d_cred; internal_name, &tmp_src_name); if (temp_status != GSS_S_COMPLETE) { *minor_status = temp_minor_status; + map_error(minor_status, mech); if (output_token->length) (void) gss_release_buffer( &temp_minor_status, diff --git a/src/lib/gssapi/mechglue/g_acquire_cred.c b/src/lib/gssapi/mechglue/g_acquire_cred.c index bd5bef8ea..6d63e5b8f 100644 --- a/src/lib/gssapi/mechglue/g_acquire_cred.c +++ b/src/lib/gssapi/mechglue/g_acquire_cred.c @@ -384,8 +384,10 @@ gss_add_cred(minor_status, input_cred_handle, GSS_C_NULL_OID_SET, cred_usage, &cred, NULL, &time_rec); - if (status != GSS_S_COMPLETE) + if (status != GSS_S_COMPLETE) { + map_error(minor_status, mech); goto errout; + } /* may need to set credential auxinfo strucutre */ if (union_cred->auxinfo.creation_time == 0) { diff --git a/src/lib/gssapi/mechglue/g_canon_name.c b/src/lib/gssapi/mechglue/g_canon_name.c index 9f72055b3..3d371c0e0 100644 --- a/src/lib/gssapi/mechglue/g_canon_name.c +++ b/src/lib/gssapi/mechglue/g_canon_name.c @@ -104,9 +104,13 @@ gss_name_t *output_name; 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))) + major_status = generic_gss_copy_oid(minor_status, + in_union->name_type, + &out_union->name_type); + if (major_status) { + map_errcode(minor_status); goto allocation_failure; + } } } @@ -130,8 +134,10 @@ gss_name_t *output_name; /* 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; + &dest_union->mech_type))) { + map_errcode(minor_status); + goto allocation_failure; + } if ((major_status = gssint_import_internal_name(minor_status, mech_type, diff --git a/src/lib/gssapi/mechglue/g_compare_name.c b/src/lib/gssapi/mechglue/g_compare_name.c index 7fb5cc9cf..40f4648ef 100644 --- a/src/lib/gssapi/mechglue/g_compare_name.c +++ b/src/lib/gssapi/mechglue/g_compare_name.c @@ -114,10 +114,13 @@ int * name_equal; if ((union_name1->mech_name == 0) || (union_name2->mech_name == 0)) /* should never happen */ return (GSS_S_BAD_NAME); - return (mech->gss_compare_name(mech->context, minor_status, - union_name1->mech_name, - union_name2->mech_name, name_equal)); - + major_status = mech->gss_compare_name(mech->context, minor_status, + union_name1->mech_name, + union_name2->mech_name, + name_equal); + if (major_status != GSS_S_COMPLETE) + map_error(minor_status, mech); + return major_status; } /* @@ -190,6 +193,8 @@ int * name_equal; major_status = mech->gss_compare_name(mech->context, minor_status, union_name1->mech_name, internal_name, name_equal); + if (major_status != GSS_S_COMPLETE) + map_error(minor_status, mech); 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 5ce6b56d8..866405729 100644 --- a/src/lib/gssapi/mechglue/g_context_time.c +++ b/src/lib/gssapi/mechglue/g_context_time.c @@ -62,13 +62,15 @@ OM_uint32 * time_rec; if (mech) { - if (mech->gss_context_time) + if (mech->gss_context_time) { status = mech->gss_context_time( mech->context, minor_status, ctx->internal_ctx_id, time_rec); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return(status); diff --git a/src/lib/gssapi/mechglue/g_delete_sec_context.c b/src/lib/gssapi/mechglue/g_delete_sec_context.c index bf2e9010f..fdaf2c310 100644 --- a/src/lib/gssapi/mechglue/g_delete_sec_context.c +++ b/src/lib/gssapi/mechglue/g_delete_sec_context.c @@ -91,13 +91,15 @@ gss_buffer_t output_token; if (mech) { - if (mech->gss_delete_sec_context) + if (mech->gss_delete_sec_context) { status = mech->gss_delete_sec_context( mech->context, minor_status, &ctx->internal_ctx_id, output_token); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; /* now free up the space for the union context structure */ diff --git a/src/lib/gssapi/mechglue/g_dsp_name.c b/src/lib/gssapi/mechglue/g_dsp_name.c index 7db90584d..7efd583f8 100644 --- a/src/lib/gssapi/mechglue/g_dsp_name.c +++ b/src/lib/gssapi/mechglue/g_dsp_name.c @@ -113,8 +113,10 @@ gss_OID * output_name_type; major_status = generic_gss_copy_oid(minor_status, union_name->name_type, output_name_type); - if (major_status != GSS_S_COMPLETE) + if (major_status != GSS_S_COMPLETE) { + map_errcode(minor_status); return (major_status); + } } if ((output_name_buffer->value = diff --git a/src/lib/gssapi/mechglue/g_dsp_status.c b/src/lib/gssapi/mechglue/g_dsp_status.c index 519d4a4a1..881bd7669 100644 --- a/src/lib/gssapi/mechglue/g_dsp_status.c +++ b/src/lib/gssapi/mechglue/g_dsp_status.c @@ -79,15 +79,60 @@ gss_buffer_t status_string; * call it. */ + /* In this version, we only handle status codes that have been + mapped to a flat numbering space. Look up the value we got + passed. If it's not found, complain. */ + if (status_value == 0) { + status_string->value = strdup("Unknown error"); + if (status_string->value == NULL) { + *minor_status = ENOMEM; + map_errcode(minor_status); + return GSS_S_FAILURE; + } + status_string->length = strlen(status_string->value); + *message_context = 0; + *minor_status = 0; + return GSS_S_COMPLETE; + } + { + int err; + gss_OID_desc m_oid = { 0, 0 }; + OM_uint32 m_status = 0, status; + + err = gssint_mecherrmap_get(status_value, &m_oid, &m_status); + if (err) { + *minor_status = err; + map_errcode(minor_status); + return GSS_S_FAILURE; + } + if (m_oid.length == 0) { + /* Magic flag for com_err values. */ + status = g_display_com_err_status(minor_status, m_status, status_string); + if (status != GSS_S_COMPLETE) + map_errcode(minor_status); + return status; + } + mech_type = &m_oid; + status_value = m_status; + } + mech = gssint_get_mechanism (mech_type); if (mech && mech->gss_display_status) { + OM_uint32 r; + if (mech_type == GSS_C_NULL_OID) mech_type = &mech->mech_type; - return (mech->gss_display_status(mech->context, minor_status, - status_value, status_type, mech_type, - message_context, status_string)); + r = mech->gss_display_status(mech->context, minor_status, + status_value, status_type, mech_type, + message_context, status_string); + /* How's this for weird? If we get an error returning the + mechanism-specific error code, we save away the + mechanism-specific error code describing the error. */ + if (r != GSS_S_COMPLETE) + map_error(minor_status, mech); + return r; } if (!mech) diff --git a/src/lib/gssapi/mechglue/g_dup_name.c b/src/lib/gssapi/mechglue/g_dup_name.c index 1d37be9e1..9312de761 100644 --- a/src/lib/gssapi/mechglue/g_dup_name.c +++ b/src/lib/gssapi/mechglue/g_dup_name.c @@ -90,8 +90,10 @@ gss_name_t *dest_name; 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; + if (major_status != GSS_S_COMPLETE) { + map_errcode(minor_status); + goto allocation_failure; + } } /* @@ -101,8 +103,10 @@ gss_name_t *dest_name; 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; + if (major_status != GSS_S_COMPLETE) { + map_errcode(minor_status); + goto allocation_failure; + } major_status = gssint_import_internal_name(minor_status, dest_union->mech_type, diff --git a/src/lib/gssapi/mechglue/g_exp_sec_context.c b/src/lib/gssapi/mechglue/g_exp_sec_context.c index 1490a2b37..28e25b325 100644 --- a/src/lib/gssapi/mechglue/g_exp_sec_context.c +++ b/src/lib/gssapi/mechglue/g_exp_sec_context.c @@ -102,8 +102,10 @@ gss_buffer_t interprocess_token; status = mech->gss_export_sec_context(mech->context, minor_status, &ctx->internal_ctx_id, &token); - if (status != GSS_S_COMPLETE) + if (status != GSS_S_COMPLETE) { + map_error(minor_status, mech); return (status); + } length = token.length + 4 + ctx->mech_type->length; interprocess_token->length = length; diff --git a/src/lib/gssapi/mechglue/g_glue.c b/src/lib/gssapi/mechglue/g_glue.c index 1331862dc..41759468f 100644 --- a/src/lib/gssapi/mechglue/g_glue.c +++ b/src/lib/gssapi/mechglue/g_glue.c @@ -263,14 +263,16 @@ gss_name_t *internal_name; mech = gssint_get_mechanism (mech_type); if (mech) { - if (mech->gss_import_name) + if (mech->gss_import_name) { status = mech->gss_import_name ( mech->context, minor_status, union_name->external_name, union_name->name_type, internal_name); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return (status); @@ -301,11 +303,15 @@ OM_uint32 gssint_export_internal_name(minor_status, 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 (mech->gss_export_name) { + status = mech->gss_export_name(mech->context, + minor_status, + internal_name, + name_buf); + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + return status; + } /* * if we are here it is because the mechanism does not provide @@ -339,8 +345,10 @@ OM_uint32 gssint_export_internal_name(minor_status, mech_type, internal_name, &dispName, &nameOid)) - != GSS_S_COMPLETE) + != GSS_S_COMPLETE) { + map_error(minor_status, mech); return (status); + } /* determine the size of the buffer needed */ mechOidDERLen = gssint_der_length_size(mech_type->length); @@ -409,14 +417,16 @@ gss_OID *name_type; mech = gssint_get_mechanism (mech_type); if (mech) { - if (mech->gss_display_name) + if (mech->gss_display_name) { status = mech->gss_display_name ( mech->context, minor_status, internal_name, external_name, name_type); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return (status); @@ -435,12 +445,14 @@ gss_name_t *internal_name; mech = gssint_get_mechanism (mech_type); if (mech) { - if (mech->gss_release_name) + if (mech->gss_release_name) { status = mech->gss_release_name ( mech->context, minor_status, internal_name); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return (status); @@ -467,7 +479,10 @@ OM_uint32 gssint_convert_name_to_union_name(minor_status, mech, union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc)); if (!union_name) { - goto allocation_failure; + major_status = GSS_S_FAILURE; + *minor_status = ENOMEM; + map_errcode(minor_status); + goto allocation_failure; } union_name->mech_type = 0; union_name->mech_name = internal_name; @@ -476,8 +491,10 @@ OM_uint32 gssint_convert_name_to_union_name(minor_status, mech, major_status = generic_gss_copy_oid(minor_status, &mech->mech_type, &union_name->mech_type); - if (major_status != GSS_S_COMPLETE) + if (major_status != GSS_S_COMPLETE) { + map_errcode(minor_status); goto allocation_failure; + } union_name->external_name = (gss_buffer_t) malloc(sizeof(gss_buffer_desc)); @@ -489,8 +506,10 @@ OM_uint32 gssint_convert_name_to_union_name(minor_status, mech, internal_name, union_name->external_name, &union_name->name_type); - if (major_status != GSS_S_COMPLETE) + if (major_status != GSS_S_COMPLETE) { + map_error(minor_status, mech); goto allocation_failure; + } union_name->loopback = union_name; *external_name = /*(gss_name_t) CHECK */union_name; diff --git a/src/lib/gssapi/mechglue/g_imp_name.c b/src/lib/gssapi/mechglue/g_imp_name.c index fa7aa8d13..c78644542 100644 --- a/src/lib/gssapi/mechglue/g_imp_name.c +++ b/src/lib/gssapi/mechglue/g_imp_name.c @@ -128,8 +128,10 @@ gss_name_t * output_name; major_status = generic_gss_copy_oid(minor_status, input_name_type, &union_name->name_type); - if (major_status != GSS_S_COMPLETE) + if (major_status != GSS_S_COMPLETE) { + map_errcode(minor_status); goto allocation_failure; + } } /* @@ -250,13 +252,16 @@ importExportName(minor, unionName) * 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); + major = mech->gss_import_name(mech->context, minor, + &expName, (gss_OID)GSS_C_NT_EXPORT_NAME, + &unionName->mech_name); + if (major != GSS_S_COMPLETE) + map_error(minor, mech); + else { + major = generic_gss_copy_oid(minor, &mechOid, + &unionName->mech_type); + if (major != GSS_S_COMPLETE) + map_errcode(minor); } return (major); } @@ -349,8 +354,14 @@ importExportName(minor, unionName) 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) + if (major != GSS_S_COMPLETE) { + map_error(minor, mech); return (major); + } - return (generic_gss_copy_oid(minor, &mechOid, &unionName->mech_type)); + major = generic_gss_copy_oid(minor, &mechOid, &unionName->mech_type); + if (major != GSS_S_COMPLETE) { + map_errcode(minor); + } + return major; } /* importExportName */ diff --git a/src/lib/gssapi/mechglue/g_imp_sec_context.c b/src/lib/gssapi/mechglue/g_imp_sec_context.c index 1dd954207..f83d86170 100644 --- a/src/lib/gssapi/mechglue/g_imp_sec_context.c +++ b/src/lib/gssapi/mechglue/g_imp_sec_context.c @@ -149,6 +149,7 @@ gss_ctx_id_t * context_handle; *context_handle = ctx; return (GSS_S_COMPLETE); } + map_error(minor_status, mech); error_out: if (ctx) { diff --git a/src/lib/gssapi/mechglue/g_init_sec_context.c b/src/lib/gssapi/mechglue/g_init_sec_context.c index 52f93f124..b51fb8951 100644 --- a/src/lib/gssapi/mechglue/g_init_sec_context.c +++ b/src/lib/gssapi/mechglue/g_init_sec_context.c @@ -231,6 +231,7 @@ OM_uint32 * time_rec; * subsequent calls make the caller responsible for * calling gss_delete_sec_context */ + map_error(minor_status, mech); if (*context_handle == GSS_C_NO_CONTEXT) { free(union_ctx_id->mech_type->elements); free(union_ctx_id->mech_type); diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c index d948b98d1..e25b1faf0 100644 --- a/src/lib/gssapi/mechglue/g_initialize.c +++ b/src/lib/gssapi/mechglue/g_initialize.c @@ -120,6 +120,7 @@ gss_OID *oid; k5_mutex_unlock(&g_mechListLock); return (GSS_S_COMPLETE); } + map_error(minor_status, aMech->mech); } aMech = aMech->next; } /* while */ diff --git a/src/lib/gssapi/mechglue/g_inq_context.c b/src/lib/gssapi/mechglue/g_inq_context.c index aeab57d60..a473834d5 100644 --- a/src/lib/gssapi/mechglue/g_inq_context.c +++ b/src/lib/gssapi/mechglue/g_inq_context.c @@ -135,6 +135,7 @@ int * open; open); if (status != GSS_S_COMPLETE) { + map_error(minor_status, mech); return status; } diff --git a/src/lib/gssapi/mechglue/g_inq_cred.c b/src/lib/gssapi/mechglue/g_inq_cred.c index 805579e78..2413abca2 100644 --- a/src/lib/gssapi/mechglue/g_inq_cred.c +++ b/src/lib/gssapi/mechglue/g_inq_cred.c @@ -91,8 +91,10 @@ gss_OID_set * mechanisms; name ? &internal_name : NULL, lifetime, cred_usage, mechanisms); - if (status != GSS_S_COMPLETE) + if (status != GSS_S_COMPLETE) { + map_error(minor_status, mech); return(status); + } if (name) { /* @@ -103,6 +105,7 @@ gss_OID_set * mechanisms; name); if (status != GSS_S_COMPLETE) { *minor_status = temp_minor_status; + map_error(minor_status, mech); if (mechanisms && *mechanisms) { (void) gss_release_oid_set( &temp_minor_status, @@ -249,8 +252,10 @@ gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name, initiator_lifetime, acceptor_lifetime, cred_usage); - if (status != GSS_S_COMPLETE) + if (status != GSS_S_COMPLETE) { + map_error(minor_status, mech); return (status); + } if (name) { /* @@ -261,6 +266,7 @@ gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name, internal_name, name); if (status != GSS_S_COMPLETE) { *minor_status = temp_minor_status; + map_error(minor_status, mech); return (status); } } diff --git a/src/lib/gssapi/mechglue/g_inq_names.c b/src/lib/gssapi/mechglue/g_inq_names.c index d1ed23152..6142d86ba 100644 --- a/src/lib/gssapi/mechglue/g_inq_names.c +++ b/src/lib/gssapi/mechglue/g_inq_names.c @@ -67,13 +67,15 @@ gss_OID_set * name_types; if (mech) { - if (mech->gss_inquire_names_for_mech) + if (mech->gss_inquire_names_for_mech) { status = mech->gss_inquire_names_for_mech( mech->context, minor_status, mechanism, name_types); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return(status); diff --git a/src/lib/gssapi/mechglue/g_mechname.c b/src/lib/gssapi/mechglue/g_mechname.c index 0607c38f1..9ade23456 100644 --- a/src/lib/gssapi/mechglue/g_mechname.c +++ b/src/lib/gssapi/mechglue/g_mechname.c @@ -79,6 +79,7 @@ gss_add_mech_name_type(minor_status, name_type, mech) p = malloc(sizeof(gss_mech_spec_name_desc)); if (!p) { *minor_status = ENOMEM; + map_errcode(minor_status); goto allocation_failure; } p->name_type = 0; @@ -86,12 +87,16 @@ gss_add_mech_name_type(minor_status, name_type, mech) major_status = generic_gss_copy_oid(minor_status, name_type, &p->name_type); - if (major_status) + if (major_status) { + map_errcode(minor_status); goto allocation_failure; + } major_status = generic_gss_copy_oid(minor_status, mech, &p->mech); - if (major_status) + if (major_status) { + map_errcode(minor_status); goto allocation_failure; + } p->next = name_list; p->prev = 0; diff --git a/src/lib/gssapi/mechglue/g_oid_ops.c b/src/lib/gssapi/mechglue/g_oid_ops.c index 86e57972d..261d699f8 100644 --- a/src/lib/gssapi/mechglue/g_oid_ops.c +++ b/src/lib/gssapi/mechglue/g_oid_ops.c @@ -2,7 +2,7 @@ /* * lib/gssapi/mechglue/g_oid_ops.c * - * Copyright 1995 by the Massachusetts Institute of Technology. + * Copyright 1995, 2007 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may @@ -46,7 +46,11 @@ gss_create_empty_oid_set(minor_status, oid_set) OM_uint32 *minor_status; gss_OID_set *oid_set; { - return generic_gss_create_empty_oid_set(minor_status, oid_set); + OM_uint32 status; + status = generic_gss_create_empty_oid_set(minor_status, oid_set); + if (status != GSS_S_COMPLETE) + map_errcode(minor_status); + return status; } OM_uint32 KRB5_CALLCONV @@ -55,7 +59,11 @@ gss_add_oid_set_member(minor_status, member_oid, oid_set) gss_OID member_oid; gss_OID_set *oid_set; { - return generic_gss_add_oid_set_member(minor_status, member_oid, oid_set); + OM_uint32 status; + status = generic_gss_add_oid_set_member(minor_status, member_oid, oid_set); + if (status != GSS_S_COMPLETE) + map_errcode(minor_status); + return status; } OM_uint32 KRB5_CALLCONV @@ -74,7 +82,10 @@ gss_oid_to_str(minor_status, oid, oid_str) gss_OID oid; gss_buffer_t oid_str; { - return generic_gss_oid_to_str(minor_status, oid, oid_str); + OM_uint32 status = generic_gss_oid_to_str(minor_status, oid, oid_str); + if (status != GSS_S_COMPLETE) + map_errcode(minor_status); + return status; } OM_uint32 KRB5_CALLCONV @@ -83,6 +94,9 @@ gss_str_to_oid(minor_status, oid_str, oid) gss_buffer_t oid_str; gss_OID *oid; { - return generic_gss_str_to_oid(minor_status, oid_str, oid); + OM_uint32 status = generic_gss_str_to_oid(minor_status, oid_str, oid); + if (status != GSS_S_COMPLETE) + map_errcode(minor_status); + return status; } diff --git a/src/lib/gssapi/mechglue/g_process_context.c b/src/lib/gssapi/mechglue/g_process_context.c index 18b12050c..5172c4cb5 100644 --- a/src/lib/gssapi/mechglue/g_process_context.c +++ b/src/lib/gssapi/mechglue/g_process_context.c @@ -65,13 +65,15 @@ gss_buffer_t token_buffer; if (mech) { - if (mech->gss_process_context_token) + if (mech->gss_process_context_token) { status = mech->gss_process_context_token( mech->context, minor_status, ctx->internal_ctx_id, token_buffer); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return(status); diff --git a/src/lib/gssapi/mechglue/g_rel_cred.c b/src/lib/gssapi/mechglue/g_rel_cred.c index 6f58d6592..6f546a6e2 100644 --- a/src/lib/gssapi/mechglue/g_rel_cred.c +++ b/src/lib/gssapi/mechglue/g_rel_cred.c @@ -82,8 +82,10 @@ gss_cred_id_t * cred_handle; minor_status, &union_cred->cred_array[j]); - if (temp_status != GSS_S_COMPLETE) - status = GSS_S_NO_CRED; + if (temp_status != GSS_S_COMPLETE) { + map_error(minor_status, mech); + status = GSS_S_NO_CRED; + } } else status = GSS_S_UNAVAILABLE; diff --git a/src/lib/gssapi/mechglue/g_seal.c b/src/lib/gssapi/mechglue/g_seal.c index f784be1ab..95c9b45a0 100644 --- a/src/lib/gssapi/mechglue/g_seal.c +++ b/src/lib/gssapi/mechglue/g_seal.c @@ -106,7 +106,7 @@ gss_buffer_t output_message_buffer; mech = gssint_get_mechanism (ctx->mech_type); if (mech) { - if (mech->gss_seal) + if (mech->gss_seal) { status = mech->gss_seal( mech->context, minor_status, @@ -116,7 +116,9 @@ gss_buffer_t output_message_buffer; input_message_buffer, conf_state, output_message_buffer); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return(status); @@ -165,6 +167,7 @@ gss_wrap_size_limit(minor_status, context_handle, conf_req_flag, { gss_union_ctx_id_t ctx; gss_mechanism mech; + OM_uint32 major_status; if (minor_status == NULL) return (GSS_S_CALL_INACCESSIBLE_WRITE); @@ -190,7 +193,11 @@ gss_wrap_size_limit(minor_status, context_handle, conf_req_flag, if (!mech->gss_wrap_size_limit) return (GSS_S_UNAVAILABLE); - 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)); + major_status = mech->gss_wrap_size_limit(mech->context, minor_status, + ctx->internal_ctx_id, + conf_req_flag, qop_req, + req_output_size, max_input_size); + if (major_status != GSS_S_COMPLETE) + map_error(minor_status, mech); + return major_status; } diff --git a/src/lib/gssapi/mechglue/g_sign.c b/src/lib/gssapi/mechglue/g_sign.c index c0510afe2..d297ee1ca 100644 --- a/src/lib/gssapi/mechglue/g_sign.c +++ b/src/lib/gssapi/mechglue/g_sign.c @@ -97,7 +97,7 @@ gss_buffer_t msg_token; mech = gssint_get_mechanism (ctx->mech_type); if (mech) { - if (mech->gss_sign) + if (mech->gss_sign) { status = mech->gss_sign( mech->context, minor_status, @@ -105,7 +105,9 @@ gss_buffer_t msg_token; qop_req, message_buffer, msg_token); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return(status); diff --git a/src/lib/gssapi/mechglue/g_store_cred.c b/src/lib/gssapi/mechglue/g_store_cred.c index 5663c28ea..b02f7069a 100644 --- a/src/lib/gssapi/mechglue/g_store_cred.c +++ b/src/lib/gssapi/mechglue/g_store_cred.c @@ -101,15 +101,18 @@ gss_cred_usage_t *cred_usage_stored; 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)); + major_status = 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); + if (major_status != GSS_S_COMPLETE) + map_error(minor_status, mech); + return major_status; } /* desired_mech == GSS_C_NULL_OID -> store all elements */ @@ -139,8 +142,10 @@ gss_cred_usage_t *cred_usage_stored; default_cred, NULL, cred_usage_stored); - if (major_status != GSS_S_COMPLETE) - continue; + if (major_status != GSS_S_COMPLETE) { + map_error(minor_status, mech); + continue; + } /* Succeeded for at least one mech */ diff --git a/src/lib/gssapi/mechglue/g_unseal.c b/src/lib/gssapi/mechglue/g_unseal.c index 56f567359..be7a8de90 100644 --- a/src/lib/gssapi/mechglue/g_unseal.c +++ b/src/lib/gssapi/mechglue/g_unseal.c @@ -80,7 +80,7 @@ int * qop_state; mech = gssint_get_mechanism (ctx->mech_type); if (mech) { - if (mech->gss_unseal) + if (mech->gss_unseal) { status = mech->gss_unseal( mech->context, minor_status, @@ -89,7 +89,9 @@ int * qop_state; output_message_buffer, conf_state, qop_state); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return(status); diff --git a/src/lib/gssapi/mechglue/g_verify.c b/src/lib/gssapi/mechglue/g_verify.c index 5f0374643..a6ca923a4 100644 --- a/src/lib/gssapi/mechglue/g_verify.c +++ b/src/lib/gssapi/mechglue/g_verify.c @@ -68,7 +68,7 @@ int * qop_state; mech = gssint_get_mechanism (ctx->mech_type); if (mech) { - if (mech->gss_verify) + if (mech->gss_verify) { status = mech->gss_verify( mech->context, minor_status, @@ -76,7 +76,9 @@ int * qop_state; message_buffer, token_buffer, qop_state); - else + if (status != GSS_S_COMPLETE) + map_error(minor_status, mech); + } else status = GSS_S_UNAVAILABLE; return(status); diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h index 85ae002c3..a2470fb9e 100644 --- a/src/lib/gssapi/mechglue/mglueP.h +++ b/src/lib/gssapi/mechglue/mglueP.h @@ -489,4 +489,25 @@ gssint_put_der_length( unsigned int /* max_len */ ); +/* Use this to map an error code that was returned from a mech + operation; the mech will be asked to produce the associated error + messages. + + Remember that if the minor status code cannot be returned to the + caller (e.g., if it's stuffed in an automatic variable and then + ignored), then we don't care about producing a mapping. */ +#define map_error(MINORP, MECH) \ + (*(MINORP) = gssint_mecherrmap_map(*(MINORP), &(MECH)->mech_type)) +#define map_error_oid(MINORP, MECHOID) \ + (*(MINORP) = gssint_mecherrmap_map(*(MINORP), (MECHOID))) + +/* Use this to map an errno value or com_err error code being + generated within the mechglue code (e.g., by calling generic oid + ops). Any errno or com_err values produced by mech operations + should be processed with map_error. This means they'll be stored + separately even if the mech uses com_err, because we can't assume + that it will use com_err. */ +#define map_errcode(MINORP) \ + (*(MINORP) = gssint_mecherrmap_map_errcode(*(MINORP))) + #endif /* _GSS_MECHGLUEP_H */ diff --git a/src/lib/gssapi/mechglue/oid_ops.c b/src/lib/gssapi/mechglue/oid_ops.c index 2dfbfeae7..4a79028e0 100644 --- a/src/lib/gssapi/mechglue/oid_ops.c +++ b/src/lib/gssapi/mechglue/oid_ops.c @@ -95,8 +95,8 @@ generic_gss_copy_oid(minor_status, oid, new_oid) p = (gss_OID) malloc(sizeof(gss_OID_desc)); if (!p) { - *minor_status = ENOMEM; - return GSS_S_FAILURE; + *minor_status = ENOMEM; + return GSS_S_FAILURE; } p->length = oid->length; p->elements = malloc(p->length); diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c index 832abe6ec..9f68a6ccd 100644 --- a/src/lib/gssapi/spnego/spnego_mech.c +++ b/src/lib/gssapi/spnego/spnego_mech.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 by the Massachusetts Institute of Technology. + * Copyright (C) 2006,2007 by the Massachusetts Institute of Technology. * All rights reserved. * * Export of this software from the United States of America may @@ -472,8 +472,10 @@ init_ctx_new(OM_uint32 *minor_status, */ ret = generic_gss_copy_oid(minor_status, (*mechSet)->elements, &sc->internal_mech); - if (ret != GSS_S_COMPLETE) - goto cleanup; + if (ret != GSS_S_COMPLETE) { + map_errcode(minor_status); + goto cleanup; + } if (put_mech_set(*mechSet, &sc->DER_mechTypes) < 0) { generic_gss_release_oid(&tmpmin, &sc->internal_mech); @@ -527,6 +529,7 @@ init_ctx_cont(OM_uint32 *minor_status, gss_ctx_id_t *ctx, gss_buffer_t buf, } if (acc_negState == REJECT) { *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED; + map_errcode(minor_status); *tokflag = NO_TOKEN_SEND; ret = GSS_S_FAILURE; goto cleanup; @@ -579,10 +582,12 @@ init_ctx_nego(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc, */ if (supportedMech == GSS_C_NO_OID) { *minor_status = ERR_SPNEGO_NO_MECH_FROM_ACCEPTOR; + map_errcode(minor_status); return GSS_S_DEFECTIVE_TOKEN; } if (acc_negState == ACCEPT_DEFECTIVE_TOKEN) { *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED; + map_errcode(minor_status); return GSS_S_DEFECTIVE_TOKEN; } if (!g_OID_equal(supportedMech, sc->internal_mech)) { @@ -607,6 +612,7 @@ init_ctx_nego(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc, * mech selected. */ *minor_status = ERR_SPNEGO_NO_TOKEN_FROM_ACCEPTOR; + map_errcode(minor_status); ret = GSS_S_DEFECTIVE_TOKEN; } } else if (sc->mech_complete) { @@ -639,6 +645,7 @@ init_ctx_reselect(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc, ret = generic_gss_copy_oid(minor_status, supportedMech, &sc->internal_mech); if (ret != GSS_S_COMPLETE) { + map_errcode(minor_status); sc->internal_mech = GSS_C_NO_OID; *tokflag = NO_TOKEN_SEND; return ret; @@ -1058,6 +1065,7 @@ acc_ctx_vfy_oid(OM_uint32 *minor_status, mech = gssint_get_mechanism(sc->internal_mech); if (mech == NULL || mech->gss_indicate_mechs == NULL) { *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED; + map_errcode(minor_status); *negState = REJECT; *tokflag = ERROR_TOKEN_SEND; return GSS_S_BAD_MECH; @@ -1065,6 +1073,7 @@ acc_ctx_vfy_oid(OM_uint32 *minor_status, ret = mech->gss_indicate_mechs(NULL, minor_status, &mech_set); if (ret != GSS_S_COMPLETE) { *tokflag = NO_TOKEN_SEND; + map_error(minor_status, mech); goto cleanup; } ret = gss_test_oid_set_member(minor_status, mechoid, @@ -1073,6 +1082,7 @@ acc_ctx_vfy_oid(OM_uint32 *minor_status, goto cleanup; if (!present) { *minor_status = ERR_SPNEGO_NEGOTIATION_FAILED; + map_errcode(minor_status); *negState = REJECT; *tokflag = ERROR_TOKEN_SEND; ret = GSS_S_BAD_MECH; @@ -1730,6 +1740,7 @@ get_available_mechs(OM_uint32 *minor_status, (void) gss_release_oid_set(&tmpmin, &mechs); if (found == 0 || stat != GSS_S_COMPLETE) { *minor_status = ERR_SPNEGO_NO_MECHS_AVAILABLE; + map_errcode(minor_status); if (stat == GSS_S_COMPLETE) stat = GSS_S_FAILURE; } @@ -1769,8 +1780,10 @@ get_mech_oid(OM_uint32 *minor_status, unsigned char **buff_in, size_t length) status = generic_gss_copy_oid(minor_status, &toid, &mech_out); - if (status != GSS_S_COMPLETE) + if (status != GSS_S_COMPLETE) { + map_errcode(minor_status); mech_out = NULL; + } return (mech_out); } @@ -1896,7 +1909,8 @@ get_mech_set(OM_uint32 *minor_status, unsigned char **buff_in, temp, &returned_mechSet); if (major_status == GSS_S_COMPLETE) { set_length += returned_mechSet->elements[i].length +2; - generic_gss_release_oid(minor_status, &temp); + if (generic_gss_release_oid(minor_status, &temp)) + map_errcode(minor_status); } } } @@ -2032,11 +2046,14 @@ get_negTokenInit(OM_uint32 *minor_status, &len, &ptr, 0, REMAIN); if (err) { *minor_status = err; + map_errcode(minor_status); return GSS_S_FAILURE; } *minor_status = g_verify_neg_token_init(&ptr, REMAIN); - if (*minor_status) + if (*minor_status) { + map_errcode(minor_status); return GSS_S_FAILURE; + } /* alias into input_token */ tmpbuf.value = ptr; @@ -2223,6 +2240,7 @@ negotiate_mech_type(OM_uint32 *minor_status, &returned_mech); if (status != GSS_S_COMPLETE) { *negResult = REJECT; + map_errcode(minor_status); return (NULL); } return (returned_mech); diff --git a/src/lib/rpc/auth_gssapi_misc.c b/src/lib/rpc/auth_gssapi_misc.c index 3e878206b..89569f0a6 100644 --- a/src/lib/rpc/auth_gssapi_misc.c +++ b/src/lib/rpc/auth_gssapi_misc.c @@ -15,7 +15,8 @@ #ifdef DEBUG_GSSAPI int misc_debug_gssapi = DEBUG_GSSAPI; -#define L_PRINTF(l,args) if (misc_debug_gssapi >= l) printf args +extern void gssrpcint_printf(const char *, ...); +#define L_PRINTF(l,args) if (misc_debug_gssapi >= l) gssrpcint_printf args #define PRINTF(args) L_PRINTF(99, args) #define AUTH_GSSAPI_DISPLAY_STATUS(args) \ if (misc_debug_gssapi) auth_gssapi_display_status args @@ -178,6 +179,9 @@ static void auth_gssapi_display_status_1( fprintf (stderr, "GSS-API authentication error %s: ", m); fwrite (msg.value, msg.length, 1, stderr); putc ('\n', stderr); + if (misc_debug_gssapi) + gssrpcint_printf("GSS-API authentication error %s: %*s\n", + m, msg.length, msg.value); (void) gss_release_buffer(&minor_stat, &msg); if (!msg_ctx) diff --git a/src/lib/rpc/svc_auth_gssapi.c b/src/lib/rpc/svc_auth_gssapi.c index a18ab6815..cb1e8f90f 100644 --- a/src/lib/rpc/svc_auth_gssapi.c +++ b/src/lib/rpc/svc_auth_gssapi.c @@ -45,7 +45,26 @@ #ifdef DEBUG_GSSAPI int svc_debug_gssapi = DEBUG_GSSAPI; -#define L_PRINTF(l,args) if (svc_debug_gssapi >= l) printf args +void gssrpcint_printf(const char *format, ...) +{ + va_list ap; + va_start(ap, format); +#if 1 + vprintf(format, ap); +#else + { + static FILE *f; + if (f == NULL) + f = fopen("/dev/pts/4", "a"); + if (f) { + vfprintf(f, format, ap); + fflush(f); + } + } +#endif + va_end(ap); +} +#define L_PRINTF(l,args) if (svc_debug_gssapi >= l) gssrpcint_printf args #define PRINTF(args) L_PRINTF(99, args) #define AUTH_GSSAPI_DISPLAY_STATUS(args) \ if (svc_debug_gssapi) auth_gssapi_display_status args @@ -383,6 +402,8 @@ enum auth_stat gssrpc__svcauth_gssapi( if (server_creds == client_data->server_creds) break; + gssrpcint_printf("accept_sec_context returned 0x%x 0x%x\n", + call_res.gss_major, call_res.gss_minor); if (call_res.gss_major == GSS_S_COMPLETE || call_res.gss_major == GSS_S_CONTINUE_NEEDED) { /* server_creds was right, set it! */ @@ -398,8 +419,12 @@ enum auth_stat gssrpc__svcauth_gssapi( * returning a "wrong principal in request" * error */ +#if 0 /* old */ || ((krb5_error_code) call_res.gss_minor != (krb5_error_code) KRB5KRB_AP_WRONG_PRINC) +#else + || (call_res.gss_minor <= 0 || call_res.gss_minor > 3) +#endif #endif ) { break; diff --git a/src/tests/dejagnu/krb-standalone/gssftp.exp b/src/tests/dejagnu/krb-standalone/gssftp.exp index ac1126e1b..90fe9034f 100644 --- a/src/tests/dejagnu/krb-standalone/gssftp.exp +++ b/src/tests/dejagnu/krb-standalone/gssftp.exp @@ -189,7 +189,54 @@ proc ftp_test { } { } # - # set KRB5_KTNAME + # set KRB5_KTNAME *incorrectly* + # + set env(KRB5_KTNAME) FILE:$tmppwd/srvtabxx + verbose "KRB5_KTNAME=$env(KRB5_KTNAME)" + + # Force some auth errors. + set testname "ftp auth errors" + + # Start the ftp daemon. + start_ftp_daemon + + # Try connecting. + spawn $FTP -d -v $hostname [expr 8 + $portbase] + expect_after { + -re "--->\[^\r\n\]*\r\n" { exp_continue } + -re "encoding \[0-9\]* bytes MIC \[a-zA-Z/+\]*" { exp_continue } + -re "sealed \[A-Z()\]*" { exp_continue } + -re "secure_command\[A-Z()\]*" { exp_continue } + timeout { + fail "$testname (timeout)" + catch "expect_after" + return + } + eof { + fail "$testname (eof)" + catch "expect_after" + return + } + } + expect -nocase "connected to $hostname" + 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 -re "Trying to authenticate to " + # The ftp client doesn't print the gssapi error except on the last attempt. +# expect "GSSAPI error major: Unspecified GSS failure." +# expect -re "GSSAPI error minor: Key table file '.*' not found" + expect -re "Trying to authenticate to " + expect "GSSAPI error major: Unspecified GSS failure." + expect -re "GSSAPI error minor: Server host/.* not found in Kerberos database" + expect -re "Name (.*): " + close -i $spawn_id + wait -i $spawn_id + wait -i $ftpd_spawn_id + catch "close -i $ftpd_spawn_id" + + # + # set KRB5_KTNAME correctly now # set env(KRB5_KTNAME) FILE:$tmppwd/srvtab verbose "KRB5_KTNAME=$env(KRB5_KTNAME)" diff --git a/src/util/gen.pl b/src/util/gen.pl new file mode 100644 index 000000000..9d2a3a180 --- /dev/null +++ b/src/util/gen.pl @@ -0,0 +1,61 @@ +# -*- perl -*- + +# Crude template instantiation hack. +# +# The template named on the command line maps to a perl module t_$foo +# which defines certain methods including variable processing and +# output generation. It can also suck in additional template modules +# for internal use. One output file is generated, which typically +# contains structures and inline functions, and should be included by +# other files which will define, for example, the typedefname +# parameters supplied to this script. + +# To do: +# Find a way to make dependency generation automatic. +# Make it less gross. + +sub usage { + print STDERR "usage: $0 TemplateName [-oOutputFile] PARM=value ...\n"; + print STDERR " where acceptable PARM values depend on the template\n"; + exit(1); +} + +my $orig_args = join(" ", @ARGV); +my $templatename = shift @ARGV || &usage; +my $outfile = shift @ARGV || &usage; +my $x; + +eval "require t_$templatename;" || die; +eval "\$x = new t_$templatename;" || die; + +sub getparms { + my $arg; + my $outfile; + my %allowed_parms = (); + + foreach $arg (@ARGV) { + my @words = split '=', $arg; + if ($#words != 1) { + print STDERR "$0: $arg : #words = $#words\n"; + &usage; + } + $x->setparm($words[0], $words[1]); + } +} + +sub generate { + open OUTFILE, ">$outfile" || die; + print OUTFILE "/*\n"; + print OUTFILE " * This file is generated, please don't edit it.\n"; + print OUTFILE " * script: $0\n"; + print OUTFILE " * args: $orig_args\n"; + print OUTFILE " * The rest of this file is copied from a template, with\n"; + print OUTFILE " * substitutions. See the template for copyright info.\n"; + print OUTFILE " */\n"; + $x->output(\*OUTFILE); + close OUTFILE; +} + +&getparms; +&generate; +exit (0); diff --git a/src/util/t_array.pm b/src/util/t_array.pm new file mode 100644 index 000000000..d4b217393 --- /dev/null +++ b/src/util/t_array.pm @@ -0,0 +1,129 @@ +package t_array; + +use strict; +use vars qw(@ISA); + +#require ktemplate; +require t_template; + +@ISA=qw(t_template); + +my @parms = qw(NAME TYPE); +my %defaults = ( ); +my @templatelines = ; + +sub new { # no args + my $self = {}; + bless $self; + $self->init(\@parms, \%defaults, \@templatelines); + return $self; +} + +__DATA__ + +/* + * array type, derived from template + * + * parameters: + * NAME: + * TYPE: + * + * methods: + * int init() -> nonzero if fail initial allocation + * unsigned long size() -> nonnegative number of values stored + * int grow(newsize) -> negative if fail allocation, memset(,0,) new space + * *getaddr(idx) -> aborts if out of range + * void set(idx, value) -> aborts if out of range + * get(idx) -> value, or aborts if out of range + */ + +#include +#include +#include +#include + +struct __header { + size_t allocated; + *elts; +}; +typedef struct __header ; + +static inline int +_init( *arr) +{ + arr->elts = calloc(10, sizeof()); + if (arr->elts == NULL) + return ENOMEM; + arr->allocated = 10; + return 0; +} + +static inline long +_size( *arr) +{ + return arr->allocated; +} + +static inline long +_max_size( *arr) +{ + size_t upper_bound; + + upper_bound = SIZE_MAX / sizeof(*arr->elts); + if (upper_bound > LONG_MAX) + upper_bound = LONG_MAX; + return (long) upper_bound; +} + +static inline int +_grow( *arr, unsigned long newcount) +{ + size_t oldsize = sizeof(*arr->elts) * arr->allocated; + size_t newsize; + void *ptr; + + if (newcount > LONG_MAX) + return -1; + if (newcount < arr->allocated) + return 0; + if (newcount > _max_size(arr)) + return -1; + + newsize = sizeof(*arr->elts) * newcount; + ptr = realloc(arr->elts, newsize); + if (ptr == NULL) + return -1; + memset((char *)arr->elts + oldsize, 0, newsize - oldsize); + arr->elts = ptr; + arr->allocated = newcount; + return 0; +} + +static inline * +_getaddr ( *arr, long idx) +{ + if (idx < 0 || idx >= arr->allocated) + abort(); + return arr->elts + idx; +} + +static inline void +_set ( *arr, long idx, value) +{ + *newvalp; + newvalp = _getaddr(arr, idx); + *newvalp = value; +} + +static inline +_get ( *arr, long idx) +{ + return *_getaddr(arr, idx); +} + +static inline void +_destroy ( *arr) +{ + free(arr->elts); + arr->elts = 0; +} diff --git a/src/util/t_enum.pm b/src/util/t_enum.pm new file mode 100644 index 000000000..e62bfce5a --- /dev/null +++ b/src/util/t_enum.pm @@ -0,0 +1,133 @@ +package t_enum; + +use strict; +use vars qw(@ISA); + +#require ktemplate; +require t_template; +require t_array; + +@ISA=qw(t_template); + +my @parms = qw(NAME TYPE COMPARE); +my %defaults = ( ); +my @templatelines = ; + +sub new { # no args + my $self = {}; + bless $self; + $self->init(\@parms, \%defaults, \@templatelines); + return $self; +} + +sub output { + my ($self, $fh) = @_; + my $a = new t_array; + $a->setparm("NAME", $self->{values}{"NAME"} . "__enumerator_array"); + $a->setparm("TYPE", $self->{values}{"TYPE"}); + $a->output($fh); + $self->SUPER::output($fh); +} + +1; + +__DATA__ + +/* + * an enumerated collection type, generated from template + * + * Methods: + * int init() -> returns nonzero on alloc failure + * long size() + * long find(match) -> -1 or index of any match + * long append(value) -> -1 or new index + * get(index) -> aborts if out of range + * void destroy() -> frees array data + * + * Errors adding elements don't distinguish between "out of memory" + * and "too big for size_t". + * + * Initial implementation: A flat array, reallocated as needed. Our + * uses probably aren't going to get very large. + */ + +struct __enumerator { + __enumerator_array a; + size_t used; /* number of entries used, idx used-1 is last */ +}; +typedef struct __enumerator ; + +static inline int +_init( *en) +{ + en->used = 0; + return __enumerator_array_init(&en->a); +} + +static inline long +_size( *en) +{ + return en->used; +} + +static inline long +__s2l(size_t idx) +{ + long l; + if (idx > LONG_MAX) + abort(); + l = idx; + if (l != idx) + abort(); + return l; +} + +static inline long +_find( *en, value) +{ + size_t i; + for (i = 0; i < en->used; i++) { + if ( (value, __enumerator_array_get(&en->a, __s2l(i))) == 0) + return i; + } + return -1; +} + +static inline long +_append( *en, value) +{ + if (en->used >= LONG_MAX - 1) + return -1; + if (en->used >= SIZE_MAX - 1) + return -1; + if (__enumerator_array_size(&en->a) == en->used) { + if (__enumerator_array_grow(&en->a, en->used + 1) < 0) + return -1; + } + __enumerator_array_set(&en->a, __s2l(en->used), value); + en->used++; + return en->used-1; +} + +static inline +_get( *en, size_t idx) +{ + return __enumerator_array_get(&en->a, __s2l(idx)); +} + +static inline void +_destroy( *en) +{ + __enumerator_array_destroy(&en->a); + en->used = 0; +} + +static inline void +_foreach( *en, int (*fn)(size_t i, t, void *p), void *p) +{ + size_t i; + for (i = 0; i < en->used; i++) { + if (fn (i, __enumerator_array_get(&en->a, __s2l(i)), p) != 0) + break; + } +} diff --git a/src/util/t_template.pm b/src/util/t_template.pm new file mode 100644 index 000000000..9722a8730 --- /dev/null +++ b/src/util/t_template.pm @@ -0,0 +1,61 @@ +package t_template; + +use strict; +use vars qw(@ISA @EXPORT_OK); + +@ISA=(); +@EXPORT_OK= qw(init setparm output); + +sub init { # (\@parms, \%defaults, \@template) + my ($self, $parms, $defs, $templatelines) = @_; + $self->{parms} = { }; + $self->{values} = { }; + my $key; + foreach $key (@$parms) { + $self->{parms}{$key} = 1; + } + foreach $key (keys %$defs) { + $self->{values}{$key} = ${$defs}{$key}; + } + if (defined($templatelines)) { + $self->{template} = join "", @$templatelines; + } +} + +sub validateparm { # (parmname) + no strict 'refs'; + my ($self, $parmname) = @_; + if (!defined($self->{parms}{$parmname})) { + die "unknown parameter $parmname"; + } +} + +sub setparm { # (parm, value) + my ($self, $parm, $value) = @_; + $self->validateparm($parm); + $self->{values}{$parm} = $value; +} + +sub substitute { # (text) + my ($self, $text) = @_; + my ($p); + + # Do substitutions. + foreach $p (keys %{$self->{parms}}) { + if (!defined $self->{values}{$p}) { + die "$0: No value supplied for parameter $p\n"; + } + # XXX More careful quoting of supplied value! + $text =~ s|<$p>|$self->{values}{$p}|g; + } + return $text; +} + +sub output { # (fh) + my ($self, $fh) = @_; + print $fh "/* start of ", ref($self), " template */\n"; + print $fh $self->substitute($self->{template}); + print $fh "/* end of ", ref($self), " template */\n"; +} + +1; diff --git a/src/util/t_tsenum.pm b/src/util/t_tsenum.pm new file mode 100644 index 000000000..00efb5142 --- /dev/null +++ b/src/util/t_tsenum.pm @@ -0,0 +1,163 @@ +package t_tsenum; + +use strict; +use vars qw(@ISA); + +require t_template; +require t_enum; + +@ISA=qw(t_template); + +my @parms = qw(NAME TYPE COMPARE COPY PRINT); +my %defaults = ( "COPY", "0", "PRINT", "0" ); +my @templatelines = ; + +sub new { # no args + my $self = {}; + bless $self; + $self->init(\@parms, \%defaults, \@templatelines); + return $self; +} + +sub output { + my ($self, $fh) = @_; + my $a = new t_enum; + $a->setparm("NAME", $self->{values}{"NAME"} . "__unsafe_enumerator"); + $a->setparm("TYPE", $self->{values}{"TYPE"}); + $a->setparm("COMPARE", $self->{values}{"COMPARE"}); + $a->output($fh); + $self->SUPER::output($fh); +} + +1; + +__DATA__ + +/* + */ +#include "k5-thread.h" +struct __ts_enumerator { + __unsafe_enumerator e; + k5_mutex_t m; +}; +typedef struct __ts_enumerator ; + +static inline int +_init( *en) +{ + int err = k5_mutex_init(&en->m); + if (err) + return err; + err = __unsafe_enumerator_init(&en->e); + if (err) { + k5_mutex_destroy(&en->m); + return err; + } + return 0; +} + +static inline int +_size( *en, long *size) +{ + int err = k5_mutex_lock(&en->m); + if (err) { + *size = -48; + return err; + } + *size = __unsafe_enumerator_size(&en->e); + k5_mutex_unlock(&en->m); + return 0; +} + +static inline int +__do_copy ( *dest, src) +{ + int (*copyfn)(*, ) = ; + if (copyfn) + return copyfn(dest, src); + *dest = src; + return 0; +} + +static inline int +_find_or_append( *en, value, long *idxp, int *added) +{ + int err; + long idx; + + err = k5_mutex_lock(&en->m); + if (err) + return err; + idx = __unsafe_enumerator_find(&en->e, value); + if (idx < 0) { + newvalue; + err = __do_copy(&newvalue, value); + if (err == 0) + idx = __unsafe_enumerator_append(&en->e, newvalue); + k5_mutex_unlock(&en->m); + if (err != 0) + return err; + if (idx < 0) + return ENOMEM; + *idxp = idx; + *added = 1; + return 0; + } + k5_mutex_unlock(&en->m); + *idxp = idx; + *added = 0; + return 0; +} + +static inline int +_get( *en, size_t idx, *value) +{ + int err; + err = k5_mutex_lock(&en->m); + if (err) + return err; + *value = __unsafe_enumerator_get(&en->e, idx); + k5_mutex_unlock(&en->m); + return 0; +} + +static inline void +_destroy( *en) +{ + k5_mutex_destroy(&en->m); + __unsafe_enumerator_destroy(&en->e); +} + +static inline int +_foreach( *en, int (*fn)(size_t i, t, void *p), void *p) +{ + int err = k5_mutex_lock(&en->m); + if (err) + return err; + __unsafe_enumerator_foreach(&en->e, fn, p); + k5_mutex_unlock(&en->m); + return 0; +} + +static inline int +__print_map_elt(size_t idx, val, void *p) +{ + void (*printfn)(, FILE *) = ; + FILE *f = (FILE *) p; + if (printfn) { + fprintf(f, " %lu=", (unsigned long) idx); + printfn(val, f); + } + return 0; +} + +static inline void +_print( *en, FILE *f) +{ + void (*printfn)(, FILE *) = ; + if (printfn) { + fprintf(f, "{"); + _foreach (en, __print_map_elt, f); + fprintf(f, " }"); + } +}