Rework error-mapping code to preserve status code values when returned
authorKen Raeburn <raeburn@mit.edu>
Wed, 5 Sep 2007 00:12:30 +0000 (00:12 +0000)
committerKen Raeburn <raeburn@mit.edu>
Wed, 5 Sep 2007 00:12:30 +0000 (00:12 +0000)
by only one mechanism.  Revert RPC code to relying on this.

Build error-mapping code on a bidirectional map instead of a simple
array.  When a status code is returned but has been seen returned from
a different mechanism already, generate a new number, starting at
100,000.

Use gssrpcint_printf for some more debugging code.

ticket: 5654

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@19919 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/gssapi/generic/Makefile.in
src/lib/gssapi/generic/maptest.c
src/lib/gssapi/generic/util_errmap.c
src/lib/rpc/auth_gssapi.c
src/lib/rpc/svc_auth_gssapi.c

index d32e8b2d62a94c3328c915c775a65787c3c8ea19..d09a67860a8841cd2bb88cd82a6b89b2811c63cf 100644 (file)
@@ -114,18 +114,20 @@ 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
+               $(SRCTOP)/util/t_bimap.pm
+       $(PERL) -w -I$(SRCTOP)/util $(SRCTOP)/util/gen.pl bimap errmap.h \
+               NAME=mecherrmap LEFT=OM_uint32 RIGHT="struct mecherror" \
+               LEFTPRINT=print_OM_uint32 RIGHTPRINT=mecherror_print \
+               LEFTCMP=cmp_OM_uint32 RIGHTCMP=mecherror_cmp
 
 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
+               $(SRCTOP)/util/t_bimap.pm
+       $(PERL) -w -I$(SRCTOP)/util $(SRCTOP)/util/gen.pl bimap maptest.h \
+               NAME=foo LEFT=int RIGHT=elt LEFTPRINT=intprt RIGHTPRINT=eltprt \
+               LEFTCMP=intcmp RIGHTCMP=eltcmp
 maptest.o: maptest.c maptest.h
 maptest: maptest.o
-       $(CC_LINK) -o maptest maptest.o $(SUPPORT_LIB)
+       $(CC_LINK) -o maptest maptest.o
 
 ##DOS##LIBOBJS = $(OBJS)
 
index b884eed8b40c3f0ef22186719b36253640a0b836..28b4b06337b52a4896f5313a9ce19cc11606265e 100644 (file)
@@ -24,6 +24,18 @@ static void eltprt(elt v, FILE *f)
 {
     fprintf(f, "{%d,%d}", v.a, v.b);
 }
+static int intcmp(int left, int right)
+{
+    if (left < right)
+       return -1;
+    if (left > right)
+       return 1;
+    return 0;
+}
+static void intprt(int v, FILE *f)
+{
+    fprintf(f, "%d", v);
+}
 
 #include "maptest.h"
 
@@ -31,24 +43,25 @@ foo foo1;
 
 int main ()
 {
-    int err;
     elt v1 = { 1, 2 }, v2 = { 3, 4 };
-    long idx;
-    int added;
+    const elt *vp;
+    const int *ip;
 
-    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);
+    assert(0 == foo_init(&foo1));
+    vp = foo_findleft(&foo1, 47);
+    assert(vp == NULL);
+    assert(0 == foo_add(&foo1, 47, v1));
+    vp = foo_findleft(&foo1, 47);
+    assert(vp != NULL);
+    assert(0 == eltcmp(*vp, v1));
+    vp = foo_findleft(&foo1, 3);
+    assert(vp == NULL);
+    assert(0 == foo_add(&foo1, 93, v2));
+    ip = foo_findright(&foo1, v1);
+    assert(ip != NULL);
+    assert(*ip == 47);
+    printf("Map content: ");
+    foo_printmap(&foo1, stdout);
+    printf("\n");
     return 0;
 }
index 6f7f1709161426050dab4f9887ab45d5cb19775c..5cd554cde0d8b22c414df6e024686c1aa325af24 100644 (file)
@@ -1,3 +1,28 @@
+/*
+ * Copyright 2007 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.
+ * 
+ */
+
 #include "gssapiP_generic.h"
 #include <string.h>
 #ifndef _WIN32
