diff options
author | Ken Raeburn <raeburn@mit.edu> | 2007-08-16 22:55:06 +0000 |
---|---|---|
committer | Ken Raeburn <raeburn@mit.edu> | 2007-08-16 22:55:06 +0000 |
commit | c15ec7751a7d7c1d97dbeb1dd88dda2a328515e0 (patch) | |
tree | 824bd8c158b1c5b72913515953c7e8576399d912 /src/lib/gssapi/generic/util_errmap.c | |
parent | 9db2f5eb745287654117e70032d05dd9f5a91a3f (diff) | |
download | krb5-c15ec7751a7d7c1d97dbeb1dd88dda2a328515e0.tar.gz krb5-c15ec7751a7d7c1d97dbeb1dd88dda2a328515e0.tar.xz krb5-c15ec7751a7d7c1d97dbeb1dd88dda2a328515e0.zip |
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
Diffstat (limited to 'src/lib/gssapi/generic/util_errmap.c')
-rw-r--r-- | src/lib/gssapi/generic/util_errmap.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/src/lib/gssapi/generic/util_errmap.c b/src/lib/gssapi/generic/util_errmap.c new file mode 100644 index 0000000000..24975cc455 --- /dev/null +++ b/src/lib/gssapi/generic/util_errmap.c @@ -0,0 +1,190 @@ +#include "gssapiP_generic.h" +#include <string.h> +#include <unistd.h> + +/* 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; +} |