gss_display_status.c revision 331722
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: stable/11/lib/libgssapi/gss_display_status.c 331722 2018-03-29 02:50:57Z eadler $
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
102static const char *
103calling_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
122static const char *
123routine_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
156static const char *
157supplementary_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
186struct 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};
193static __thread struct mg_thread_ctx last_error_context;
194
195static 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
231void
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
269OM_uint32
270gss_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
342void
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}
351