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 <string.h>
29 #ifndef _WIN32
30 #include <unistd.h>
31 #endif
32
33 /* The mapping table is 0-based, but let's export codes that are
34 1-based, keeping 0 for errors or unknown errors.
35
36 The elements in the mapping table currently have separate copies of
37 each OID stored. This is a bit wasteful, but we are assuming the
38 table isn't likely to grow very large. */
39
40 struct mecherror {
41 gss_OID_desc mech;
42 OM_uint32 code;
43 };
44
45 static inline int
cmp_OM_uint32(OM_uint32 m1,OM_uint32 m2)46 cmp_OM_uint32(OM_uint32 m1, OM_uint32 m2)
47 {
48 if (m1 < m2)
49 return -1;
50 else if (m1 > m2)
51 return 1;
52 else
53 return 0;
54 }
55
56 static inline int
mecherror_cmp(struct mecherror m1,struct mecherror m2)57 mecherror_cmp(struct mecherror m1, struct mecherror m2)
58 {
59 if (m1.code < m2.code)
60 return -1;
61 if (m1.code > m2.code)
62 return 1;
63 if (m1.mech.length < m2.mech.length)
64 return -1;
65 if (m1.mech.length > m2.mech.length)
66 return 1;
67 if (m1.mech.length == 0)
68 return 0;
69 return memcmp(m1.mech.elements, m2.mech.elements, m1.mech.length);
70 }
71
72 static void
print_OM_uint32(OM_uint32 value,FILE * f)73 print_OM_uint32 (OM_uint32 value, FILE *f)
74 {
75 fprintf(f, "%lu", (unsigned long) value);
76 }
77
78 static inline int
mecherror_copy(struct mecherror * dest,struct mecherror src)79 mecherror_copy(struct mecherror *dest, struct mecherror src)
80 {
81 *dest = src;
82 if (src.mech.length > 0) {
83 dest->mech.elements = malloc(src.mech.length);
84 if (dest->mech.elements == NULL)
85 return ENOMEM;
86 memcpy(dest->mech.elements, src.mech.elements, src.mech.length);
87 } else {
88 dest->mech.elements = NULL;
89 }
90 return 0;
91 }
92
93 static void
mecherror_print(struct mecherror value,FILE * f)94 mecherror_print(struct mecherror value, FILE *f)
95 {
96 OM_uint32 minor;
97 gss_buffer_desc str;
98 static const struct {
99 const char *oidstr, *name;
100 } mechnames[] = {
101 { "{ 1 2 840 113554 1 2 2 }", "krb5-new" },
102 { "{ 1 3 5 1 5 2 }", "krb5-old" },
103 { "{ 1 2 840 48018 1 2 2 }", "krb5-microsoft" },
104 { "{ 1 3 6 1 5 5 2 }", "spnego" },
105 };
106 unsigned int i;
107
108 fprintf(f, "%lu@", (unsigned long) value.code);
109
110 if (value.mech.length == 0) {
111 fprintf(f, "(com_err)");
112 return;
113 }
114 fprintf(f, "%p=", value.mech.elements);
115 if (generic_gss_oid_to_str(&minor, &value.mech, &str)) {
116 fprintf(f, "(error in conversion)");
117 return;
118 }
119 /* Note: generic_gss_oid_to_str returns a null-terminated string. */
120 for (i = 0; i < sizeof(mechnames)/sizeof(mechnames[0]); i++) {
121 if (!strcmp(str.value, mechnames[i].oidstr) && mechnames[i].name != 0) {
122 fprintf(f, "%s", mechnames[i].name);
123 break;
124 }
125 }
126 if (i == sizeof(mechnames)/sizeof(mechnames[0]))
127 fprintf(f, "%s", (char *) str.value);
128 generic_gss_release_buffer(&minor, &str);
129 }
130
131 #include "errmap.h"
132 #include "krb5.h" /* for KRB5KRB_AP_WRONG_PRINC */
133
134 static mecherrmap m;
135 static k5_mutex_t mutex = K5_MUTEX_PARTIAL_INITIALIZER;
136 static OM_uint32 next_fake = 100000;
137
gssint_mecherrmap_init(void)138 int gssint_mecherrmap_init(void)
139 {
140 int err;
141
142 err = mecherrmap_init(&m);
143 if (err)
144 return err;
145 err = k5_mutex_finish_init(&mutex);
146 if (err) {
147 mecherrmap_destroy(&m);
148 return err;
149 }
150
151 return 0;
152 }
153
154 /* Currently the enumeration template doesn't handle freeing
155 element storage when destroying the collection. */
free_one(OM_uint32 i,struct mecherror value,void * p)156 static int free_one(OM_uint32 i, struct mecherror value, void *p)
157 {
158 free(value.mech.elements);
159 return 0;
160 }
161
gssint_mecherrmap_destroy(void)162 void gssint_mecherrmap_destroy(void)
163 {
164 mecherrmap_foreach(&m, free_one, NULL);
165 mecherrmap_destroy(&m);
166 k5_mutex_destroy(&mutex);
167 }
168
gssint_mecherrmap_map(OM_uint32 minor,const gss_OID_desc * oid)169 OM_uint32 gssint_mecherrmap_map(OM_uint32 minor, const gss_OID_desc * oid)
170 {
171 const struct mecherror *mep;
172 struct mecherror me, me_copy;
173 const OM_uint32 *p;
174 int err;
175 OM_uint32 new_status;
176
177 #ifdef DEBUG
178 FILE *f;
179 f = fopen("/dev/pts/9", "w+");
180 if (f == NULL)
181 f = stderr;
182 #endif
183
184 me.code = minor;
185 me.mech = *oid;
186 k5_mutex_lock(&mutex);
187
188 /* Is this status+oid already mapped? */
189 p = mecherrmap_findright(&m, me);
190 if (p != NULL) {
191 k5_mutex_unlock(&mutex);
192 #ifdef DEBUG
193 fprintf(f, "%s: found ", __FUNCTION__);
194 mecherror_print(me, f);
195 fprintf(f, " in map as %lu\n", (unsigned long) *p);
196 if (f != stderr) fclose(f);
197 #endif
198 return *p;
199 }
200 /* Is this status code already mapped to something else
201 mech-specific? */
202 mep = mecherrmap_findleft(&m, minor);
203 if (mep == NULL) {
204 /* Map it to itself plus this mech-oid. */
205 new_status = minor;
206 } else {
207 /* Already assigned. Pick a fake new value and map it. */
208 /* There's a theoretical infinite loop risk here, if we fill
209 in 2**32 values. Also, returning 0 has a special
210 meaning. */
211 do {
212 next_fake++;
213 new_status = next_fake;
214 if (new_status == 0)
215 /* ??? */;
216 } while (mecherrmap_findleft(&m, new_status) != NULL);
217 }
218 err = mecherror_copy(&me_copy, me);
219 if (err) {
220 k5_mutex_unlock(&mutex);
221 return err;
222 }
223 err = mecherrmap_add(&m, new_status, me_copy);
224 k5_mutex_unlock(&mutex);
225 if (err)
226 free(me_copy.mech.elements);
227 #ifdef DEBUG
228 fprintf(f, "%s: mapping ", __FUNCTION__);
229 mecherror_print(me, f);
230 fprintf(f, " to %lu: err=%d\nnew map: ", (unsigned long) new_status, err);
231 mecherrmap_printmap(&m, f);
232 fprintf(f, "\n");
233 if (f != stderr) fclose(f);
234 #endif
235 if (err)
236 return 0;
237 else
238 return new_status;
239 }
240
241 static gss_OID_desc no_oid = { 0, 0 };
gssint_mecherrmap_map_errcode(OM_uint32 errcode)242 OM_uint32 gssint_mecherrmap_map_errcode(OM_uint32 errcode)
243 {
244 return gssint_mecherrmap_map(errcode, &no_oid);
245 }
246
gssint_mecherrmap_get(OM_uint32 minor,gss_OID mech_oid,OM_uint32 * mech_minor)247 int gssint_mecherrmap_get(OM_uint32 minor, gss_OID mech_oid,
248 OM_uint32 *mech_minor)
249 {
250 const struct mecherror *p;
251
252 if (minor == 0) {
253 return EINVAL;
254 }
255 k5_mutex_lock(&mutex);
256 p = mecherrmap_findleft(&m, minor);
257 k5_mutex_unlock(&mutex);
258 if (!p) {
259 return EINVAL;
260 }
261 *mech_oid = p->mech;
262 *mech_minor = p->code;
263 return 0;
264 }
265