Blame src/lib/gssapi/generic/util_errmap.c

Packit fd8b60
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit fd8b60
/*
Packit fd8b60
 * Copyright 2007, 2008 by the Massachusetts Institute of Technology.
Packit fd8b60
 * All Rights Reserved.
Packit fd8b60
 *
Packit fd8b60
 * Export of this software from the United States of America may
Packit fd8b60
 *   require a specific license from the United States Government.
Packit fd8b60
 *   It is the responsibility of any person or organization contemplating
Packit fd8b60
 *   export to obtain such a license before exporting.
Packit fd8b60
 *
Packit fd8b60
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
Packit fd8b60
 * distribute this software and its documentation for any purpose and
Packit fd8b60
 * without fee is hereby granted, provided that the above copyright
Packit fd8b60
 * notice appear in all copies and that both that copyright notice and
Packit fd8b60
 * this permission notice appear in supporting documentation, and that
Packit fd8b60
 * the name of M.I.T. not be used in advertising or publicity pertaining
Packit fd8b60
 * to distribution of the software without specific, written prior
Packit fd8b60
 * permission.  Furthermore if you modify this software you must label
Packit fd8b60
 * your software as modified software and not distribute it in such a
Packit fd8b60
 * fashion that it might be confused with the original M.I.T. software.
Packit fd8b60
 * M.I.T. makes no representations about the suitability of
Packit fd8b60
 * this software for any purpose.  It is provided "as is" without express
Packit fd8b60
 * or implied warranty.
Packit fd8b60
 *
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
#include "gssapiP_generic.h"
Packit fd8b60
#include <string.h>
Packit fd8b60
#ifndef _WIN32
Packit fd8b60
#include <unistd.h>
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
/* The mapping table is 0-based, but let's export codes that are
Packit fd8b60
   1-based, keeping 0 for errors or unknown errors.
Packit fd8b60
Packit fd8b60
   The elements in the mapping table currently have separate copies of
Packit fd8b60
   each OID stored.  This is a bit wasteful, but we are assuming the
Packit fd8b60
   table isn't likely to grow very large.  */
