summaryrefslogtreecommitdiffstats
path: root/src/lib/gssapi/mechglue/g_dsp_status.c
blob: 49b79e15d82aa9929b2b7730bda7ba8bd56f5a0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
/* #pragma ident	"@(#)g_dsp_status.c	1.17	04/02/23 SMI" */

/*
 * Copyright 1996 by Sun Microsystems, Inc.
 * 
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appears in all copies and
 * that both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of Sun Microsystems not be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission. Sun Microsystems makes no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 * 
 * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

/*
 *  glue routine gss_display_status
 *
 */

#include "mglueP.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* local function */
static OM_uint32 displayMajor(OM_uint32, OM_uint32 *, gss_buffer_t);

OM_uint32 KRB5_CALLCONV
gss_display_status (minor_status,
                    status_value,
                    status_type,
                    req_mech_type,
                    message_context,
                    status_string)

OM_uint32 *		minor_status;
OM_uint32		status_value;
int			status_type;
gss_OID			req_mech_type;
OM_uint32 *		message_context;
gss_buffer_t		status_string;

{
    gss_OID		mech_type = (gss_OID) req_mech_type;
    gss_mechanism	mech;
    gss_OID_desc	m_oid = { 0, 0 };

    if (minor_status != NULL)
	*minor_status = 0;

    if (status_string != GSS_C_NO_BUFFER) {
	status_string->length = 0;
	status_string->value = NULL;
    }

    if (minor_status == NULL ||
	message_context == NULL ||
	status_string == GSS_C_NO_BUFFER)

	return (GSS_S_CALL_INACCESSIBLE_WRITE);

    /* we handle major status codes, and the mechs do the minor */
    if (status_type == GSS_C_GSS_CODE)
	return (displayMajor(status_value, message_context,
			     status_string));

    /*
     * must be the minor status - let mechs do the work
     * select the appropriate underlying mechanism routine and
     * call it.
     */

    /* In this version, we only handle status codes that have been
       mapped to a flat numbering space.  Look up the value we got
       passed.  If it's not found, complain.  */
    if (status_value == 0) {
	status_string->value = strdup("Unknown error");
	if (status_string->value == NULL) {
	    *minor_status = ENOMEM;
	    map_errcode(minor_status);
	    return GSS_S_FAILURE;
	}
	status_string->length = strlen(status_string->value);
	*message_context = 0;
	*minor_status = 0;
	return GSS_S_COMPLETE;
    }
    {
	int err;
	OM_uint32 m_status = 0, status;

	err = gssint_mecherrmap_get(status_value, &m_oid, &m_status);
	if (err) {
	    *minor_status = err;
	    map_errcode(minor_status);
	    return GSS_S_BAD_STATUS;
	}
	if (m_oid.length == 0) {
	    /* Magic flag for com_err values.  */
	    status = g_display_com_err_status(minor_status, m_status, status_string);
	    if (status != GSS_S_COMPLETE)
		map_errcode(minor_status);
	    return status;
	}
	mech_type = &m_oid;
	status_value = m_status;
    }

    mech = gssint_get_mechanism (mech_type);

    if (mech && mech->gss_display_status) {
	OM_uint32 r;

	r = mech->gss_display_status(minor_status,
				     status_value, status_type, mech_type,
				     message_context, status_string);
	/* How's this for weird?  If we get an error returning the
	   mechanism-specific error code, we save away the
	   mechanism-specific error code describing the error.  */
	if (r != GSS_S_COMPLETE)
	    map_error(minor_status, mech);
	return r;
    }

    if (!mech)
	return (GSS_S_BAD_MECH);

    return (GSS_S_UNAVAILABLE);
}

/*
 * function to map the major error codes
 * it uses case statements so that the strings could be wrapped by gettext
 * msgCtxt is interpreted as:
 *	0 - first call
 *	1 - routine error
 *	>= 2 - the supplementary error code bit shifted by 1
 */
