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 366940 2020-10-22 16:41:13Z brooks $
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 <sys/param.h>
94#include <gssapi/gssapi.h>
95#include <stdio.h>
96#include <string.h>
97#include <stdlib.h>
98#include <errno.h>
99
100#include "mech_switch.h"
101#include "utils.h"
102
103static const char *
104calling_error(OM_uint32 v)
105{
106    static const char *msgs[] = {
107	[0] = "",
108	[1] = "A required input parameter could not be read.",
109	[2] = "A required output parameter could not be written.",
110	[3] = "A parameter was malformed",
111    };
112
113    v >>= GSS_C_CALLING_ERROR_OFFSET;
114
115    if (v >= nitems(msgs))
116	return "unknown calling error";
117    else
118	return msgs[v];
119}
120
121static const char *
122routine_error(OM_uint32 v)
123{
124    static const char *msgs[] = {
125	[0] = "Function completed successfully",
126	[1] = "An unsupported mechanism was requested",
127	[2] = "An invalid name was supplied",
128	[3] = "A supplied name was of an unsupported type",
129	[4] = "Incorrect channel bindings were supplied",
130	[5] = "An invalid status code was supplied",
131	[6] = "A token had an invalid MIC",
132	[7] = ("No credentials were supplied, "
133	    "or the credentials were unavailable or inaccessible."),
134	[8] = "No context has been established",
135	[9] = "A token was invalid",
136	[10] = "A credential was invalid",
137	[11] =  "The referenced credentials have expired",
138	[12] = "The context has expired",
139	[13] = "Miscellaneous failure (see text)",
140	[14] = "The quality-of-protection requested could not be provide",
141	[15] = "The operation is forbidden by local security policy",
142	[16] = "The operation or option is not available",
143	[17] = "The requested credential element already exists",
144	[18] = "The provided name was not a mechanism name.",
145    };
146
147    v >>= GSS_C_ROUTINE_ERROR_OFFSET;
148
149    if (v >= nitems(msgs))
150	return "unknown routine error";
151    else
152	return msgs[v];
153}
154
155static const char *
156supplementary_error(OM_uint32 v)
157{
158    static const char *msgs[] = {
159	[0] = "normal completion",
160	[1] = "continuation call to routine required",
161	[2] = "duplicate per-message token detected",
162	[3] = "timed-out per-message token detected",
163	[4] = "reordered (early) per-message token detected",
164	[5] = "skipped predecessor token(s) detected",
165    };
166
167    v >>= GSS_C_SUPPLEMENTARY_OFFSET;
168
169    if (v >= nitems(msgs))
170	return "unknown routine error";
171    else
172	return msgs[v];
173}
174
175#if defined(__NO_TLS)
176
177/*
178 * These platforms don't support TLS on FreeBSD - threads will just
179 * have to step on each other's error values for now.
180 */
181#define __thread
182
183#endif
184
185struct mg_thread_ctx {
186    gss_OID mech;
187    OM_uint32 maj_stat;
188    OM_uint32 min_stat;
189    gss_buffer_desc maj_error;
190    gss_buffer_desc min_error;
191};
192static __thread struct mg_thread_ctx last_error_context;
193
194static OM_uint32
195_gss_mg_get_error(const gss_OID mech, OM_uint32 type,
196		  OM_uint32 value, gss_buffer_t string)
197{
198	struct mg_thread_ctx *mg;
199
200	mg = &last_error_context;
201
202	if (mech != NULL && gss_oid_equal(mg->mech, mech) == 0)
203		return (GSS_S_BAD_STATUS);
204
205	switch (type) {
206	case GSS_C_GSS_CODE: {
207		if (value != mg->maj_stat || mg->maj_error.length == 0)
208			break;
209		string->value = malloc(mg->maj_error.length);
210		string->length = mg->maj_error.length;
211		memcpy(string->value, mg->maj_error.value,
212		    mg->maj_error.length);
213		return (GSS_S_COMPLETE);
214	}
215	case GSS_C_MECH_CODE: {
216		if (value != mg->min_stat || mg->min_error.length == 0)
217			break;
218		string->value = malloc(mg->min_error.length);
219		string->length = mg->min_error.length;
220		memcpy(string->value, mg->min_error.value,
221		    mg->min_error.length);
222		return (GSS_S_COMPLETE);
223	}
224	}
225	string->value = NULL;
226	string->length = 0;
227	return (GSS_S_BAD_STATUS);
228}
229
230void
231_gss_mg_error(struct _gss_mech_switch *m, OM_uint32 maj, OM_uint32 min)
232{
233	OM_uint32 major_status, minor_status;
234	OM_uint32 message_content;
235	struct mg_thread_ctx *mg;
236
237	mg = &last_error_context;
238
239	gss_release_buffer(&minor_status, &mg->maj_error);
240	gss_release_buffer(&minor_status, &mg->min_error);
241
242	mg->mech = &m->gm_mech_oid;
243	mg->maj_stat = maj;
244	mg->min_stat = min;
245
246	major_status = m->gm_display_status(&minor_status,
247	    maj,
248	    GSS_C_GSS_CODE,
249	    &m->gm_mech_oid,
250	    &message_content,
251	    &mg->maj_error);
252	if (GSS_ERROR(major_status)) {
253		mg->maj_error.value = NULL;
254		mg->maj_error.length = 0;
255	}
256	major_status = m->gm_display_status(&minor_status,
257	    min,
258	    GSS_C_MECH_CODE,
259	    &m->gm_mech_oid,
260	    &message_content,
261	    &mg->min_error);
262	if (GSS_ERROR(major_status)) {
263		mg->min_error.value = NULL;
264		mg->min_error.length = 0;
265	}
266}
267
268OM_uint32
269gss_display_status(OM_uint32 *minor_status,
270    OM_uint32 status_value,
271    int status_type,
272    const gss_OID mech_type,
273    OM_uint32 *message_content,
274    gss_buffer_t status_string)
275{
276	OM_uint32 major_status;
277
278	_gss_buffer_zero(status_string);
279	*message_content = 0;
280
281	major_status = _gss_mg_get_error(mech_type, status_type,
282					 status_value, status_string);
283	if (major_status == GSS_S_COMPLETE) {
284
285		*message_content = 0;
286		*minor_status = 0;
287		return (GSS_S_COMPLETE);
288	}
289
290	*minor_status = 0;
291	switch (status_type) {
292	case GSS_C_GSS_CODE: {
293		char *buf;
294
295		if (GSS_SUPPLEMENTARY_INFO(status_value))
296		    asprintf(&buf, "%s", supplementary_error(
297		        GSS_SUPPLEMENTARY_INFO(status_value)));
298		else
299		    asprintf (&buf, "%s %s",
300		        calling_error(GSS_CALLING_ERROR(status_value)),
301			routine_error(GSS_ROUTINE_ERROR(status_value)));
302
303		if (buf == NULL)
304			break;
305
306		status_string->length = strlen(buf);
307		status_string->value  = buf;
308
309		return (GSS_S_COMPLETE);
310	}
311	case GSS_C_MECH_CODE: {
312		OM_uint32 maj_junk, min_junk;
313		gss_buffer_desc oid;
314		char *buf;
315
316		maj_junk = gss_oid_to_str(&min_junk, mech_type, &oid);
317		if (maj_junk != GSS_S_COMPLETE) {
318			oid.value = strdup("unknown");
319			oid.length = 7;
320		}
321
322		asprintf (&buf, "unknown mech-code %lu for mech %.*s",
323			  (unsigned long)status_value,
324			  (int)oid.length, (char *)oid.value);
325		if (maj_junk == GSS_S_COMPLETE)
326			gss_release_buffer(&min_junk, &oid);
327
328		if (buf == NULL)
329		    break;
330
331		status_string->length = strlen(buf);
332		status_string->value  = buf;
333
334		return (GSS_S_COMPLETE);
335	}
336	}
337	_gss_buffer_zero(status_string);
338	return (GSS_S_BAD_STATUS);
339}
340
341void
342_gss_mg_collect_error(gss_OID mech, OM_uint32 maj, OM_uint32 min)
343{
344	struct _gss_mech_switch *m;
345
346	m = _gss_find_mech_switch(mech);
347	if (m != NULL)
348		_gss_mg_error(m, maj, min);
349}
350