Packit fd8b60
Packit fd8b60
struct mecherror {
Packit fd8b60
    gss_OID_desc mech;
Packit fd8b60
    OM_uint32 code;
Packit fd8b60
};
Packit fd8b60
Packit fd8b60
static inline int
Packit fd8b60
cmp_OM_uint32(OM_uint32 m1, OM_uint32 m2)
Packit fd8b60
{
Packit fd8b60
    if (m1 < m2)
Packit fd8b60
        return -1;
Packit fd8b60
    else if (m1 > m2)
Packit fd8b60
        return 1;
Packit fd8b60
    else
Packit fd8b60
        return 0;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static inline int
Packit fd8b60
mecherror_cmp(struct mecherror m1, struct mecherror m2)
Packit fd8b60
{
Packit fd8b60
    if (m1.code < m2.code)
Packit fd8b60
        return -1;
Packit fd8b60
    if (m1.code > m2.code)
Packit fd8b60
        return 1;
Packit fd8b60
    if (m1.mech.length < m2.mech.length)
Packit fd8b60
        return -1;
Packit fd8b60
    if (m1.mech.length > m2.mech.length)
Packit fd8b60
        return 1;
Packit fd8b60
    if (m1.mech.length == 0)
Packit fd8b60
        return 0;
Packit fd8b60
    return memcmp(m1.mech.elements, m2.mech.elements, m1.mech.length);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static void
Packit fd8b60
print_OM_uint32 (OM_uint32 value, FILE *f)
Packit fd8b60
{
Packit fd8b60
    fprintf(f, "%lu", (unsigned long) value);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static inline int
Packit fd8b60
mecherror_copy(struct mecherror *dest, struct mecherror src)
Packit fd8b60
{
Packit fd8b60
    *dest = src;
Packit fd8b60
    if (src.mech.length > 0) {
Packit fd8b60
        dest->mech.elements = malloc(src.mech.length);
Packit fd8b60
        if (dest->mech.elements == NULL)
Packit fd8b60
            return ENOMEM;
Packit fd8b60
        memcpy(dest->mech.elements, src.mech.elements, src.mech.length);
Packit fd8b60
    } else {
Packit fd8b60
        dest->mech.elements = NULL;
Packit fd8b60
    }
Packit fd8b60
    return 0;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static void
Packit fd8b60
mecherror_print(struct mecherror value, FILE *f)
Packit fd8b60
{
Packit fd8b60
    OM_uint32 minor;
Packit fd8b60
    gss_buffer_desc str;
Packit fd8b60
    static const struct {
Packit fd8b60
        const char *oidstr, *name;
Packit fd8b60
    } mechnames[] = {
Packit fd8b60
        { "{ 1 2 840 113554 1 2 2 }", "krb5-new" },
Packit fd8b60
        { "{ 1 3 5 1 5 2 }", "krb5-old" },
Packit fd8b60
        { "{ 1 2 840 48018 1 2 2 }", "krb5-microsoft" },
Packit fd8b60
        { "{ 1 3 6 1 5 5 2 }", "spnego" },
Packit fd8b60
    };
Packit fd8b60
    unsigned int i;
Packit fd8b60
Packit fd8b60
    fprintf(f, "%lu@", (unsigned long) value.code);
Packit fd8b60
Packit fd8b60
    if (value.mech.length == 0) {
Packit fd8b60
        fprintf(f, "(com_err)");
Packit fd8b60
        return;
Packit fd8b60
    }
Packit fd8b60
    fprintf(f, "%p=", value.mech.elements);
Packit fd8b60
    if (generic_gss_oid_to_str(&minor, &value.mech, &str)) {
Packit fd8b60
        fprintf(f, "(error in conversion)");
Packit fd8b60
        return;
Packit fd8b60
    }
Packit fd8b60
    /* Note: generic_gss_oid_to_str returns a null-terminated string.  */
Packit fd8b60
    for (i = 0; i < sizeof(mechnames)/sizeof(mechnames[0]); i++) {
Packit fd8b60
        if (!strcmp(str.value, mechnames[i].oidstr) && mechnames[i].name != 0) {
Packit fd8b60
            fprintf(f, "%s", mechnames[i].name);
Packit fd8b60
            break;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
    if (i == sizeof(mechnames)/sizeof(mechnames[0]))
Packit fd8b60
        fprintf(f, "%s", (char *) str.value);
Packit fd8b60
    generic_gss_release_buffer(&minor, &str);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
#include "errmap.h"
Packit fd8b60
#include "krb5.h"               /* for KRB5KRB_AP_WRONG_PRINC */
Packit fd8b60
Packit fd8b60
static mecherrmap m;
Packit fd8b60
static k5_mutex_t mutex = K5_MUTEX_PARTIAL_INITIALIZER;
Packit fd8b60
static OM_uint32 next_fake = 100000;
Packit fd8b60
Packit fd8b60
int gssint_mecherrmap_init(void)
Packit fd8b60
{
Packit fd8b60
    int err;
Packit fd8b60
Packit fd8b60
    err = mecherrmap_init(&m);
Packit fd8b60
    if (err)
Packit fd8b60
        return err;
Packit fd8b60
    err = k5_mutex_finish_init(&mutex);
Packit fd8b60
    if (err) {
Packit fd8b60
        mecherrmap_destroy(&m);
Packit fd8b60
        return err;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    return 0;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/* Currently the enumeration template doesn't handle freeing
Packit fd8b60
   element storage when destroying the collection.  */
Packit fd8b60
static int free_one(OM_uint32 i, struct mecherror value, void *p)
Packit fd8b60
{
Packit fd8b60
    free(value.mech.elements);
Packit fd8b60
    return 0;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
void gssint_mecherrmap_destroy(void)
Packit fd8b60
{
Packit fd8b60
    mecherrmap_foreach(&m, free_one, NULL);
Packit fd8b60
    mecherrmap_destroy(&m);
Packit fd8b60
    k5_mutex_destroy(&mutex);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
OM_uint32 gssint_mecherrmap_map(OM_uint32 minor, const gss_OID_desc * oid)
Packit fd8b60
{
Packit fd8b60
    const struct mecherror *mep;
Packit fd8b60
    struct mecherror me, me_copy;
Packit fd8b60
    const OM_uint32 *p;
Packit fd8b60
    int err;
Packit fd8b60
    OM_uint32 new_status;
Packit fd8b60
Packit fd8b60
#ifdef DEBUG
Packit fd8b60
    FILE *f;
Packit fd8b60
    f = fopen("/dev/pts/9", "w+");
Packit fd8b60
    if (f == NULL)
Packit fd8b60
        f = stderr;
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
    me.code = minor;
Packit fd8b60
    me.mech = *oid;
Packit fd8b60
    k5_mutex_lock(&mutex);
Packit fd8b60
Packit fd8b60
    /* Is this status+oid already mapped?  */
Packit fd8b60
    p = mecherrmap_findright(&m, me);
Packit fd8b60
    if (p != NULL) {
Packit fd8b60
        k5_mutex_unlock(&mutex);
Packit fd8b60
#ifdef DEBUG
Packit fd8b60
        fprintf(f, "%s: found ", __FUNCTION__);
Packit fd8b60
        mecherror_print(me, f);
Packit fd8b60
        fprintf(f, " in map as %lu\n", (unsigned long) *p);
Packit fd8b60
        if (f != stderr) fclose(f);
Packit fd8b60
#endif
Packit fd8b60
        return *p;
Packit fd8b60
    }
Packit fd8b60
    /* Is this status code already mapped to something else
Packit fd8b60
       mech-specific?  */
Packit fd8b60
    mep = mecherrmap_findleft(&m, minor);
Packit fd8b60
    if (mep == NULL) {
Packit fd8b60
        /* Map it to itself plus this mech-oid.  */
Packit fd8b60
        new_status = minor;
Packit fd8b60
    } else {
Packit fd8b60
        /* Already assigned.  Pick a fake new value and map it.  */
Packit fd8b60
        /* There's a theoretical infinite loop risk here, if we fill
Packit fd8b60
           in 2**32 values.  Also, returning 0 has a special
Packit fd8b60
           meaning.  */
Packit fd8b60
        do {
Packit fd8b60
            next_fake++;
Packit fd8b60
            new_status = next_fake;
Packit fd8b60
            if (new_status == 0)
Packit fd8b60
                /* ??? */;
Packit fd8b60
        } while (mecherrmap_findleft(&m, new_status) != NULL);
Packit fd8b60
    }
Packit fd8b60
    err = mecherror_copy(&me_copy, me);
Packit fd8b60
    if (err) {
Packit fd8b60
        k5_mutex_unlock(&mutex);
Packit fd8b60
        return err;
Packit fd8b60
    }
Packit fd8b60
    err = mecherrmap_add(&m, new_status, me_copy);
Packit fd8b60
    k5_mutex_unlock(&mutex);
Packit fd8b60
    if (err)
Packit fd8b60
        free(me_copy.mech.elements);
Packit fd8b60
#ifdef DEBUG
Packit fd8b60
    fprintf(f, "%s: mapping ", __FUNCTION__);
Packit fd8b60
    mecherror_print(me, f);
Packit fd8b60
    fprintf(f, " to %lu: err=%d\nnew map: ", (unsigned long) new_status, err);
Packit fd8b60
    mecherrmap_printmap(&m, f);
Packit fd8b60
    fprintf(f, "\n");
Packit fd8b60
    if (f != stderr) fclose(f);
Packit fd8b60
#endif
Packit fd8b60
    if (err)
Packit fd8b60
        return 0;
Packit fd8b60
    else
Packit fd8b60
        return new_status;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static gss_OID_desc no_oid = { 0, 0 };
Packit fd8b60
OM_uint32 gssint_mecherrmap_map_errcode(OM_uint32 errcode)
Packit fd8b60
{
Packit fd8b60
    return gssint_mecherrmap_map(errcode, &no_oid);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
int gssint_mecherrmap_get(OM_uint32 minor, gss_OID mech_oid,
Packit fd8b60
                          OM_uint32 *mech_minor)
Packit fd8b60
{
Packit fd8b60
    const struct mecherror *p;
Packit fd8b60
Packit fd8b60
    if (minor == 0) {
Packit fd8b60
        return EINVAL;
Packit fd8b60
    }
Packit fd8b60
    k5_mutex_lock(&mutex);
Packit fd8b60
    p = mecherrmap_findleft(&m, minor);
Packit fd8b60
    k5_mutex_unlock(&mutex);
Packit fd8b60
    if (!p) {
Packit fd8b60
        return EINVAL;
Packit fd8b60
    }
Packit fd8b60
    *mech_oid = p->mech;
Packit fd8b60
    *mech_minor = p->code;
Packit fd8b60
    return 0;
Packit fd8b60
}