static OM_uint32
displayMajor(status, msgCtxt, outStr)
OM_uint32 status;
OM_uint32 *msgCtxt;
gss_buffer_t outStr;
{
	OM_uint32 oneVal, mask = 0x1, currErr;
	char *errStr = NULL;
	int i, haveErr = 0;

	/* take care of the success value first */
	if (status == GSS_S_COMPLETE)
		errStr = "The routine completed successfully";
	else if (*msgCtxt == 0 && (oneVal = GSS_CALLING_ERROR(status))) {
		switch (oneVal) {
		case GSS_S_CALL_INACCESSIBLE_READ:
			errStr = "A required input parameter"
				" could not be read";
			break;

		case GSS_S_CALL_INACCESSIBLE_WRITE:
			errStr = "A required output parameter"
				" could not be written";
			break;

		case GSS_S_CALL_BAD_STRUCTURE:
			errStr = "A parameter was malformed";
			break;

		default:
			errStr = "An invalid status code was supplied";
			break;
		}

		/* we now need to determine new value of msgCtxt */
		if (GSS_ROUTINE_ERROR(status))
			*msgCtxt = 1;
		else if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
			*msgCtxt = (OM_uint32)(oneVal << 1);
		else
			*msgCtxt = 0;

	} else if ((*msgCtxt == 0 || *msgCtxt == 1) &&
		(oneVal = GSS_ROUTINE_ERROR(status))) {
		switch (oneVal) {
		case GSS_S_BAD_MECH:
			errStr = "An unsupported mechanism"
				" was requested";
			break;

		case GSS_S_BAD_NAME:
			errStr = "An invalid name was supplied";
			break;

		case GSS_S_BAD_NAMETYPE:
			errStr = "A supplied name was of an"
				" unsupported type";
			break;

		case GSS_S_BAD_BINDINGS:
			errStr = "Incorrect channel bindings"
				" were supplied";
			break;

		case GSS_S_BAD_SIG: /* same as GSS_S_BAD_MIC: */
			errStr = "A token had an invalid Message"
				" Integrity Check (MIC)";
			break;

		case GSS_S_NO_CRED:
			errStr = "No credentials were supplied, or the"
				" credentials were unavailable or"
				" inaccessible";
			break;

		case GSS_S_NO_CONTEXT:
			errStr = "No context has been established";
			break;

		case GSS_S_DEFECTIVE_TOKEN:
			errStr = "Invalid token was supplied";
			break;

		case GSS_S_DEFECTIVE_CREDENTIAL:
			errStr = "Invalid credential was supplied";
			break;

		case GSS_S_CREDENTIALS_EXPIRED:
			errStr = "The referenced credential has"
				" expired";
			break;

		case GSS_S_CONTEXT_EXPIRED:
			errStr = "The referenced context has expired";
			break;

		case GSS_S_FAILURE:
			errStr = "Unspecified GSS failure.  Minor code"
				" may provide more information";
			break;

		case GSS_S_BAD_QOP:
			errStr = "The quality-of-protection (QOP) "
				"requested could not be provided";
			break;

		case GSS_S_UNAUTHORIZED:
			errStr = "The operation is forbidden by local"
				" security policy";
			break;

		case GSS_S_UNAVAILABLE:
			errStr = "The operation or option is not"
				" available or unsupported";
			break;

		case GSS_S_DUPLICATE_ELEMENT:
			errStr = "The requested credential element"
				" already exists";
			break;

		case GSS_S_NAME_NOT_MN:
			errStr = "The provided name was not mechanism"
				" specific (MN)";
			break;

		case GSS_S_BAD_STATUS:
		default:
			errStr = "An invalid status code was supplied";
		}

		/* we must determine if the caller should call us again */
		if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
			*msgCtxt = (OM_uint32)(oneVal << 1);
		else
			*msgCtxt = 0;

	} else if ((*msgCtxt == 0 || *msgCtxt >= 2) &&
		(oneVal = GSS_SUPPLEMENTARY_INFO(status))) {
		/*
		 * if msgCtxt is not 0, then it should encode
		 * the supplementary error code we should be printing
		 */
		if (*msgCtxt >= 2)
			oneVal = (OM_uint32) (*msgCtxt) >> 1;
		else
			oneVal = GSS_SUPPLEMENTARY_INFO(status);

		/* we display the errors LSB first */
		for (i = 0; i < 16; i++) {
			if (oneVal & mask) {
				haveErr = 1;
				break;
			}
			mask <<= 1;
		}

		/* isolate the bit or if not found set to illegal value */
		if (haveErr)
			currErr = oneVal & mask;
		else
			currErr = 1 << 17; /* illegal value */

		switch (currErr) {
		case GSS_S_CONTINUE_NEEDED:
			errStr = "The routine must be called again to"
				" complete its function";
			break;

		case GSS_S_DUPLICATE_TOKEN:
			errStr = "The token was a duplicate of an"
				" earlier token";
			break;

		case GSS_S_OLD_TOKEN:
			errStr = "The token's validity period"
				" has expired";
			break;

		case GSS_S_UNSEQ_TOKEN:
			errStr = "A later token has already been"
				" processed";
			break;

		case GSS_S_GAP_TOKEN:
			errStr = "An expected per-message token was"
				" not received";
			break;

		default:
			errStr = "An invalid status code was supplied";
		}

		/*
		 * we must check if there is any other supplementary errors
		 * if found, then turn off current bit, and store next value
		 * in msgCtxt shifted by 1 bit
		 */
		if (!haveErr)
			*msgCtxt = 0;
		else if (GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask)
			*msgCtxt = (OM_uint32)
				((GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) << 1);
		else
			*msgCtxt = 0;
	}

	if (errStr == NULL)
		errStr = "An invalid status code was supplied";

	/* now copy the status code and return to caller */
	outStr->length = strlen(errStr);
	outStr->value = strdup(errStr);
	if (outStr->value == NULL) {
		outStr->length = 0;
		return (GSS_S_FAILURE);
	}

	return (GSS_S_COMPLETE);
} /* displayMajor */