aboutsummaryrefslogtreecommitdiff
path: root/src/lib/gssapi/generic
diff options
context:
space:
mode:
authorKen Raeburn <raeburn@mit.edu>2007-08-16 22:55:06 +0000
committerKen Raeburn <raeburn@mit.edu>2007-08-16 22:55:06 +0000
commitc15ec7751a7d7c1d97dbeb1dd88dda2a328515e0 (patch)
tree824bd8c158b1c5b72913515953c7e8576399d912 /src/lib/gssapi/generic
parent9db2f5eb745287654117e70032d05dd9f5a91a3f (diff)
downloadkrb5-c15ec7751a7d7c1d97dbeb1dd88dda2a328515e0.zip
krb5-c15ec7751a7d7c1d97dbeb1dd88dda2a328515e0.tar.gz
krb5-c15ec7751a7d7c1d97dbeb1dd88dda2a328515e0.tar.bz2
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')
-rw-r--r--src/lib/gssapi/generic/Makefile.in21
-rw-r--r--src/lib/gssapi/generic/gssapiP_generic.h5
-rw-r--r--src/lib/gssapi/generic/maptest.c54
-rw-r--r--src/lib/gssapi/generic/util_errmap.c190
4 files changed, 270 insertions, 0 deletions
diff --git a/src/lib/gssapi/generic/Makefile.in b/src/lib/gssapi/generic/Makefile.in
index e63be6b..6d66396 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 e34055b..1ec5417 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 0000000..b884eed
--- /dev/null
+++ b/src/lib/gssapi/generic/maptest.c
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+
+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 0000000..24975cc
--- /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;
+}