summaryrefslogtreecommitdiff
path: root/src/lib/gssapi/generic/util_errmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/gssapi/generic/util_errmap.c')
-rw-r--r--src/lib/gssapi/generic/util_errmap.c264
1 files changed, 264 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 000000000000..628a455d2ad4
--- /dev/null
+++ b/src/lib/gssapi/generic/util_errmap.c
@@ -0,0 +1,264 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2007, 2008 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
+#include <unistd.h>
+#endif
+
+/* 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
+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)
+{
+ 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 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 > 0) {
+ dest->mech.elements = malloc(src.mech.length);
+ if (dest->mech.elements == NULL)
+ return ENOMEM;
+ memcpy(dest->mech.elements, src.mech.elements, src.mech.length);
+ } else {
+ dest->mech.elements = NULL;
+ }
+ 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" },
+ };
+ unsigned int i;
+
+ fprintf(f, "%lu@", (unsigned long) value.code);
+
+ if (value.mech.length == 0) {
+ 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;
+ }
+ /* 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;
+static k5_mutex_t mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+static OM_uint32 next_fake = 100000;
+
+int gssint_mecherrmap_init(void)
+{
+ int err;
+
+ err = mecherrmap_init(&m);
+ if (err)
+ return err;
+ err = k5_mutex_finish_init(&mutex);
+ if (err) {
+ mecherrmap_destroy(&m);
+ return err;
+ }
+
+ return 0;
+}
+
+/* Currently the enumeration template doesn't handle freeing
+ element storage when destroying the collection. */
+static int free_one(OM_uint32 i, struct mecherror value, void *p)
+{
+ free(value.mech.elements);
+ return 0;
+}
+
+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)
+{
+ 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;
+ k5_mutex_lock(&mutex);
+
+ /* Is this status+oid already mapped? */
+ p = mecherrmap_findright(&m, me);
+ if (p != NULL) {
+ k5_mutex_unlock(&mutex);
+#ifdef DEBUG
+ fprintf(f, "%s: found ", __FUNCTION__);
+ 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)
+ free(me_copy.mech.elements);
+#ifdef DEBUG
+ fprintf(f, "%s: mapping ", __FUNCTION__);
+ 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 };
+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)
+{
+ const struct mecherror *p;
+
+ if (minor == 0) {
+ return EINVAL;
+ }
+ k5_mutex_lock(&mutex);
+ p = mecherrmap_findleft(&m, minor);
+ k5_mutex_unlock(&mutex);
+ if (!p) {
+ return EINVAL;
+ }
+ *mech_oid = p->mech;
+ *mech_minor = p->code;
+ return 0;
+}