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