1153838Sdfr/*-
2153838Sdfr * Copyright (c) 2005 Doug Rabson
3153838Sdfr * All rights reserved.
4153838Sdfr *
5153838Sdfr * Redistribution and use in source and binary forms, with or without
6153838Sdfr * modification, are permitted provided that the following conditions
7153838Sdfr * are met:
8153838Sdfr * 1. Redistributions of source code must retain the above copyright
9153838Sdfr *    notice, this list of conditions and the following disclaimer.
10153838Sdfr * 2. Redistributions in binary form must reproduce the above copyright
11153838Sdfr *    notice, this list of conditions and the following disclaimer in the
12153838Sdfr *    documentation and/or other materials provided with the distribution.
13153838Sdfr *
14153838Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15153838Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16153838Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17153838Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18153838Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19153838Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20153838Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21153838Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22153838Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23153838Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24153838Sdfr * SUCH DAMAGE.
25153838Sdfr *
26153838Sdfr *	$FreeBSD$
27153838Sdfr */
28171112Sdfr/*
29229784Suqs * Copyright (c) 1998 - 2005 Kungliga Tekniska H��gskolan
30171112Sdfr * (Royal Institute of Technology, Stockholm, Sweden).
31171112Sdfr * All rights reserved.
32171112Sdfr *
33171112Sdfr * Redistribution and use in source and binary forms, with or without
34171112Sdfr * modification, are permitted provided that the following conditions
35171112Sdfr * are met:
36171112Sdfr *
37171112Sdfr * 1. Redistributions of source code must retain the above copyright
38171112Sdfr *    notice, this list of conditions and the following disclaimer.
39171112Sdfr *
40171112Sdfr * 2. Redistributions in binary form must reproduce the above copyright
41171112Sdfr *    notice, this list of conditions and the following disclaimer in the
42171112Sdfr *    documentation and/or other materials provided with the distribution.
43171112Sdfr *
44171112Sdfr * 3. Neither the name of the Institute nor the names of its contributors
45171112Sdfr *    may be used to endorse or promote products derived from this software
46171112Sdfr *    without specific prior written permission.
47171112Sdfr *
48171112Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
49171112Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50171112Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51171112Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
52171112Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53171112Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54171112Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55171112Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56171112Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57171112Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58171112Sdfr * SUCH DAMAGE.
59171112Sdfr */
60178828Sdfr/*
61229784Suqs * Copyright (c) 1998 - 2005 Kungliga Tekniska H��gskolan
62178828Sdfr * (Royal Institute of Technology, Stockholm, Sweden).
63178828Sdfr * All rights reserved.
64178828Sdfr *
65178828Sdfr * Redistribution and use in source and binary forms, with or without
66178828Sdfr * modification, are permitted provided that the following conditions
67178828Sdfr * are met:
68178828Sdfr *
69178828Sdfr * 1. Redistributions of source code must retain the above copyright
70178828Sdfr *    notice, this list of conditions and the following disclaimer.
71178828Sdfr *
72178828Sdfr * 2. Redistributions in binary form must reproduce the above copyright
73178828Sdfr *    notice, this list of conditions and the following disclaimer in the
74178828Sdfr *    documentation and/or other materials provided with the distribution.
75178828Sdfr *
76178828Sdfr * 3. Neither the name of the Institute nor the names of its contributors
77178828Sdfr *    may be used to endorse or promote products derived from this software
78178828Sdfr *    without specific prior written permission.
79178828Sdfr *
80178828Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
81178828Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
82178828Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
83178828Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
84178828Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
85178828Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
86178828Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
87178828Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
88178828Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
89178828Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
90178828Sdfr * SUCH DAMAGE.
91178828Sdfr */
92153838Sdfr
93153838Sdfr#include <gssapi/gssapi.h>
94178828Sdfr#include <stdio.h>
95153838Sdfr#include <string.h>
96178828Sdfr#include <stdlib.h>
97171112Sdfr#include <errno.h>
98153838Sdfr
99153838Sdfr#include "mech_switch.h"
100178828Sdfr#include "utils.h"
101153838Sdfr
102171112Sdfrstatic const char *
103171112Sdfrcalling_error(OM_uint32 v)
104171112Sdfr{
105171112Sdfr    static const char *msgs[] = {
106171112Sdfr	NULL,			/* 0 */
107171112Sdfr	"A required input parameter could not be read.", /*  */
108171112Sdfr	"A required output parameter could not be written.", /*  */
109171112Sdfr	"A parameter was malformed"
110171112Sdfr    };
111153838Sdfr
112171112Sdfr    v >>= GSS_C_CALLING_ERROR_OFFSET;
113153838Sdfr
114171112Sdfr    if (v == 0)
115171112Sdfr	return "";
116171112Sdfr    else if (v >= sizeof(msgs)/sizeof(*msgs))
117171112Sdfr	return "unknown calling error";
118171112Sdfr    else
119171112Sdfr	return msgs[v];
120171112Sdfr}
121153838Sdfr
122171112Sdfrstatic const char *
123171112Sdfrroutine_error(OM_uint32 v)
124171112Sdfr{
125171112Sdfr    static const char *msgs[] = {
126178828Sdfr	"Function completed successfully",			/* 0 */
127171112Sdfr	"An unsupported mechanism was requested",
128171112Sdfr	"An invalid name was supplied",
129171112Sdfr	"A supplied name was of an unsupported type",
130171112Sdfr	"Incorrect channel bindings were supplied",
131171112Sdfr	"An invalid status code was supplied",
132171112Sdfr	"A token had an invalid MIC",
133171112Sdfr	"No credentials were supplied, "
134171112Sdfr	"or the credentials were unavailable or inaccessible.",
135171112Sdfr	"No context has been established",
136171112Sdfr	"A token was invalid",
137171112Sdfr	"A credential was invalid",
138171112Sdfr	"The referenced credentials have expired",
139171112Sdfr	"The context has expired",
140171112Sdfr	"Miscellaneous failure (see text)",
141171112Sdfr	"The quality-of-protection requested could not be provide",
142171112Sdfr	"The operation is forbidden by local security policy",
143171112Sdfr	"The operation or option is not available",
144171112Sdfr	"The requested credential element already exists",
145171112Sdfr	"The provided name was not a mechanism name.",
146171112Sdfr    };
147171112Sdfr
148171112Sdfr    v >>= GSS_C_ROUTINE_ERROR_OFFSET;
149171112Sdfr
150178828Sdfr    if (v >= sizeof(msgs)/sizeof(*msgs))
151171112Sdfr	return "unknown routine error";
152171112Sdfr    else
153171112Sdfr	return msgs[v];
154171112Sdfr}
155171112Sdfr
156171112Sdfrstatic const char *
157171112Sdfrsupplementary_error(OM_uint32 v)
158171112Sdfr{
159171112Sdfr    static const char *msgs[] = {
160171112Sdfr	"normal completion",
161171112Sdfr	"continuation call to routine required",
162171112Sdfr	"duplicate per-message token detected",
163171112Sdfr	"timed-out per-message token detected",
164171112Sdfr	"reordered (early) per-message token detected",
165171112Sdfr	"skipped predecessor token(s) detected"
166171112Sdfr    };
167171112Sdfr
168171112Sdfr    v >>= GSS_C_SUPPLEMENTARY_OFFSET;
169171112Sdfr
170171112Sdfr    if (v >= sizeof(msgs)/sizeof(*msgs))
171171112Sdfr	return "unknown routine error";
172171112Sdfr    else
173171112Sdfr	return msgs[v];
174171112Sdfr}
175171112Sdfr
176234011Sstas#if defined(__NO_TLS)
177178828Sdfr
178178828Sdfr/*
179178828Sdfr * These platforms don't support TLS on FreeBSD - threads will just
180178828Sdfr * have to step on each other's error values for now.
181178828Sdfr */
182178828Sdfr#define __thread
183178828Sdfr
184178828Sdfr#endif
185178828Sdfr
186178828Sdfrstruct mg_thread_ctx {
187178828Sdfr    gss_OID mech;
188178828Sdfr    OM_uint32 maj_stat;
189178828Sdfr    OM_uint32 min_stat;
190178828Sdfr    gss_buffer_desc maj_error;
191178828Sdfr    gss_buffer_desc min_error;
192178828Sdfr};
193178828Sdfrstatic __thread struct mg_thread_ctx last_error_context;
194178828Sdfr
195178828Sdfrstatic OM_uint32
196178828Sdfr_gss_mg_get_error(const gss_OID mech, OM_uint32 type,
197178828Sdfr		  OM_uint32 value, gss_buffer_t string)
198178828Sdfr{
199178828Sdfr	struct mg_thread_ctx *mg;
200178828Sdfr
201178828Sdfr	mg = &last_error_context;
202178828Sdfr
203178828Sdfr	if (mech != NULL && gss_oid_equal(mg->mech, mech) == 0)
204178828Sdfr		return (GSS_S_BAD_STATUS);
205178828Sdfr
206178828Sdfr	switch (type) {
207178828Sdfr	case GSS_C_GSS_CODE: {
208178828Sdfr		if (value != mg->maj_stat || mg->maj_error.length == 0)
209178828Sdfr			break;
210178828Sdfr		string->value = malloc(mg->maj_error.length);
211178828Sdfr		string->length = mg->maj_error.length;
212178828Sdfr		memcpy(string->value, mg->maj_error.value,
213178828Sdfr		    mg->maj_error.length);
214178828Sdfr		return (GSS_S_COMPLETE);
215178828Sdfr	}
216178828Sdfr	case GSS_C_MECH_CODE: {
217178828Sdfr		if (value != mg->min_stat || mg->min_error.length == 0)
218178828Sdfr			break;
219178828Sdfr		string->value = malloc(mg->min_error.length);
220178828Sdfr		string->length = mg->min_error.length;
221178828Sdfr		memcpy(string->value, mg->min_error.value,
222178828Sdfr		    mg->min_error.length);
223178828Sdfr		return (GSS_S_COMPLETE);
224178828Sdfr	}
225178828Sdfr	}
226178828Sdfr	string->value = NULL;
227178828Sdfr	string->length = 0;
228178828Sdfr	return (GSS_S_BAD_STATUS);
229178828Sdfr}
230178828Sdfr
231178828Sdfrvoid
232178828Sdfr_gss_mg_error(struct _gss_mech_switch *m, OM_uint32 maj, OM_uint32 min)
233178828Sdfr{
234178828Sdfr	OM_uint32 major_status, minor_status;
235178828Sdfr	OM_uint32 message_content;
236178828Sdfr	struct mg_thread_ctx *mg;
237178828Sdfr
238178828Sdfr	mg = &last_error_context;
239178828Sdfr
240178828Sdfr	gss_release_buffer(&minor_status, &mg->maj_error);
241178828Sdfr	gss_release_buffer(&minor_status, &mg->min_error);
242178828Sdfr
243178828Sdfr	mg->mech = &m->gm_mech_oid;
244178828Sdfr	mg->maj_stat = maj;
245178828Sdfr	mg->min_stat = min;
246178828Sdfr
247178828Sdfr	major_status = m->gm_display_status(&minor_status,
248178828Sdfr	    maj,
249178828Sdfr	    GSS_C_GSS_CODE,
250178828Sdfr	    &m->gm_mech_oid,
251178828Sdfr	    &message_content,
252178828Sdfr	    &mg->maj_error);
253178828Sdfr	if (GSS_ERROR(major_status)) {
254178828Sdfr		mg->maj_error.value = NULL;
255178828Sdfr		mg->maj_error.length = 0;
256178828Sdfr	}
257178828Sdfr	major_status = m->gm_display_status(&minor_status,
258178828Sdfr	    min,
259178828Sdfr	    GSS_C_MECH_CODE,
260178828Sdfr	    &m->gm_mech_oid,
261178828Sdfr	    &message_content,
262178828Sdfr	    &mg->min_error);
263178828Sdfr	if (GSS_ERROR(major_status)) {
264178828Sdfr		mg->min_error.value = NULL;
265178828Sdfr		mg->min_error.length = 0;
266178828Sdfr	}
267178828Sdfr}
268178828Sdfr
269153838SdfrOM_uint32
270153838Sdfrgss_display_status(OM_uint32 *minor_status,
271153838Sdfr    OM_uint32 status_value,
272153838Sdfr    int status_type,
273178828Sdfr    const gss_OID mech_type,
274153838Sdfr    OM_uint32 *message_content,
275153838Sdfr    gss_buffer_t status_string)
276153838Sdfr{
277153838Sdfr	OM_uint32 major_status;
278153838Sdfr
279178828Sdfr	_gss_buffer_zero(status_string);
280178828Sdfr	*message_content = 0;
281178828Sdfr
282178828Sdfr	major_status = _gss_mg_get_error(mech_type, status_type,
283178828Sdfr					 status_value, status_string);
284178828Sdfr	if (major_status == GSS_S_COMPLETE) {
285178828Sdfr
286178828Sdfr		*message_content = 0;
287178828Sdfr		*minor_status = 0;
288178828Sdfr		return (GSS_S_COMPLETE);
289171254Sdfr	}
290171254Sdfr
291153838Sdfr	*minor_status = 0;
292153838Sdfr	switch (status_type) {
293171112Sdfr	case GSS_C_GSS_CODE: {
294171112Sdfr		char *buf;
295153838Sdfr
296171112Sdfr		if (GSS_SUPPLEMENTARY_INFO(status_value))
297171112Sdfr		    asprintf(&buf, "%s", supplementary_error(
298171112Sdfr		        GSS_SUPPLEMENTARY_INFO(status_value)));
299171112Sdfr		else
300171112Sdfr		    asprintf (&buf, "%s %s",
301171112Sdfr		        calling_error(GSS_CALLING_ERROR(status_value)),
302171112Sdfr			routine_error(GSS_ROUTINE_ERROR(status_value)));
303171112Sdfr
304178828Sdfr		if (buf == NULL)
305178828Sdfr			break;
306178828Sdfr
307171112Sdfr		status_string->length = strlen(buf);
308171112Sdfr		status_string->value  = buf;
309171112Sdfr
310178828Sdfr		return (GSS_S_COMPLETE);
311171112Sdfr	}
312171112Sdfr	case GSS_C_MECH_CODE: {
313178828Sdfr		OM_uint32 maj_junk, min_junk;
314178828Sdfr		gss_buffer_desc oid;
315178828Sdfr		char *buf;
316178828Sdfr
317178828Sdfr		maj_junk = gss_oid_to_str(&min_junk, mech_type, &oid);
318178828Sdfr		if (maj_junk != GSS_S_COMPLETE) {
319178828Sdfr			oid.value = strdup("unknown");
320178828Sdfr			oid.length = 7;
321153838Sdfr		}
322178828Sdfr
323178828Sdfr		asprintf (&buf, "unknown mech-code %lu for mech %.*s",
324178828Sdfr			  (unsigned long)status_value,
325178828Sdfr			  (int)oid.length, (char *)oid.value);
326178828Sdfr		if (maj_junk == GSS_S_COMPLETE)
327178828Sdfr			gss_release_buffer(&min_junk, &oid);
328178828Sdfr
329178828Sdfr		if (buf == NULL)
330178828Sdfr		    break;
331178828Sdfr
332178828Sdfr		status_string->length = strlen(buf);
333178828Sdfr		status_string->value  = buf;
334178828Sdfr
335178828Sdfr		return (GSS_S_COMPLETE);
336153838Sdfr	}
337171112Sdfr	}
338178828Sdfr	_gss_buffer_zero(status_string);
339153838Sdfr	return (GSS_S_BAD_STATUS);
340153838Sdfr}
341233294Sstas
342233294Sstasvoid
343233294Sstas_gss_mg_collect_error(gss_OID mech, OM_uint32 maj, OM_uint32 min)
344233294Sstas{
345233294Sstas	struct _gss_mech_switch *m;
346233294Sstas
347233294Sstas	m = _gss_find_mech_switch(mech);
348233294Sstas	if (m != NULL)
349233294Sstas		_gss_mg_error(m, maj, min);
350233294Sstas}
351