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