xref: /freebsd/lib/libgssapi/gss_display_status.c (revision 8d20be1e22095c27faf8fe8b2f0d089739cc742e)
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 }
351