1178825Sdfr/*
2233294Sstas * Copyright (c) 1998 - 2006 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34233294Sstas#include "gsskrb5_locl.h"
35178825Sdfr
36178825Sdfrstatic const char *
37178825Sdfrcalling_error(OM_uint32 v)
38178825Sdfr{
39178825Sdfr    static const char *msgs[] = {
40178825Sdfr	NULL,			/* 0 */
41178825Sdfr	"A required input parameter could not be read.", /*  */
42178825Sdfr	"A required output parameter could not be written.", /*  */
43178825Sdfr	"A parameter was malformed"
44178825Sdfr    };
45178825Sdfr
46178825Sdfr    v >>= GSS_C_CALLING_ERROR_OFFSET;
47178825Sdfr
48178825Sdfr    if (v == 0)
49178825Sdfr	return "";
50178825Sdfr    else if (v >= sizeof(msgs)/sizeof(*msgs))
51178825Sdfr	return "unknown calling error";
52178825Sdfr    else
53178825Sdfr	return msgs[v];
54178825Sdfr}
55178825Sdfr
56178825Sdfrstatic const char *
57178825Sdfrroutine_error(OM_uint32 v)
58178825Sdfr{
59178825Sdfr    static const char *msgs[] = {
60178825Sdfr	NULL,			/* 0 */
61178825Sdfr	"An unsupported mechanism was requested",
62178825Sdfr	"An invalid name was supplied",
63178825Sdfr	"A supplied name was of an unsupported type",
64178825Sdfr	"Incorrect channel bindings were supplied",
65178825Sdfr	"An invalid status code was supplied",
66178825Sdfr	"A token had an invalid MIC",
67178825Sdfr	"No credentials were supplied, "
68178825Sdfr	"or the credentials were unavailable or inaccessible.",
69178825Sdfr	"No context has been established",
70178825Sdfr	"A token was invalid",
71178825Sdfr	"A credential was invalid",
72178825Sdfr	"The referenced credentials have expired",
73178825Sdfr	"The context has expired",
74178825Sdfr	"Miscellaneous failure (see text)",
75178825Sdfr	"The quality-of-protection requested could not be provide",
76178825Sdfr	"The operation is forbidden by local security policy",
77178825Sdfr	"The operation or option is not available",
78178825Sdfr	"The requested credential element already exists",
79178825Sdfr	"The provided name was not a mechanism name.",
80178825Sdfr    };
81178825Sdfr
82178825Sdfr    v >>= GSS_C_ROUTINE_ERROR_OFFSET;
83178825Sdfr
84178825Sdfr    if (v == 0)
85178825Sdfr	return "";
86178825Sdfr    else if (v >= sizeof(msgs)/sizeof(*msgs))
87178825Sdfr	return "unknown routine error";
88178825Sdfr    else
89178825Sdfr	return msgs[v];
90178825Sdfr}
91178825Sdfr
92178825Sdfrstatic const char *
93178825Sdfrsupplementary_error(OM_uint32 v)
94178825Sdfr{
95178825Sdfr    static const char *msgs[] = {
96178825Sdfr	"normal completion",
97178825Sdfr	"continuation call to routine required",
98178825Sdfr	"duplicate per-message token detected",
99178825Sdfr	"timed-out per-message token detected",
100178825Sdfr	"reordered (early) per-message token detected",
101178825Sdfr	"skipped predecessor token(s) detected"
102178825Sdfr    };
103178825Sdfr
104178825Sdfr    v >>= GSS_C_SUPPLEMENTARY_OFFSET;
105178825Sdfr
106178825Sdfr    if (v >= sizeof(msgs)/sizeof(*msgs))
107178825Sdfr	return "unknown routine error";
108178825Sdfr    else
109178825Sdfr	return msgs[v];
110178825Sdfr}
111178825Sdfr
112178825Sdfrvoid
113178825Sdfr_gsskrb5_clear_status (void)
114178825Sdfr{
115178825Sdfr    krb5_context context;
116178825Sdfr
117178825Sdfr    if (_gsskrb5_init (&context) != 0)
118178825Sdfr	return;
119233294Sstas    krb5_clear_error_message(context);
120178825Sdfr}
121178825Sdfr
122178825Sdfrvoid
123233294Sstas_gsskrb5_set_status (int ret, const char *fmt, ...)
124178825Sdfr{
125178825Sdfr    krb5_context context;
126178825Sdfr    va_list args;
127178825Sdfr    char *str;
128233294Sstas    int e;
129178825Sdfr
130178825Sdfr    if (_gsskrb5_init (&context) != 0)
131178825Sdfr	return;
132178825Sdfr
133178825Sdfr    va_start(args, fmt);
134233294Sstas    e = vasprintf(&str, fmt, args);
135178825Sdfr    va_end(args);
136233294Sstas    if (e >= 0 && str) {
137233294Sstas	krb5_set_error_message(context, ret, "%s", str);
138178825Sdfr	free(str);
139178825Sdfr    }
140178825Sdfr}
141178825Sdfr
142233294SstasOM_uint32 GSSAPI_CALLCONV _gsskrb5_display_status
143178825Sdfr(OM_uint32		*minor_status,
144178825Sdfr OM_uint32		 status_value,
145178825Sdfr int			 status_type,
146178825Sdfr const gss_OID	 mech_type,
147178825Sdfr OM_uint32		*message_context,
148178825Sdfr gss_buffer_t	 status_string)
149178825Sdfr{
150178825Sdfr    krb5_context context;
151233294Sstas    char *buf = NULL;
152233294Sstas    int e = 0;
153178825Sdfr
154178825Sdfr    GSSAPI_KRB5_INIT (&context);
155178825Sdfr
156178825Sdfr    status_string->length = 0;
157178825Sdfr    status_string->value = NULL;
158178825Sdfr
159178825Sdfr    if (gss_oid_equal(mech_type, GSS_C_NO_OID) == 0 &&
160178825Sdfr	gss_oid_equal(mech_type, GSS_KRB5_MECHANISM) == 0) {
161178825Sdfr	*minor_status = 0;
162178825Sdfr	return GSS_C_GSS_CODE;
163178825Sdfr    }
164178825Sdfr
165178825Sdfr    if (status_type == GSS_C_GSS_CODE) {
166178825Sdfr	if (GSS_SUPPLEMENTARY_INFO(status_value))
167233294Sstas	    e = asprintf(&buf, "%s",
168233294Sstas			 supplementary_error(GSS_SUPPLEMENTARY_INFO(status_value)));
169178825Sdfr	else
170233294Sstas	    e = asprintf (&buf, "%s %s",
171233294Sstas			  calling_error(GSS_CALLING_ERROR(status_value)),
172233294Sstas			  routine_error(GSS_ROUTINE_ERROR(status_value)));
173178825Sdfr    } else if (status_type == GSS_C_MECH_CODE) {
174233294Sstas	const char *buf2 = krb5_get_error_message(context, status_value);
175233294Sstas	if (buf2) {
176233294Sstas	    buf = strdup(buf2);
177233294Sstas	    krb5_free_error_message(context, buf2);
178233294Sstas	} else {
179233294Sstas	    e = asprintf(&buf, "unknown mech error-code %u",
180178825Sdfr			 (unsigned)status_value);
181178825Sdfr	}
182178825Sdfr    } else {
183178825Sdfr	*minor_status = EINVAL;
184178825Sdfr	return GSS_S_BAD_STATUS;
185178825Sdfr    }
186178825Sdfr
187233294Sstas    if (e < 0 || buf == NULL) {
188178825Sdfr	*minor_status = ENOMEM;
189178825Sdfr	return GSS_S_FAILURE;
190178825Sdfr    }
191178825Sdfr
192178825Sdfr    *message_context = 0;
193178825Sdfr    *minor_status = 0;
194178825Sdfr
195178825Sdfr    status_string->length = strlen(buf);
196178825Sdfr    status_string->value  = buf;
197233294Sstas
198178825Sdfr    return GSS_S_COMPLETE;
199178825Sdfr}
200