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