@@ -16,6 +41,17 @@ struct mecherror {
     OM_uint32 code;
 };
 
+static inline int
+cmp_OM_uint32(OM_uint32 m1, OM_uint32 m2)
+{
+    if (m1 < m2)
+       return -1;
+    else if (m1 > m2)
+       return 1;
+    else
+       return 0;
+}
+
 static inline int
 mecherror_cmp(struct mecherror m1, struct mecherror m2)
 {
@@ -32,14 +68,22 @@ mecherror_cmp(struct mecherror m1, struct mecherror m2)
     return memcmp(m1.mech.elements, m2.mech.elements, m1.mech.length);
 }
 
+static void
+print_OM_uint32 (OM_uint32 value, FILE *f)
+{
+    fprintf(f, "%lu", (unsigned long) value);
+}
+
 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)
+    dest->mech.elements = malloc(src.mech.length);
+    if (dest->mech.elements == NULL) {
+       if (src.mech.length)
            return ENOMEM;
+       else
+           return 0;
     }
     memcpy(dest->mech.elements, src.mech.elements, src.mech.length);
     return 0;
@@ -66,6 +110,7 @@ mecherror_print(struct mecherror value, FILE *f)
        fprintf(f, "(com_err)");
        return;
     }
+    fprintf(f, "%p=", value.mech.elements);
     if (generic_gss_oid_to_str(&minor, &value.mech, &str)) {
        fprintf(f, "(error in conversion)");
        return;
@@ -86,44 +131,20 @@ mecherror_print(struct mecherror value, FILE *f)
 #include "krb5.h"              /* for KRB5KRB_AP_WRONG_PRINC */
 
 static mecherrmap m;
+static k5_mutex_t mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+static OM_uint32 next_fake = 100000;
 
 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;
+    err = k5_mutex_finish_init(&mutex);
+    if (err) {
+       mecherrmap_destroy(&m);
+       return err;
     }
 
     return 0;
@@ -142,21 +163,87 @@ void gssint_mecherrmap_destroy(void)
 {
     mecherrmap_foreach(&m, free_one, NULL);
     mecherrmap_destroy(&m);
+    k5_mutex_destroy(&mutex);
 }
 
 OM_uint32 gssint_mecherrmap_map(OM_uint32 minor, const gss_OID_desc * oid)
 {
-    struct mecherror me;
-    int err, added;
-    long idx;
+    const struct mecherror *mep;
+    struct mecherror me, me_copy;
+    const OM_uint32 *p;
+    int err;
+    OM_uint32 new_status;
+
+#ifdef DEBUG
+    FILE *f;
+    f = fopen("/dev/pts/9", "w+");
+    if (f == NULL)
+       f = stderr;
+#endif
 
     me.code = minor;
     me.mech = *oid;
-    err = mecherrmap_find_or_append(&m, me, &idx, &added);
+    err = k5_mutex_lock(&mutex);
     if (err) {
+#ifdef DEBUG
+       if (f != stderr) fclose(f);
+#endif
        return 0;
     }
-    return idx+1;
+
+    /* Is this status+oid already mapped?  */
+    p = mecherrmap_findright(&m, me);
+    if (p != NULL) {
+       k5_mutex_unlock(&mutex);
+#ifdef DEBUG
+       fprintf(f, "%s: found ", __func__);
+       mecherror_print(me, f);
+       fprintf(f, " in map as %lu\n", (unsigned long) *p);
+       if (f != stderr) fclose(f);
+#endif
+       return *p;
+    }
+    /* Is this status code already mapped to something else
+       mech-specific?  */
+    mep = mecherrmap_findleft(&m, minor);
+    if (mep == NULL) {
+       /* Map it to itself plus this mech-oid.  */
+       new_status = minor;
+    } else {
+       /* Already assigned.  Pick a fake new value and map it.  */
+       /* There's a theoretical infinite loop risk here, if we fill
+          in 2**32 values.  Also, returning 0 has a special
+          meaning.  */
+       do {
+           next_fake++;
+           new_status = next_fake;
+           if (new_status == 0)
+               /* ??? */;
+       } while (mecherrmap_findleft(&m, new_status) != NULL);
+    }
+    err = mecherror_copy(&me_copy, me);
+    if (err) {
+       k5_mutex_unlock(&mutex);
+       return err;
+    }
+    err = mecherrmap_add(&m, new_status, me_copy);
+    k5_mutex_unlock(&mutex);
+    if (err) {
+       if (me_copy.mech.length)
+           free(me_copy.mech.elements);
+    }
+#ifdef DEBUG
+    fprintf(f, "%s: mapping ", __func__);
+    mecherror_print(me, f);
+    fprintf(f, " to %lu: err=%d\nnew map: ", (unsigned long) new_status, err);
+    mecherrmap_printmap(&m, f);
+    fprintf(f, "\n");
+    if (f != stderr) fclose(f);
+#endif
+    if (err)
+       return 0;
+    else
+       return new_status;
 }
 
 static gss_OID_desc no_oid = { 0, 0 };
@@ -168,25 +255,21 @@ OM_uint32 gssint_mecherrmap_map_errcode(OM_uint32 errcode)
 int gssint_mecherrmap_get(OM_uint32 minor, gss_OID mech_oid,
                          OM_uint32 *mech_minor)
 {
-    struct mecherror me;
+    const struct mecherror *p;
     int err;
-    long size;
 
     if (minor == 0) {
        return EINVAL;
     }
-    err = mecherrmap_size(&m, &size);
-    if (err) {
+    err = k5_mutex_lock(&mutex);
+    if (err)
        return err;
-    }
-    if (minor > size) {
+    p = mecherrmap_findleft(&m, minor);
+    k5_mutex_unlock(&mutex);
+    if (!p) {
        return EINVAL;
     }
-    err = mecherrmap_get(&m, minor-1, &me);
-    if (err) {
-       return err;
-    }
-    *mech_oid = me.mech;
-    *mech_minor = me.code;
+    *mech_oid = p->mech;
+    *mech_minor = p->code;
     return 0;
 }
index 3d6e6fe6341efbd49c351e1675dc069d20894832..bd185bc899901767d47e6ea81fa4ba35c9fe6e1d 100644 (file)
@@ -22,7 +22,8 @@
 
 #ifdef DEBUG_GSSAPI
 int auth_debug_gssapi = DEBUG_GSSAPI;
-#define L_PRINTF(l,args) if (auth_debug_gssapi >= l) printf args
+extern void gssrpcint_printf(const char *format, ...);
+#define L_PRINTF(l,args) if (auth_debug_gssapi >= l) gssrpcint_printf args
 #define PRINTF(args) L_PRINTF(99, args)
 #define AUTH_GSSAPI_DISPLAY_STATUS(args) \
        if (auth_debug_gssapi) auth_gssapi_display_status args
index cb1e8f90f80e2a372a2dd2f14b210814ffb52ddc..f899c896896a1fa31f5c7d9b8506e10c56b241b0 100644 (file)
@@ -402,8 +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);
+              PRINTF(("accept_sec_context returned 0x%x 0x%x wrong-princ=%#x\n",
+                      call_res.gss_major, call_res.gss_minor, KRB5KRB_AP_WRONG_PRINC));
               if (call_res.gss_major == GSS_S_COMPLETE ||
                   call_res.gss_major == GSS_S_CONTINUE_NEEDED) {
                    /* server_creds was right, set it! */
@@ -419,12 +419,8 @@ 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;
@@ -437,8 +433,8 @@ enum auth_stat gssrpc__svcauth_gssapi(
          /* done with call args */
          xdr_free(xdr_authgssapi_init_arg, &call_arg);
 
-         PRINTF(("svcauth_gssapi: accept_sec_context returned %#x\n",
-                 call_res.gss_major));
+         PRINTF(("svcauth_gssapi: accept_sec_context returned %#x %#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) {
               AUTH_GSSAPI_DISPLAY_STATUS(("accepting context",