1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /*
26 * glue routine gss_display_status
27 *
28 */
29
30 #include <mechglueP.h>
31 #include "gssapiP_generic.h"
32 #include <stdio.h>
33 #ifdef HAVE_STDLIB_H
34 #include <stdlib.h>
35 #endif
36 #include <string.h>
37 #include <libintl.h>
38 #include <errno.h>
39 #include <syslog.h>
40 #ifndef TEXT_DOMAIN
41 #error TEXT_DOMAIN not defined
42 #endif
43
44 /* local function */
45 static OM_uint32 displayMajor(OM_uint32, OM_uint32 *, gss_buffer_t);
46
47
48 OM_uint32
gss_display_status(minor_status,status_value,status_type,req_mech_type,message_context,status_string)49 gss_display_status(minor_status,
50 status_value,
51 status_type,
52 req_mech_type,
53 message_context,
54 status_string)
55
56 OM_uint32 *minor_status;
57 OM_uint32 status_value;
58 int status_type;
59 const gss_OID req_mech_type;
60 OM_uint32 *message_context;
61 gss_buffer_t status_string;
62 {
63 gss_OID mech_type = (gss_OID) req_mech_type;
64 gss_mechanism mech;
65 gss_OID_desc m_oid = { 0, 0 };
66
67 if (minor_status != NULL)
68 *minor_status = 0;
69
70 if (status_string != GSS_C_NO_BUFFER) {
71 status_string->length = 0;
72 status_string->value = NULL;
73 }
74
75 if (minor_status == NULL ||
76 message_context == NULL ||
77 status_string == GSS_C_NO_BUFFER)
78 return (GSS_S_CALL_INACCESSIBLE_WRITE);
79
80 /* we handle major status codes, and the mechs do the minor */
81 if (status_type == GSS_C_GSS_CODE)
82 return (displayMajor(status_value, message_context,
83 status_string));
84
85 /*
86 * must be the minor status - let mechs do the work
87 * select the appropriate underlying mechanism routine and
88 * call it.
89 */
90
91 /* In this version, we only handle status codes that have been
92 mapped to a flat numbering space. Look up the value we got
93 passed. If it's not found, complain. */
94 if (status_value == 0) {
95 status_string->value = strdup("Unknown error");
96 if (status_string->value == NULL) {
97 *minor_status = ENOMEM;
98 map_errcode(minor_status);
99 return GSS_S_FAILURE;
100 }
101 status_string->length = strlen(status_string->value);
102 *message_context = 0;
103 *minor_status = 0;
104 return GSS_S_COMPLETE;
105 }
106 {
107 int err;
108 OM_uint32 m_status = 0, status;
109
110 err = gssint_mecherrmap_get(status_value, &m_oid, &m_status);
111 if (err) {
112 *minor_status = err;
113 map_errcode(minor_status);
114 return GSS_S_BAD_STATUS;
115 }
116
117 if (m_oid.length == 0) {
118 /* Magic flag for com_err values. */
119 status = gssint_g_display_com_err_status(minor_status,
120 m_status,
121 status_string);
122 if (status != GSS_S_COMPLETE)
123 map_errcode(minor_status);
124 return status;
125 }
126 mech_type = &m_oid;
127 status_value = m_status;
128 }
129
130 mech = __gss_get_mechanism(mech_type);
131
132 if (mech && mech->gss_display_status) {
133 OM_uint32 r;
134
135 if (mech_type == GSS_C_NULL_OID)
136 mech_type = &mech->mech_type;
137
138 r = mech->gss_display_status(mech->context, minor_status,
139 status_value, status_type, mech_type,
140 message_context, status_string);
141 /* How's this for weird? If we get an error returning the
142 mechanism-specific error code, we save away the
143 mechanism-specific error code describing the error. */
144 if (r != GSS_S_COMPLETE)
145 map_error(minor_status, mech);
146 return r;
147 }
148
149 if (!mech)
150 return (GSS_S_BAD_MECH);
151
152 return (GSS_S_UNAVAILABLE);
153 } /* gss_display_status */
154
155
156 /*
157 * function to map the major error codes
158 * it uses case statements so that the strings could be wrapped by gettext
159 * msgCtxt is interpreted as:
160 * 0 - first call
161 * 1 - routine error
162 * >= 2 - the supplementary error code bit shifted by 1
163 */
164 static OM_uint32
displayMajor(status,msgCtxt,outStr)165 displayMajor(status, msgCtxt, outStr)
166 OM_uint32 status;
167 OM_uint32 *msgCtxt;
168 gss_buffer_t outStr;
169 {
170 OM_uint32 oneVal, mask = 0x1, currErr;
171 char *errStr = NULL;
172 int i, haveErr = 0;
173
174 /* take care of the success value first */
175 if (status == GSS_S_COMPLETE)
176 errStr = dgettext(TEXT_DOMAIN,
177 "The routine completed successfully");
178 else if (*msgCtxt == 0 && (oneVal = GSS_CALLING_ERROR(status))) {
179 switch (oneVal) {
180 case GSS_S_CALL_INACCESSIBLE_READ:
181 errStr = dgettext(TEXT_DOMAIN,
182 "A required input parameter"
183 " could not be read");
184 break;
185
186 case GSS_S_CALL_INACCESSIBLE_WRITE:
187 errStr = dgettext(TEXT_DOMAIN,
188 "A required output parameter"
189 " could not be written");
190 break;
191
192 case GSS_S_CALL_BAD_STRUCTURE:
193 errStr = dgettext(TEXT_DOMAIN,
194 "A parameter was malformed");
195 break;
196
197 default:
198 errStr = dgettext(TEXT_DOMAIN,
199 "An invalid status code was supplied");
200 break;
201 }
202
203 /* we now need to determine new value of msgCtxt */
204 if (GSS_ROUTINE_ERROR(status))
205 *msgCtxt = 1;
206 else if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
207 *msgCtxt = (OM_uint32)(oneVal << 1);
208 else
209 *msgCtxt = 0;
210
211 } else if ((*msgCtxt == 0 || *msgCtxt == 1) &&
212 (oneVal = GSS_ROUTINE_ERROR(status))) {
213 switch (oneVal) {
214 case GSS_S_BAD_MECH:
215 errStr = dgettext(TEXT_DOMAIN,
216 "An unsupported mechanism"
217 " was requested");
218 break;
219
220 case GSS_S_BAD_NAME:
221 errStr = dgettext(TEXT_DOMAIN,
222 "An invalid name was supplied");
223 break;
224
225 case GSS_S_BAD_NAMETYPE:
226 errStr = dgettext(TEXT_DOMAIN,
227 "A supplied name was of an"
228 " unsupported type");
229 break;
230
231 case GSS_S_BAD_BINDINGS:
232 errStr = dgettext(TEXT_DOMAIN,
233 "Incorrect channel bindings"
234 " were supplied");
235 break;
236
237 case GSS_S_BAD_SIG: /* same as GSS_S_BAD_MIC: */
238 errStr = dgettext(TEXT_DOMAIN,
239 "A token had an invalid Message"
240 " Integrity Check (MIC)");
241 break;
242
243 case GSS_S_NO_CRED:
244 errStr = dgettext(TEXT_DOMAIN,
245 "No credentials were supplied, or the"
246 " credentials were unavailable or"
247 " inaccessible");
248 break;
249
250 case GSS_S_NO_CONTEXT:
251 errStr = dgettext(TEXT_DOMAIN,
252 "No context has been established");
253 break;
254
255 case GSS_S_DEFECTIVE_TOKEN:
256 errStr = dgettext(TEXT_DOMAIN,
257 "Invalid token was supplied");
258 break;
259
260 case GSS_S_DEFECTIVE_CREDENTIAL:
261 errStr = dgettext(TEXT_DOMAIN,
262 "Invalid credential was supplied");
263 break;
264
265 case GSS_S_CREDENTIALS_EXPIRED:
266 errStr = dgettext(TEXT_DOMAIN,
267 "The referenced credential has"
268 " expired");
269 break;
270
271 case GSS_S_CONTEXT_EXPIRED:
272 errStr = dgettext(TEXT_DOMAIN,
273 "The referenced context has expired");
274 break;
275
276 case GSS_S_FAILURE:
277 errStr = dgettext(TEXT_DOMAIN,
278 "Unspecified GSS failure. Minor code"
279 " may provide more information");
280 break;
281
282 case GSS_S_BAD_QOP:
283 errStr = dgettext(TEXT_DOMAIN,
284 "The quality-of-protection (QOP) "
285 "requested could not be provided");
286 break;
287
288 case GSS_S_UNAUTHORIZED:
289 errStr = dgettext(TEXT_DOMAIN,
290 "The operation is forbidden by local"
291 " security policy");
292 break;
293
294 case GSS_S_UNAVAILABLE:
295 errStr = dgettext(TEXT_DOMAIN,
296 "The operation or option is not"
297 " available or unsupported");
298 break;
299
300 case GSS_S_DUPLICATE_ELEMENT:
301 errStr = dgettext(TEXT_DOMAIN,
302 "The requested credential element"
303 " already exists");
304 break;
305
306 case GSS_S_NAME_NOT_MN:
307 errStr = dgettext(TEXT_DOMAIN,
308 "The provided name was not mechanism"
309 " specific (MN)");
310 break;
311
312 case GSS_S_BAD_STATUS:
313 default:
314 errStr = dgettext(TEXT_DOMAIN,
315 "An invalid status code was supplied");
316 }
317
318 /* we must determine if the caller should call us again */
319 if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
320 *msgCtxt = (OM_uint32)(oneVal << 1);
321 else
322 *msgCtxt = 0;
323
324 } else if ((*msgCtxt == 0 || *msgCtxt >= 2) &&
325 (oneVal = GSS_SUPPLEMENTARY_INFO(status))) {
326 /*
327 * if msgCtxt is not 0, then it should encode
328 * the supplementary error code we should be printing
329 */
330 if (*msgCtxt >= 2)
331 oneVal = (OM_uint32) (*msgCtxt) >> 1;
332 else
333 oneVal = GSS_SUPPLEMENTARY_INFO(status);
334
335 /* we display the errors LSB first */
336 for (i = 0; i < 16; i++) {
337 if (oneVal & mask) {
338 haveErr = 1;
339 break;
340 }
341 mask <<= 1;
342 }
343
344 /* isolate the bit or if not found set to illegal value */
345 if (haveErr)
346 currErr = oneVal & mask;
347 else
348 currErr = 1 << 17; /* illegal value */
349
350 switch (currErr) {
351 case GSS_S_CONTINUE_NEEDED:
352 errStr = dgettext(TEXT_DOMAIN,
353 "The routine must be called again to"
354 " complete its function");
355 break;
356
357 case GSS_S_DUPLICATE_TOKEN:
358 errStr = dgettext(TEXT_DOMAIN,
359 "The token was a duplicate of an"
360 " earlier token");
361 break;
362
363 case GSS_S_OLD_TOKEN:
364 errStr = dgettext(TEXT_DOMAIN,
365 "The token's validity period"
366 " has expired");
367 break;
368
369 case GSS_S_UNSEQ_TOKEN:
370 errStr = dgettext(TEXT_DOMAIN,
371 "A later token has already been"
372 " processed");
373 break;
374
375 case GSS_S_GAP_TOKEN:
376 errStr = dgettext(TEXT_DOMAIN,
377 "An expected per-message token was"
378 " not received");
379 break;
380
381 default:
382 errStr = dgettext(TEXT_DOMAIN,
383 "An invalid status code was supplied");
384 }
385
386 /*
387 * we must check if there is any other supplementary errors
388 * if found, then turn off current bit, and store next value
389 * in msgCtxt shifted by 1 bit
390 */
391 if (!haveErr)
392 *msgCtxt = 0;
393 else if (GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask)
394 *msgCtxt = (OM_uint32)
395 ((GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) << 1);
396 else
397 *msgCtxt = 0;
398 }
399
400 if (errStr == NULL)
401 errStr = dgettext(TEXT_DOMAIN,
402 "An invalid status code was supplied");
403
404 /* now copy the status code and return to caller */
405 outStr->length = strlen(errStr);
406 outStr->value = strdup(errStr);
407 if (outStr->value == NULL) {
408 outStr->length = 0;
409 return (GSS_S_FAILURE);
410 }
411
412 return (GSS_S_COMPLETE);
413 } /* displayMajor */
414