Branch data Line data Source code
1 : : /* error.c --- Error handling functionality.
2 : : * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010 Simon Josefsson
3 : : *
4 : : * This file is part of the Generic Security Service (GSS).
5 : : *
6 : : * GSS is free software; you can redistribute it and/or modify it
7 : : * under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 3 of the License, or
9 : : * (at your option) any later version.
10 : : *
11 : : * GSS is distributed in the hope that it will be useful, but WITHOUT
12 : : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 : : * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 : : * License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with GSS; if not, see http://www.gnu.org/licenses or write to
18 : : * the Free Software Foundation, Inc., 51 Franklin Street, Fifth
19 : : * Floor, Boston, MA 02110-1301, USA.
20 : : *
21 : : */
22 : :
23 : : #include "internal.h"
24 : :
25 : : /* _gss_find_mech */
26 : : #include "meta.h"
27 : :
28 : : struct gss_status_codes
29 : : {
30 : : gss_uint32 err;
31 : : const char *name;
32 : : const char *text;
33 : : };
34 : :
35 : : static struct gss_status_codes gss_calling_errors[] = {
36 : : {GSS_S_CALL_INACCESSIBLE_READ, "GSS_S_CALL_INACCESSIBLE_READ",
37 : : N_("A required input parameter could not be read")},
38 : : {GSS_S_CALL_INACCESSIBLE_WRITE, "GSS_S_CALL_INACCESSIBLE_WRITE",
39 : : N_("A required output parameter could not be written")},
40 : : {GSS_S_CALL_BAD_STRUCTURE, "GSS_S_CALL_BAD_STRUCTURE",
41 : : N_("A parameter was malformed")}
42 : : };
43 : :
44 : : static struct gss_status_codes gss_routine_errors[] = {
45 : : {GSS_S_BAD_MECH, "GSS_S_BAD_MECH",
46 : : N_("An unsupported mechanism was requested")},
47 : : {GSS_S_BAD_NAME, "GSS_S_BAD_NAME",
48 : : N_("An invalid name was supplied")},
49 : : {GSS_S_BAD_NAMETYPE, "GSS_S_BAD_NAMETYPE",
50 : : N_("A supplied name was of an unsupported type")},
51 : : {GSS_S_BAD_BINDINGS, "GSS_S_BAD_BINDINGS",
52 : : N_("Incorrect channel bindings were supplied")},
53 : : {GSS_S_BAD_STATUS, "GSS_S_BAD_STATUS",
54 : : N_("An invalid status code was supplied")},
55 : : {GSS_S_BAD_SIG, "GSS_S_BAD_SIG",
56 : : N_("A token had an invalid MIC")},
57 : : {GSS_S_NO_CRED, "GSS_S_NO_CRED",
58 : : N_("No credentials were supplied, or the credentials were unavailable "
59 : : "or inaccessible")},
60 : : {GSS_S_NO_CONTEXT, "GSS_S_NO_CONTEXT",
61 : : N_("No context has been established")},
62 : : {GSS_S_DEFECTIVE_TOKEN, "GSS_S_DEFECTIVE_TOKEN",
63 : : N_("A token was invalid")},
64 : : {GSS_S_DEFECTIVE_CREDENTIAL, "GSS_S_DEFECTIVE_CREDENTIAL",
65 : : N_("A credential was invalid")},
66 : : {GSS_S_CREDENTIALS_EXPIRED, "GSS_S_CREDENTIALS_EXPIRED",
67 : : N_("The referenced credentials have expired")},
68 : : {GSS_S_CONTEXT_EXPIRED, "GSS_S_CONTEXT_EXPIRED",
69 : : N_("The context has expired")},
70 : : {GSS_S_FAILURE, "GSS_S_FAILURE",
71 : : N_("Unspecified error in underlying mechanism")},
72 : : {GSS_S_BAD_QOP, "GSS_S_BAD_QOP",
73 : : N_("The quality-of-protection requested could not be provided")},
74 : : {GSS_S_UNAUTHORIZED, "GSS_S_UNAUTHORIZED",
75 : : N_("The operation is forbidden by local security policy")},
76 : : {GSS_S_UNAVAILABLE, "GSS_S_UNAVAILABLE",
77 : : N_("The operation or option is unavailable")},
78 : : {GSS_S_DUPLICATE_ELEMENT, "GSS_S_DUPLICATE_ELEMENT",
79 : : N_("The requested credential element already exists")},
80 : : {GSS_S_NAME_NOT_MN, "GSS_S_NAME_NOT_MN",
81 : : N_("The provided name was not a mechanism name")}
82 : : };
83 : :
84 : : static struct gss_status_codes gss_supplementary_errors[] = {
85 : : {GSS_S_CONTINUE_NEEDED, "GSS_S_CONTINUE_NEEDED",
86 : : N_("The gss_init_sec_context() or gss_accept_sec_context() function "
87 : : "must be called again to complete its function")},
88 : : {GSS_S_DUPLICATE_TOKEN, "GSS_S_DUPLICATE_TOKEN",
89 : : N_("The token was a duplicate of an earlier token")},
90 : : {GSS_S_OLD_TOKEN, "GSS_S_OLD_TOKEN",
91 : : N_("The token's validity period has expired")},
92 : : {GSS_S_UNSEQ_TOKEN, "GSS_S_UNSEQ_TOKEN",
93 : : N_("A later token has already been processed")},
94 : : {GSS_S_GAP_TOKEN, "GSS_S_GAP_TOKEN",
95 : : N_("An expected per-message token was not received")}
96 : : };
97 : :
98 : : /**
99 : : * gss_display_status:
100 : : * @minor_status: (integer, modify) Mechanism specific status code.
101 : : * @status_value: (Integer, read) Status value to be converted.
102 : : * @status_type: (Integer, read) GSS_C_GSS_CODE - status_value is a
103 : : * GSS status code. GSS_C_MECH_CODE - status_value is a mechanism
104 : : * status code.
105 : : * @mech_type: (Object ID, read, optional) Underlying mechanism (used
106 : : * to interpret a minor status value). Supply GSS_C_NO_OID to obtain
107 : : * the system default.
108 : : * @message_context: (Integer, read/modify) Should be initialized to
109 : : * zero by the application prior to the first call. On return from
110 : : * gss_display_status(), a non-zero status_value parameter indicates
111 : : * that additional messages may be extracted from the status code
112 : : * via subsequent calls to gss_display_status(), passing the same
113 : : * status_value, status_type, mech_type, and message_context
114 : : * parameters.
115 : : * @status_string: (buffer, character string, modify) Textual
116 : : * interpretation of the status_value. Storage associated with this
117 : : * parameter must be freed by the application after use with a call
118 : : * to gss_release_buffer().
119 : : *
120 : : * Allows an application to obtain a textual representation of a
121 : : * GSS-API status code, for display to the user or for logging
122 : : * purposes. Since some status values may indicate multiple
123 : : * conditions, applications may need to call gss_display_status
124 : : * multiple times, each call generating a single text string. The
125 : : * message_context parameter is used by gss_display_status to store
126 : : * state information about which error messages have already been
127 : : * extracted from a given status_value; message_context must be
128 : : * initialized to 0 by the application prior to the first call, and
129 : : * gss_display_status will return a non-zero value in this parameter
130 : : * if there are further messages to extract.
131 : : *
132 : : * The message_context parameter contains all state information
133 : : * required by gss_display_status in order to extract further messages
134 : : * from the status_value; even when a non-zero value is returned in
135 : : * this parameter, the application is not required to call
136 : : * gss_display_status again unless subsequent messages are desired.
137 : : * The following code extracts all messages from a given status code
138 : : * and prints them to stderr:
139 : : *
140 : : *
141 : : * ---------------------------------------------------
142 : : * OM_uint32 message_context;
143 : : * OM_uint32 status_code;
144 : : * OM_uint32 maj_status;
145 : : * OM_uint32 min_status;
146 : : * gss_buffer_desc status_string;
147 : : *
148 : : * ...
149 : : *
150 : : * message_context = 0;
151 : : *
152 : : * do {
153 : : * maj_status = gss_display_status (
154 : : * &min_status,
155 : : * status_code,
156 : : * GSS_C_GSS_CODE,
157 : : * GSS_C_NO_OID,
158 : : * &message_context,
159 : : * &status_string)
160 : : *
161 : : * fprintf(stderr,
162 : : * "%.*s\n",
163 : : * (int)status_string.length,
164 : : *
165 : : * (char *)status_string.value);
166 : : *
167 : : * gss_release_buffer(&min_status, &status_string);
168 : : *
169 : : * } while (message_context != 0);
170 : : * ---------------------------------------------------
171 : : *
172 : : * Return value:
173 : : *
174 : : * `GSS_S_COMPLETE`: Successful completion.
175 : : *
176 : : * `GSS_S_BAD_MECH`: Indicates that translation in accordance with an
177 : : * unsupported mechanism type was requested.
178 : : *
179 : : * `GSS_S_BAD_STATUS`: The status value was not recognized, or the
180 : : * status type was neither GSS_C_GSS_CODE nor GSS_C_MECH_CODE.
181 : : **/
182 : : OM_uint32
183 : 1 : gss_display_status (OM_uint32 * minor_status,
184 : : OM_uint32 status_value,
185 : : int status_type,
186 : : const gss_OID mech_type,
187 : : OM_uint32 * message_context, gss_buffer_t status_string)
188 : : {
189 : : size_t i;
190 : :
191 : 1 : bindtextdomain (PACKAGE PO_SUFFIX, LOCALEDIR);
192 : :
193 [ + - ]: 1 : if (minor_status)
194 : 1 : *minor_status = 0;
195 : :
196 [ + - ]: 1 : if (message_context)
197 : 1 : status_value &= ~*message_context;
198 : :
199 [ + - - ]: 1 : switch (status_type)
200 : : {
201 : : case GSS_C_GSS_CODE:
202 [ + - ]: 1 : if (message_context)
203 : : {
204 : 1 : *message_context |=
205 : : GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET;
206 [ + - ]: 1 : if ((status_value & ~*message_context) == 0)
207 : 1 : *message_context = 0;
208 : : }
209 : :
210 [ + - - ]: 1 : switch (GSS_ROUTINE_ERROR (status_value))
211 : : {
212 : : case 0:
213 : : break;
214 : :
215 : : case GSS_S_BAD_MECH:
216 : : case GSS_S_BAD_NAME:
217 : : case GSS_S_BAD_NAMETYPE:
218 : : case GSS_S_BAD_BINDINGS:
219 : : case GSS_S_BAD_STATUS:
220 : : case GSS_S_BAD_SIG:
221 : : case GSS_S_NO_CRED:
222 : : case GSS_S_NO_CONTEXT:
223 : : case GSS_S_DEFECTIVE_TOKEN:
224 : : case GSS_S_DEFECTIVE_CREDENTIAL:
225 : : case GSS_S_CREDENTIALS_EXPIRED:
226 : : case GSS_S_CONTEXT_EXPIRED:
227 : : case GSS_S_FAILURE:
228 : : case GSS_S_BAD_QOP:
229 : : case GSS_S_UNAUTHORIZED:
230 : : case GSS_S_UNAVAILABLE:
231 : : case GSS_S_DUPLICATE_ELEMENT:
232 : : case GSS_S_NAME_NOT_MN:
233 : 0 : status_string->value =
234 : 0 : strdup (_(gss_routine_errors
235 : : [(GSS_ROUTINE_ERROR (status_value) >>
236 : : GSS_C_ROUTINE_ERROR_OFFSET) - 1].text));
237 [ # # ]: 0 : if (!status_string->value)
238 : : {
239 [ # # ]: 0 : if (minor_status)
240 : 0 : *minor_status = ENOMEM;
241 : 0 : return GSS_S_FAILURE;
242 : : }
243 : 0 : status_string->length = strlen (status_string->value);
244 : 0 : return GSS_S_COMPLETE;
245 : : break;
246 : :
247 : : default:
248 : 0 : return GSS_S_BAD_STATUS;
249 : : break;
250 : : }
251 : :
252 [ + - ]: 1 : if (message_context)
253 : : {
254 : 1 : *message_context |=
255 : : GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET;
256 [ + - ]: 1 : if ((status_value & ~*message_context) == 0)
257 : 1 : *message_context = 0;
258 : : }
259 : :
260 [ + - - ]: 1 : switch (GSS_CALLING_ERROR (status_value))
261 : : {
262 : : case 0:
263 : : break;
264 : :
265 : : case GSS_S_CALL_INACCESSIBLE_READ:
266 : : case GSS_S_CALL_INACCESSIBLE_WRITE:
267 : : case GSS_S_CALL_BAD_STRUCTURE:
268 : 0 : status_string->value =
269 : 0 : strdup (_(gss_calling_errors
270 : : [(GSS_CALLING_ERROR (status_value) >>
271 : : GSS_C_CALLING_ERROR_OFFSET) - 1].text));
272 [ # # ]: 0 : if (!status_string->value)
273 : : {
274 [ # # ]: 0 : if (minor_status)
275 : 0 : *minor_status = ENOMEM;
276 : 0 : return GSS_S_FAILURE;
277 : : }
278 : 0 : status_string->length = strlen (status_string->value);
279 : 0 : return GSS_S_COMPLETE;
280 : : break;
281 : :
282 : : default:
283 : 0 : return GSS_S_BAD_STATUS;
284 : : break;
285 : : }
286 : :
287 [ + + ]: 6 : for (i = 0; i < sizeof (gss_supplementary_errors) /
288 : 5 : sizeof (gss_supplementary_errors[0]); i++)
289 [ - + ]: 5 : if (gss_supplementary_errors[i].err &
290 : : GSS_SUPPLEMENTARY_INFO (status_value))
291 : : {
292 : 0 : status_string->value =
293 : 0 : strdup (_(gss_supplementary_errors[i].text));
294 [ # # ]: 0 : if (!status_string->value)
295 : : {
296 [ # # ]: 0 : if (minor_status)
297 : 0 : *minor_status = ENOMEM;
298 : 0 : return GSS_S_FAILURE;
299 : : }
300 : 0 : status_string->length = strlen (status_string->value);
301 : 0 : *message_context |= gss_supplementary_errors[i].err;
302 [ # # ]: 0 : if ((status_value & ~*message_context) == 0)
303 : 0 : *message_context = 0;
304 : 0 : return GSS_S_COMPLETE;
305 : : }
306 : :
307 [ - + ]: 1 : if (GSS_SUPPLEMENTARY_INFO (status_value))
308 : 0 : return GSS_S_BAD_STATUS;
309 : :
310 [ + - ]: 1 : if (message_context)
311 : 1 : *message_context = 0;
312 : 1 : status_string->value = strdup (_("No error"));
313 [ - + ]: 1 : if (!status_string->value)
314 : : {
315 [ # # ]: 0 : if (minor_status)
316 : 0 : *minor_status = ENOMEM;
317 : 0 : return GSS_S_FAILURE;
318 : : }
319 : 1 : status_string->length = strlen (status_string->value);
320 : : break;
321 : :
322 : : case GSS_C_MECH_CODE:
323 : : {
324 : : _gss_mech_api_t mech;
325 : :
326 : 0 : mech = _gss_find_mech (mech_type);
327 : 0 : return mech->display_status (minor_status, status_value, status_type,
328 : : mech_type, message_context,
329 : : status_string);
330 : : }
331 : : break;
332 : :
333 : : default:
334 : 1 : return GSS_S_BAD_STATUS;
335 : : }
336 : :
337 : 1 : return GSS_S_COMPLETE;
338 : : }
|