1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2005 Doug Rabson
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
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
103 static const char *
calling_error(OM_uint32 v)104 calling_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
121 static const char *
routine_error(OM_uint32 v)122 routine_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
155 static const char *
supplementary_error(OM_uint32 v)156 supplementary_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 struct mg_thread_ctx {
176 gss_OID mech;
177 OM_uint32 maj_stat;
178 OM_uint32 min_stat;
179 gss_buffer_desc maj_error;
180 gss_buffer_desc min_error;
181 };
182 static __thread struct mg_thread_ctx last_error_context;
183
184 static OM_uint32
_gss_mg_get_error(const gss_OID mech,OM_uint32 type,OM_uint32 value,gss_buffer_t string)185 _gss_mg_get_error(const gss_OID mech, OM_uint32 type,
186 OM_uint32 value, gss_buffer_t string)
187 {
188 struct mg_thread_ctx *mg;
189
190 mg = &last_error_context;
191
192 if (mech != NULL && gss_oid_equal(mg->mech, mech) == 0)
193 return (GSS_S_BAD_STATUS);
194
195 switch (type) {
196 case GSS_C_GSS_CODE: {
197 if (value != mg->maj_stat || mg->maj_error.length == 0)
198 break;
199 string->value = malloc(mg->maj_error.length);
200 string->length = mg->maj_error.length;
201 memcpy(string->value, mg->maj_error.value,
202 mg->maj_error.length);
203 return (GSS_S_COMPLETE);
204 }
205 case GSS_C_MECH_CODE: {
206 if (value != mg->min_stat || mg->min_error.length == 0)
207 break;
208 string->value = malloc(mg->min_error.length);
209 string->length = mg->min_error.length;
210 memcpy(string->value, mg->min_error.value,
211 mg->min_error.length);
212 return (GSS_S_COMPLETE);
213 }
214 }
215 string->value = NULL;
216 string->length = 0;
217 return (GSS_S_BAD_STATUS);
218 }
219
220 void
_gss_mg_error(struct _gss_mech_switch * m,OM_uint32 maj,OM_uint32 min)221 _gss_mg_error(struct _gss_mech_switch *m, OM_uint32 maj, OM_uint32 min)
222 {
223 OM_uint32 major_status, minor_status;
224 OM_uint32 message_content;
225 struct mg_thread_ctx *mg;
226
227 mg = &last_error_context;
228
229 gss_release_buffer(&minor_status, &mg->maj_error);
230 gss_release_buffer(&minor_status, &mg->min_error);
231
232 mg->mech = &m->gm_mech_oid;
233 mg->maj_stat = maj;
234 mg->min_stat = min;
235
236 major_status = m->gm_display_status(&minor_status,
237 maj,
238 GSS_C_GSS_CODE,
239 &m->gm_mech_oid,
240 &message_content,
241 &mg->maj_error);
242 if (GSS_ERROR(major_status)) {
243 mg->maj_error.value = NULL;
244 mg->maj_error.length = 0;
245 }
246 major_status = m->gm_display_status(&minor_status,
247 min,
248 GSS_C_MECH_CODE,
249 &m->gm_mech_oid,
250 &message_content,
251 &mg->min_error);
252 if (GSS_ERROR(major_status)) {
253 mg->min_error.value = NULL;
254 mg->min_error.length = 0;
255 }
256 }
257
258 OM_uint32
gss_display_status(OM_uint32 * minor_status,OM_uint32 status_value,int status_type,const gss_OID mech_type,OM_uint32 * message_content,gss_buffer_t status_string)259 gss_display_status(OM_uint32 *minor_status,
260 OM_uint32 status_value,
261 int status_type,
262 const gss_OID mech_type,
263 OM_uint32 *message_content,
264 gss_buffer_t status_string)
265 {
266 OM_uint32 major_status;
267
268 _gss_buffer_zero(status_string);
269 *message_content = 0;
270
271 major_status = _gss_mg_get_error(mech_type, status_type,
272 status_value, status_string);
273 if (major_status == GSS_S_COMPLETE) {
274
275 *message_content = 0;
276 *minor_status = 0;
277 return (GSS_S_COMPLETE);
278 }
279
280 *minor_status = 0;
281 switch (status_type) {
282 case GSS_C_GSS_CODE: {
283 char *buf;
284
285 if (GSS_SUPPLEMENTARY_INFO(status_value))
286 asprintf(&buf, "%s", supplementary_error(
287 GSS_SUPPLEMENTARY_INFO(status_value)));
288 else
289 asprintf (&buf, "%s %s",
290 calling_error(GSS_CALLING_ERROR(status_value)),
291 routine_error(GSS_ROUTINE_ERROR(status_value)));
292
293 if (buf == NULL)
294 break;
295
296 status_string->length = strlen(buf);
297 status_string->value = buf;
298
299 return (GSS_S_COMPLETE);
300 }
301 case GSS_C_MECH_CODE: {
302 OM_uint32 maj_junk, min_junk;
303 gss_buffer_desc oid;
304 char *buf;
305
306 maj_junk = gss_oid_to_str(&min_junk, mech_type, &oid);
307 if (maj_junk != GSS_S_COMPLETE) {
308 oid.value = strdup("unknown");
309 oid.length = 7;
310 }
311
312 asprintf (&buf, "unknown mech-code %lu for mech %.*s",
313 (unsigned long)status_value,
314 (int)oid.length, (char *)oid.value);
315 if (maj_junk == GSS_S_COMPLETE)
316 gss_release_buffer(&min_junk, &oid);
317
318 if (buf == NULL)
319 break;
320
321 status_string->length = strlen(buf);
322 status_string->value = buf;
323
324 return (GSS_S_COMPLETE);
325 }
326 }
327 _gss_buffer_zero(status_string);
328 return (GSS_S_BAD_STATUS);
329 }
330
331 void
_gss_mg_collect_error(gss_OID mech,OM_uint32 maj,OM_uint32 min)332 _gss_mg_collect_error(gss_OID mech, OM_uint32 maj, OM_uint32 min)
333 {
334 struct _gss_mech_switch *m;
335
336 m = _gss_find_mech_switch(mech);
337 if (m != NULL)
338 _gss_mg_error(m, maj, min);
339 }
340