xref: /freebsd/crypto/krb5/src/lib/gssapi/generic/util_errmap.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
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
cmp_OM_uint32(OM_uint32 m1,OM_uint32 m2)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
mecherror_cmp(struct mecherror m1,struct mecherror m2)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
print_OM_uint32(OM_uint32 value,FILE * f)74 print_OM_uint32 (OM_uint32 value, FILE *f)
75 {
76     fprintf(f, "%lu", (unsigned long) value);
77 }
78 
79 static inline int
mecherror_copy(struct mecherror * dest,struct mecherror src)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
mecherror_print(struct mecherror value,FILE * f)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 
gssint_mecherrmap_init(void)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.  */
free_one(OM_uint32 i,struct mecherror value,void * p)157 static int free_one(OM_uint32 i, struct mecherror value, void *p)
158 {
159     free(value.mech.elements);
160     return 0;
161 }
162 
gssint_mecherrmap_destroy(void)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 
gssint_mecherrmap_map(OM_uint32 minor,const gss_OID_desc * oid)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 };
gssint_mecherrmap_map_errcode(OM_uint32 errcode)246 OM_uint32 gssint_mecherrmap_map_errcode(OM_uint32 errcode)
247 {
248     return gssint_mecherrmap_map(errcode, &no_oid);
249 }
250 
gssint_mecherrmap_get(OM_uint32 minor,gss_OID mech_oid,OM_uint32 * mech_minor)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