]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - lib/libgssapi/gss_display_status.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / lib / libgssapi / gss_display_status.c
1 /*-
2  * Copyright (c) 2005 Doug Rabson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *      $FreeBSD$
27  */
28 /*
29  * Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan
30  * (Royal Institute of Technology, Stockholm, Sweden). 
31  * All rights reserved. 
32  *
33  * Redistribution and use in source and binary forms, with or without 
34  * modification, are permitted provided that the following conditions 
35  * are met: 
36  *
37  * 1. Redistributions of source code must retain the above copyright 
38  *    notice, this list of conditions and the following disclaimer. 
39  *
40  * 2. Redistributions in binary form must reproduce the above copyright 
41  *    notice, this list of conditions and the following disclaimer in the 
42  *    documentation and/or other materials provided with the distribution. 
43  *
44  * 3. Neither the name of the Institute nor the names of its contributors 
45  *    may be used to endorse or promote products derived from this software 
46  *    without specific prior written permission. 
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
58  * SUCH DAMAGE. 
59  */
60 /*
61  * Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan
62  * (Royal Institute of Technology, Stockholm, Sweden). 
63  * All rights reserved. 
64  *
65  * Redistribution and use in source and binary forms, with or without 
66  * modification, are permitted provided that the following conditions 
67  * are met: 
68  *
69  * 1. Redistributions of source code must retain the above copyright 
70  *    notice, this list of conditions and the following disclaimer. 
71  *
72  * 2. Redistributions in binary form must reproduce the above copyright 
73  *    notice, this list of conditions and the following disclaimer in the 
74  *    documentation and/or other materials provided with the distribution. 
75  *
76  * 3. Neither the name of the Institute nor the names of its contributors 
77  *    may be used to endorse or promote products derived from this software 
78  *    without specific prior written permission. 
79  *
80  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
81  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
82  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
83  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
84  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
85  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
86  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
87  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
88  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
89  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
90  * SUCH DAMAGE. 
91  */
92
93 #include <gssapi/gssapi.h>
94 #include <stdio.h>
95 #include <string.h>
96 #include <stdlib.h>
97 #include <errno.h>
98
99 #include "mech_switch.h"
100 #include "utils.h"
101
102 static const char *
103 calling_error(OM_uint32 v)
104 {
105     static const char *msgs[] = {
106         NULL,                   /* 0 */
107         "A required input parameter could not be read.", /*  */
108         "A required output parameter could not be written.", /*  */
109         "A parameter was malformed"
110     };
111
112     v >>= GSS_C_CALLING_ERROR_OFFSET;
113
114     if (v == 0)
115         return "";
116     else if (v >= sizeof(msgs)/sizeof(*msgs))
117         return "unknown calling error";
118     else
119         return msgs[v];
120 }
121
122 static const char *
123 routine_error(OM_uint32 v)
124 {
125     static const char *msgs[] = {
126         "Function completed successfully",                      /* 0 */
127         "An unsupported mechanism was requested",
128         "An invalid name was supplied",
129         "A supplied name was of an unsupported type",
130         "Incorrect channel bindings were supplied",
131         "An invalid status code was supplied",
132         "A token had an invalid MIC",
133         "No credentials were supplied, "
134         "or the credentials were unavailable or inaccessible.",
135         "No context has been established",
136         "A token was invalid",
137         "A credential was invalid",
138         "The referenced credentials have expired",
139         "The context has expired",
140         "Miscellaneous failure (see text)",
141         "The quality-of-protection requested could not be provide",
142         "The operation is forbidden by local security policy",
143         "The operation or option is not available",
144         "The requested credential element already exists",
145         "The provided name was not a mechanism name.",
146     };
147
148     v >>= GSS_C_ROUTINE_ERROR_OFFSET;
149
150     if (v >= sizeof(msgs)/sizeof(*msgs))
151         return "unknown routine error";
152     else
153         return msgs[v];
154 }
155
156 static const char *
157 supplementary_error(OM_uint32 v)
158 {
159     static const char *msgs[] = {
160         "normal completion",
161         "continuation call to routine required",
162         "duplicate per-message token detected",
163         "timed-out per-message token detected",
164         "reordered (early) per-message token detected",
165         "skipped predecessor token(s) detected"
166     };
167
168     v >>= GSS_C_SUPPLEMENTARY_OFFSET;
169
170     if (v >= sizeof(msgs)/sizeof(*msgs))
171         return "unknown routine error";
172     else
173         return msgs[v];
174 }
175
176 #if defined(__NO_TLS)
177
178 /*
179  * These platforms don't support TLS on FreeBSD - threads will just
180  * have to step on each other's error values for now.
181  */
182 #define __thread
183
184 #endif
185
186 struct mg_thread_ctx {
187     gss_OID mech;
188     OM_uint32 maj_stat;
189     OM_uint32 min_stat;
190     gss_buffer_desc maj_error;
191     gss_buffer_desc min_error;
192 };
193 static __thread struct mg_thread_ctx last_error_context;
194
195 static OM_uint32
196 _gss_mg_get_error(const gss_OID mech, OM_uint32 type,
197                   OM_uint32 value, gss_buffer_t string)
198 {
199         struct mg_thread_ctx *mg;
200
201         mg = &last_error_context;
202
203         if (mech != NULL && gss_oid_equal(mg->mech, mech) == 0)
204                 return (GSS_S_BAD_STATUS);
205
206         switch (type) {
207         case GSS_C_GSS_CODE: {
208                 if (value != mg->maj_stat || mg->maj_error.length == 0)
209                         break;
210                 string->value = malloc(mg->maj_error.length);
211                 string->length = mg->maj_error.length;
212                 memcpy(string->value, mg->maj_error.value,
213                     mg->maj_error.length);
214                 return (GSS_S_COMPLETE);
215         }
216         case GSS_C_MECH_CODE: {
217                 if (value != mg->min_stat || mg->min_error.length == 0)
218                         break;
219                 string->value = malloc(mg->min_error.length);
220                 string->length = mg->min_error.length;
221                 memcpy(string->value, mg->min_error.value,
222                     mg->min_error.length);
223                 return (GSS_S_COMPLETE);
224         }
225         }
226         string->value = NULL;
227         string->length = 0;
228         return (GSS_S_BAD_STATUS);
229 }
230
231 void
232 _gss_mg_error(struct _gss_mech_switch *m, OM_uint32 maj, OM_uint32 min)
233 {
234         OM_uint32 major_status, minor_status;
235         OM_uint32 message_content;
236         struct mg_thread_ctx *mg;
237
238         mg = &last_error_context;
239
240         gss_release_buffer(&minor_status, &mg->maj_error);
241         gss_release_buffer(&minor_status, &mg->min_error);
242
243         mg->mech = &m->gm_mech_oid;
244         mg->maj_stat = maj;
245         mg->min_stat = min;
246
247         major_status = m->gm_display_status(&minor_status,
248             maj, 
249             GSS_C_GSS_CODE,
250             &m->gm_mech_oid,
251             &message_content,
252             &mg->maj_error);
253         if (GSS_ERROR(major_status)) {
254                 mg->maj_error.value = NULL;
255                 mg->maj_error.length = 0;
256         }
257         major_status = m->gm_display_status(&minor_status,
258             min, 
259             GSS_C_MECH_CODE,
260             &m->gm_mech_oid,
261             &message_content,
262             &mg->min_error);
263         if (GSS_ERROR(major_status)) {
264                 mg->min_error.value = NULL;
265                 mg->min_error.length = 0;
266         }
267 }
268
269 OM_uint32
270 gss_display_status(OM_uint32 *minor_status,
271     OM_uint32 status_value,
272     int status_type,
273     const gss_OID mech_type,
274     OM_uint32 *message_content,
275     gss_buffer_t status_string)
276 {
277         OM_uint32 major_status;
278
279         _gss_buffer_zero(status_string);
280         *message_content = 0;
281
282         major_status = _gss_mg_get_error(mech_type, status_type,
283                                          status_value, status_string);
284         if (major_status == GSS_S_COMPLETE) {
285
286                 *message_content = 0;
287                 *minor_status = 0;
288                 return (GSS_S_COMPLETE);
289         }
290
291         *minor_status = 0;
292         switch (status_type) {
293         case GSS_C_GSS_CODE: {
294                 char *buf;
295
296                 if (GSS_SUPPLEMENTARY_INFO(status_value))
297                     asprintf(&buf, "%s", supplementary_error(
298                         GSS_SUPPLEMENTARY_INFO(status_value)));
299                 else
300                     asprintf (&buf, "%s %s",
301                         calling_error(GSS_CALLING_ERROR(status_value)),
302                         routine_error(GSS_ROUTINE_ERROR(status_value)));
303
304                 if (buf == NULL)
305                         break;
306
307                 status_string->length = strlen(buf);
308                 status_string->value  = buf;
309
310                 return (GSS_S_COMPLETE);
311         }
312         case GSS_C_MECH_CODE: {
313                 OM_uint32 maj_junk, min_junk;
314                 gss_buffer_desc oid;
315                 char *buf;
316
317                 maj_junk = gss_oid_to_str(&min_junk, mech_type, &oid);
318                 if (maj_junk != GSS_S_COMPLETE) {
319                         oid.value = strdup("unknown");
320                         oid.length = 7;
321                 }
322
323                 asprintf (&buf, "unknown mech-code %lu for mech %.*s",
324                           (unsigned long)status_value,
325                           (int)oid.length, (char *)oid.value);
326                 if (maj_junk == GSS_S_COMPLETE)
327                         gss_release_buffer(&min_junk, &oid);
328
329                 if (buf == NULL)
330                     break;
331
332                 status_string->length = strlen(buf);
333                 status_string->value  = buf;
334
335                 return (GSS_S_COMPLETE);
336         }
337         }
338         _gss_buffer_zero(status_string);
339         return (GSS_S_BAD_STATUS);
340 }
341
342 void
343 _gss_mg_collect_error(gss_OID mech, OM_uint32 maj, OM_uint32 min)
344 {
345         struct _gss_mech_switch *m;
346
347         m = _gss_find_mech_switch(mech);
348         if (m != NULL)
349                 _gss_mg_error(m, maj, min);
350 }