1*5e01956fSGlenn Barry /* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ 2*5e01956fSGlenn Barry /* -*- mode: c; indent-tabs-mode: nil -*- */ 3*5e01956fSGlenn Barry /* 4*5e01956fSGlenn Barry * Copyright 2007, 2008 by the Massachusetts Institute of Technology. 5*5e01956fSGlenn Barry * All Rights Reserved. 6*5e01956fSGlenn Barry * 7*5e01956fSGlenn Barry * Export of this software from the United States of America may 8*5e01956fSGlenn Barry * require a specific license from the United States Government. 9*5e01956fSGlenn Barry * It is the responsibility of any person or organization contemplating 10*5e01956fSGlenn Barry * export to obtain such a license before exporting. 11*5e01956fSGlenn Barry * 12*5e01956fSGlenn Barry * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13*5e01956fSGlenn Barry * distribute this software and its documentation for any purpose and 14*5e01956fSGlenn Barry * without fee is hereby granted, provided that the above copyright 15*5e01956fSGlenn Barry * notice appear in all copies and that both that copyright notice and 16*5e01956fSGlenn Barry * this permission notice appear in supporting documentation, and that 17*5e01956fSGlenn Barry * the name of M.I.T. not be used in advertising or publicity pertaining 18*5e01956fSGlenn Barry * to distribution of the software without specific, written prior 19*5e01956fSGlenn Barry * permission. Furthermore if you modify this software you must label 20*5e01956fSGlenn Barry * your software as modified software and not distribute it in such a 21*5e01956fSGlenn Barry * fashion that it might be confused with the original M.I.T. software. 22*5e01956fSGlenn Barry * M.I.T. makes no representations about the suitability of 23*5e01956fSGlenn Barry * this software for any purpose. It is provided "as is" without express 24*5e01956fSGlenn Barry * or implied warranty. 25*5e01956fSGlenn Barry * 26*5e01956fSGlenn Barry */ 27*5e01956fSGlenn Barry 28*5e01956fSGlenn Barry #include "gssapiP_generic.h" 29*5e01956fSGlenn Barry #include "mechglueP.h" 30*5e01956fSGlenn Barry #include <string.h> 31*5e01956fSGlenn Barry #include <stdio.h> 32*5e01956fSGlenn Barry #ifndef _WIN32 33*5e01956fSGlenn Barry #include <unistd.h> 34*5e01956fSGlenn Barry #endif 35*5e01956fSGlenn Barry 36*5e01956fSGlenn Barry /* Solaris Kerberos */ 37*5e01956fSGlenn Barry #define inline 38*5e01956fSGlenn Barry #ifdef DEBUG 39*5e01956fSGlenn Barry #undef DEBUG 40*5e01956fSGlenn Barry #endif 41*5e01956fSGlenn Barry 42*5e01956fSGlenn Barry /* The mapping table is 0-based, but let's export codes that are 43*5e01956fSGlenn Barry 1-based, keeping 0 for errors or unknown errors. 44*5e01956fSGlenn Barry 45*5e01956fSGlenn Barry The elements in the mapping table currently have separate copies of 46*5e01956fSGlenn Barry each OID stored. This is a bit wasteful, but we are assuming the 47*5e01956fSGlenn Barry table isn't likely to grow very large. */ 48*5e01956fSGlenn Barry 49*5e01956fSGlenn Barry struct mecherror { 50*5e01956fSGlenn Barry gss_OID_desc mech; 51*5e01956fSGlenn Barry OM_uint32 code; 52*5e01956fSGlenn Barry }; 53*5e01956fSGlenn Barry 54*5e01956fSGlenn Barry static inline int 55*5e01956fSGlenn Barry cmp_OM_uint32(OM_uint32 m1, OM_uint32 m2) 56*5e01956fSGlenn Barry { 57*5e01956fSGlenn Barry if (m1 < m2) 58*5e01956fSGlenn Barry return -1; 59*5e01956fSGlenn Barry else if (m1 > m2) 60*5e01956fSGlenn Barry return 1; 61*5e01956fSGlenn Barry else 62*5e01956fSGlenn Barry return 0; 63*5e01956fSGlenn Barry } 64*5e01956fSGlenn Barry 65*5e01956fSGlenn Barry static inline int 66*5e01956fSGlenn Barry mecherror_cmp(struct mecherror m1, struct mecherror m2) 67*5e01956fSGlenn Barry { 68*5e01956fSGlenn Barry if (m1.code < m2.code) 69*5e01956fSGlenn Barry return -1; 70*5e01956fSGlenn Barry if (m1.code > m2.code) 71*5e01956fSGlenn Barry return 1; 72*5e01956fSGlenn Barry if (m1.mech.length < m2.mech.length) 73*5e01956fSGlenn Barry return -1; 74*5e01956fSGlenn Barry if (m1.mech.length > m2.mech.length) 75*5e01956fSGlenn Barry return 1; 76*5e01956fSGlenn Barry if (m1.mech.length == 0) 77*5e01956fSGlenn Barry return 0; 78*5e01956fSGlenn Barry return memcmp(m1.mech.elements, m2.mech.elements, m1.mech.length); 79*5e01956fSGlenn Barry } 80*5e01956fSGlenn Barry 81*5e01956fSGlenn Barry static void 82*5e01956fSGlenn Barry print_OM_uint32 (OM_uint32 value, FILE *f) 83*5e01956fSGlenn Barry { 84*5e01956fSGlenn Barry fprintf(f, "%lu", (unsigned long) value); 85*5e01956fSGlenn Barry } 86*5e01956fSGlenn Barry 87*5e01956fSGlenn Barry static inline int 88*5e01956fSGlenn Barry mecherror_copy(struct mecherror *dest, struct mecherror src) 89*5e01956fSGlenn Barry { 90*5e01956fSGlenn Barry *dest = src; 91*5e01956fSGlenn Barry dest->mech.elements = malloc(src.mech.length); 92*5e01956fSGlenn Barry if (dest->mech.elements == NULL) { 93*5e01956fSGlenn Barry if (src.mech.length) 94*5e01956fSGlenn Barry return ENOMEM; 95*5e01956fSGlenn Barry else 96*5e01956fSGlenn Barry return 0; 97*5e01956fSGlenn Barry } 98*5e01956fSGlenn Barry memcpy(dest->mech.elements, src.mech.elements, src.mech.length); 99*5e01956fSGlenn Barry return 0; 100*5e01956fSGlenn Barry } 101*5e01956fSGlenn Barry 102*5e01956fSGlenn Barry static void 103*5e01956fSGlenn Barry mecherror_print(struct mecherror value, FILE *f) 104*5e01956fSGlenn Barry { 105*5e01956fSGlenn Barry OM_uint32 minor; 106*5e01956fSGlenn Barry gss_buffer_desc str; 107*5e01956fSGlenn Barry static const struct { 108*5e01956fSGlenn Barry const char *oidstr, *name; 109*5e01956fSGlenn Barry } mechnames[] = { 110*5e01956fSGlenn Barry { "{ 1 2 840 113554 1 2 2 }", "krb5-new" }, 111*5e01956fSGlenn Barry { "{ 1 3 5 1 5 2 }", "krb5-old" }, 112*5e01956fSGlenn Barry { "{ 1 2 840 48018 1 2 2 }", "krb5-microsoft" }, 113*5e01956fSGlenn Barry { "{ 1 3 6 1 5 5 2 }", "spnego" }, 114*5e01956fSGlenn Barry }; 115*5e01956fSGlenn Barry unsigned int i; 116*5e01956fSGlenn Barry 117*5e01956fSGlenn Barry fprintf(f, "%lu@", (unsigned long) value.code); 118*5e01956fSGlenn Barry 119*5e01956fSGlenn Barry if (value.mech.length == 0) { 120*5e01956fSGlenn Barry fprintf(f, "(com_err)"); 121*5e01956fSGlenn Barry return; 122*5e01956fSGlenn Barry } 123*5e01956fSGlenn Barry fprintf(f, "%p=", value.mech.elements); 124*5e01956fSGlenn Barry if (generic_gss_oid_to_str(&minor, &value.mech, &str)) { 125*5e01956fSGlenn Barry fprintf(f, "(error in conversion)"); 126*5e01956fSGlenn Barry return; 127*5e01956fSGlenn Barry } 128*5e01956fSGlenn Barry /* Note: generic_gss_oid_to_str returns a null-terminated string. */ 129*5e01956fSGlenn Barry for (i = 0; i < sizeof(mechnames)/sizeof(mechnames[0]); i++) { 130*5e01956fSGlenn Barry if (!strcmp(str.value, mechnames[i].oidstr) && mechnames[i].name != 0) { 131*5e01956fSGlenn Barry fprintf(f, "%s", mechnames[i].name); 132*5e01956fSGlenn Barry break; 133*5e01956fSGlenn Barry } 134*5e01956fSGlenn Barry } 135*5e01956fSGlenn Barry if (i == sizeof(mechnames)/sizeof(mechnames[0])) 136*5e01956fSGlenn Barry fprintf(f, "%s", (char *) str.value); 137*5e01956fSGlenn Barry generic_gss_release_buffer(&minor, &str); 138*5e01956fSGlenn Barry } 139*5e01956fSGlenn Barry 140*5e01956fSGlenn Barry #include "errmap.h" 141*5e01956fSGlenn Barry #include "krb5.h" /* for KRB5KRB_AP_WRONG_PRINC */ 142*5e01956fSGlenn Barry 143*5e01956fSGlenn Barry static mecherrmap m; 144*5e01956fSGlenn Barry static k5_mutex_t mutex = K5_MUTEX_PARTIAL_INITIALIZER; 145*5e01956fSGlenn Barry static OM_uint32 next_fake = 100000; 146*5e01956fSGlenn Barry 147*5e01956fSGlenn Barry int gssint_mecherrmap_init(void) 148*5e01956fSGlenn Barry { 149*5e01956fSGlenn Barry int err; 150*5e01956fSGlenn Barry 151*5e01956fSGlenn Barry err = mecherrmap_init(&m); 152*5e01956fSGlenn Barry if (err) 153*5e01956fSGlenn Barry return err; 154*5e01956fSGlenn Barry err = k5_mutex_finish_init(&mutex); 155*5e01956fSGlenn Barry if (err) { 156*5e01956fSGlenn Barry mecherrmap_destroy(&m); 157*5e01956fSGlenn Barry return err; 158*5e01956fSGlenn Barry } 159*5e01956fSGlenn Barry 160*5e01956fSGlenn Barry return 0; 161*5e01956fSGlenn Barry } 162*5e01956fSGlenn Barry 163*5e01956fSGlenn Barry /* Currently the enumeration template doesn't handle freeing 164*5e01956fSGlenn Barry element storage when destroying the collection. */ 165*5e01956fSGlenn Barry static int free_one(OM_uint32 i, struct mecherror value, void *p) 166*5e01956fSGlenn Barry { 167*5e01956fSGlenn Barry if (value.mech.length && value.mech.elements) 168*5e01956fSGlenn Barry free(value.mech.elements); 169*5e01956fSGlenn Barry return 0; 170*5e01956fSGlenn Barry } 171*5e01956fSGlenn Barry 172*5e01956fSGlenn Barry void gssint_mecherrmap_destroy(void) 173*5e01956fSGlenn Barry { 174*5e01956fSGlenn Barry mecherrmap_foreach(&m, free_one, NULL); 175*5e01956fSGlenn Barry mecherrmap_destroy(&m); 176*5e01956fSGlenn Barry k5_mutex_destroy(&mutex); 177*5e01956fSGlenn Barry } 178*5e01956fSGlenn Barry 179*5e01956fSGlenn Barry OM_uint32 gssint_mecherrmap_map(OM_uint32 minor, const gss_OID_desc * oid) 180*5e01956fSGlenn Barry { 181*5e01956fSGlenn Barry const struct mecherror *mep; 182*5e01956fSGlenn Barry struct mecherror me, me_copy; 183*5e01956fSGlenn Barry const OM_uint32 *p; 184*5e01956fSGlenn Barry int err; 185*5e01956fSGlenn Barry OM_uint32 new_status; 186*5e01956fSGlenn Barry 187*5e01956fSGlenn Barry #ifdef DEBUG 188*5e01956fSGlenn Barry FILE *f; 189*5e01956fSGlenn Barry f = fopen("/dev/pts/9", "w+"); 190*5e01956fSGlenn Barry if (f == NULL) 191*5e01956fSGlenn Barry f = stderr; 192*5e01956fSGlenn Barry #endif 193*5e01956fSGlenn Barry 194*5e01956fSGlenn Barry me.code = minor; 195*5e01956fSGlenn Barry me.mech = *oid; 196*5e01956fSGlenn Barry err = k5_mutex_lock(&mutex); 197*5e01956fSGlenn Barry if (err) { 198*5e01956fSGlenn Barry #ifdef DEBUG 199*5e01956fSGlenn Barry if (f != stderr) fclose(f); 200*5e01956fSGlenn Barry #endif 201*5e01956fSGlenn Barry return 0; 202*5e01956fSGlenn Barry } 203*5e01956fSGlenn Barry 204*5e01956fSGlenn Barry /* Is this status+oid already mapped? */ 205*5e01956fSGlenn Barry p = mecherrmap_findright(&m, me); 206*5e01956fSGlenn Barry if (p != NULL) { 207*5e01956fSGlenn Barry k5_mutex_unlock(&mutex); 208*5e01956fSGlenn Barry #ifdef DEBUG 209*5e01956fSGlenn Barry fprintf(f, "%s: found ", __func__); 210*5e01956fSGlenn Barry mecherror_print(me, f); 211*5e01956fSGlenn Barry fprintf(f, " in map as %lu\n", (unsigned long) *p); 212*5e01956fSGlenn Barry if (f != stderr) fclose(f); 213*5e01956fSGlenn Barry #endif 214*5e01956fSGlenn Barry return *p; 215*5e01956fSGlenn Barry } 216*5e01956fSGlenn Barry /* Is this status code already mapped to something else 217*5e01956fSGlenn Barry mech-specific? */ 218*5e01956fSGlenn Barry mep = mecherrmap_findleft(&m, minor); 219*5e01956fSGlenn Barry if (mep == NULL) { 220*5e01956fSGlenn Barry /* Map it to itself plus this mech-oid. */ 221*5e01956fSGlenn Barry new_status = minor; 222*5e01956fSGlenn Barry } else { 223*5e01956fSGlenn Barry /* Already assigned. Pick a fake new value and map it. */ 224*5e01956fSGlenn Barry /* There's a theoretical infinite loop risk here, if we fill 225*5e01956fSGlenn Barry in 2**32 values. Also, returning 0 has a special 226*5e01956fSGlenn Barry meaning. */ 227*5e01956fSGlenn Barry do { 228*5e01956fSGlenn Barry next_fake++; 229*5e01956fSGlenn Barry new_status = next_fake; 230*5e01956fSGlenn Barry if (new_status == 0) 231*5e01956fSGlenn Barry /* ??? */; 232*5e01956fSGlenn Barry } while (mecherrmap_findleft(&m, new_status) != NULL); 233*5e01956fSGlenn Barry } 234*5e01956fSGlenn Barry err = mecherror_copy(&me_copy, me); 235*5e01956fSGlenn Barry if (err) { 236*5e01956fSGlenn Barry k5_mutex_unlock(&mutex); 237*5e01956fSGlenn Barry return err; 238*5e01956fSGlenn Barry } 239*5e01956fSGlenn Barry err = mecherrmap_add(&m, new_status, me_copy); 240*5e01956fSGlenn Barry k5_mutex_unlock(&mutex); 241*5e01956fSGlenn Barry if (err) { 242*5e01956fSGlenn Barry if (me_copy.mech.length) 243*5e01956fSGlenn Barry free(me_copy.mech.elements); 244*5e01956fSGlenn Barry } 245*5e01956fSGlenn Barry #ifdef DEBUG 246*5e01956fSGlenn Barry fprintf(f, "%s: mapping ", __func__); 247*5e01956fSGlenn Barry mecherror_print(me, f); 248*5e01956fSGlenn Barry fprintf(f, " to %lu: err=%d\nnew map: ", (unsigned long) new_status, err); 249*5e01956fSGlenn Barry mecherrmap_printmap(&m, f); 250*5e01956fSGlenn Barry fprintf(f, "\n"); 251*5e01956fSGlenn Barry if (f != stderr) fclose(f); 252*5e01956fSGlenn Barry #endif 253*5e01956fSGlenn Barry 254*5e01956fSGlenn Barry if (err) 255*5e01956fSGlenn Barry return 0; 256*5e01956fSGlenn Barry else 257*5e01956fSGlenn Barry return new_status; 258*5e01956fSGlenn Barry } 259*5e01956fSGlenn Barry 260*5e01956fSGlenn Barry static gss_OID_desc no_oid = { 0, 0 }; 261*5e01956fSGlenn Barry OM_uint32 gssint_mecherrmap_map_errcode(OM_uint32 errcode) 262*5e01956fSGlenn Barry { 263*5e01956fSGlenn Barry return gssint_mecherrmap_map(errcode, &no_oid); 264*5e01956fSGlenn Barry } 265*5e01956fSGlenn Barry 266*5e01956fSGlenn Barry int gssint_mecherrmap_get(OM_uint32 minor, gss_OID mech_oid, 267*5e01956fSGlenn Barry OM_uint32 *mech_minor) 268*5e01956fSGlenn Barry { 269*5e01956fSGlenn Barry const struct mecherror *p; 270*5e01956fSGlenn Barry int err; 271*5e01956fSGlenn Barry 272*5e01956fSGlenn Barry if (minor == 0) { 273*5e01956fSGlenn Barry return EINVAL; 274*5e01956fSGlenn Barry } 275*5e01956fSGlenn Barry err = k5_mutex_lock(&mutex); 276*5e01956fSGlenn Barry if (err) 277*5e01956fSGlenn Barry return err; 278*5e01956fSGlenn Barry p = mecherrmap_findleft(&m, minor); 279*5e01956fSGlenn Barry k5_mutex_unlock(&mutex); 280*5e01956fSGlenn Barry if (!p) { 281*5e01956fSGlenn Barry return EINVAL; 282*5e01956fSGlenn Barry } 283*5e01956fSGlenn Barry *mech_oid = p->mech; 284*5e01956fSGlenn Barry *mech_minor = p->code; 285*5e01956fSGlenn Barry return 0; 286*5e01956fSGlenn Barry } 287