1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 1993 by OpenVision Technologies, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without fee,
7 * provided that the above copyright notice appears in all copies and
8 * that both that copyright notice and this permission notice appear in
9 * supporting documentation, and that the name of OpenVision not be used
10 * in advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. OpenVision makes no
12 * representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
20 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24 #include "gssapiP_generic.h"
25 #include <string.h>
26 #include <stdio.h>
27
28 /*
29 * $Id$
30 */
31
32 /* This code has knowledge of the min and max errors of each type
33 within the gssapi major status */
34
35 #define GSS_ERROR_STR(value, array, select, min, max, num) \
36 (((select(value) < (min)) || (select(value) > (max))) ? NULL : \
37 _((array)[num(value)]))
38
39 /**/
40
41 static const char * const calling_error_string[] = {
42 NULL,
43 N_("A required input parameter could not be read"),
44 N_("A required input parameter could not be written"),
45 N_("A parameter was malformed"),
46 };
47
48 static const char * const calling_error = N_("calling error");
49
50 #define GSS_CALLING_ERROR_STR(x) \
51 GSS_ERROR_STR((x), calling_error_string, GSS_CALLING_ERROR, \
52 GSS_S_CALL_INACCESSIBLE_READ, GSS_S_CALL_BAD_STRUCTURE, \
53 GSS_CALLING_ERROR_FIELD)
54
55 /**/
56
57 static const char * const routine_error_string[] = {
58 NULL,
59 N_("An unsupported mechanism was requested"),
60 N_("An invalid name was supplied"),
61 N_("A supplied name was of an unsupported type"),
62 N_("Incorrect channel bindings were supplied"),
63 N_("An invalid status code was supplied"),
64 N_("A token had an invalid signature"),
65 N_("No credentials were supplied"),
66 N_("No context has been established"),
67 N_("A token was invalid"),
68 N_("A credential was invalid"),
69 N_("The referenced credentials have expired"),
70 N_("The context has expired"),
71 N_("Miscellaneous failure"),
72 N_("The quality-of-protection requested could not be provided"),
73 N_("The operation is forbidden by the local security policy"),
74 N_("The operation or option is not available"),
75 };
76
77 static const char * const routine_error = N_("routine error");
78
79 #define GSS_ROUTINE_ERROR_STR(x) \
80 GSS_ERROR_STR((x), routine_error_string, GSS_ROUTINE_ERROR, \
81 GSS_S_BAD_MECH, GSS_S_FAILURE, \
82 GSS_ROUTINE_ERROR_FIELD)
83
84 /**/
85
86 /* this becomes overly gross after about 4 strings */
87
88 static const char * const sinfo_string[] = {
89 N_("The routine must be called again to complete its function"),
90 N_("The token was a duplicate of an earlier token"),
91 N_("The token's validity period has expired"),
92 N_("A later token has already been processed"),
93 };
94
95 static const char * const sinfo_code = N_("supplementary info code");
96
97 #define LSBGET(x) ((((x)^((x)-1))+1)>>1)
98 #define LSBMASK(n) ((1<<(n))^((1<<(n))-1))
99
100 #define GSS_SINFO_STR(x) \
101 ((((1<<(x)) < GSS_S_CONTINUE_NEEDED) || ((1<<(x)) > GSS_S_UNSEQ_TOKEN)) ? \
102 /**/NULL:sinfo_string[(x)])
103
104 /**/
105
106 static const char * const no_error = N_("No error");
107 static const char * const unknown_error = N_("Unknown %s (field = %d)");
108
109 /**/
110
111 static int
display_unknown(const char * kind,OM_uint32 value,gss_buffer_t buffer)112 display_unknown(const char *kind, OM_uint32 value, gss_buffer_t buffer)
113 {
114 char *str;
115
116 if (asprintf(&str, _(unknown_error), kind, value) < 0)
117 return(0);
118
119 buffer->length = strlen(str);
120 buffer->value = str;
121
122 return(1);
123 }
124
125 /* code should be set to the calling error field */
126
127 static OM_uint32
display_calling(OM_uint32 * minor_status,OM_uint32 code,gss_buffer_t status_string)128 display_calling(OM_uint32 *minor_status, OM_uint32 code,
129 gss_buffer_t status_string)
130 {
131 const char *str;
132
133 if ((str = GSS_CALLING_ERROR_STR(code))) {
134 if (! g_make_string_buffer(str, status_string)) {
135 *minor_status = ENOMEM;
136 return(GSS_S_FAILURE);
137 }
138 } else {
139 if (! display_unknown(_(calling_error), GSS_CALLING_ERROR_FIELD(code),
140 status_string)) {
141 *minor_status = ENOMEM;
142 return(GSS_S_FAILURE);
143 }
144 }
145 *minor_status = 0;
146 return(GSS_S_COMPLETE);
147 }
148
149 /* code should be set to the routine error field */
150
151 static OM_uint32
display_routine(OM_uint32 * minor_status,OM_uint32 code,gss_buffer_t status_string)152 display_routine(OM_uint32 *minor_status, OM_uint32 code,
153 gss_buffer_t status_string)
154 {
155 const char *str;
156
157 if ((str = GSS_ROUTINE_ERROR_STR(code))) {
158 if (! g_make_string_buffer(str, status_string)) {
159 *minor_status = ENOMEM;
160 return(GSS_S_FAILURE);
161 }
162 } else {
163 if (! display_unknown(_(routine_error), GSS_ROUTINE_ERROR_FIELD(code),
164 status_string)) {
165 *minor_status = ENOMEM;
166 return(GSS_S_FAILURE);
167 }
168 }
169 *minor_status = 0;
170 return(GSS_S_COMPLETE);
171 }
172
173 /* code should be set to the bit offset (log_2) of a supplementary info bit */
174
175 static OM_uint32
display_bit(OM_uint32 * minor_status,OM_uint32 code,gss_buffer_t status_string)176 display_bit(OM_uint32 *minor_status, OM_uint32 code,
177 gss_buffer_t status_string)
178 {
179 const char *str;
180
181 if ((str = GSS_SINFO_STR(code))) {
182 if (! g_make_string_buffer(str, status_string)) {
183 *minor_status = ENOMEM;
184 return(GSS_S_FAILURE);
185 }
186 } else {
187 if (! display_unknown(_(sinfo_code), 1<<code, status_string)) {
188 *minor_status = ENOMEM;
189 return(GSS_S_FAILURE);
190 }
191 }
192 *minor_status = 0;
193 return(GSS_S_COMPLETE);
194 }
195
196 /**/
197
198 /* return error messages, for routine errors, call error, and status,
199 in that order.
200 message_context == 0 : print the routine error
201 message_context == 1 : print the calling error
202 message_context > 2 : print supplementary info bit (message_context-2)
203 */
204
205 OM_uint32
g_display_major_status(OM_uint32 * minor_status,OM_uint32 status_value,OM_uint32 * message_context,gss_buffer_t status_string)206 g_display_major_status(OM_uint32 *minor_status, OM_uint32 status_value,
207 OM_uint32 *message_context, gss_buffer_t status_string)
208 {
209 OM_uint32 ret, tmp;
210 int bit;
211
212 /*** deal with no error at all specially */
213
214 if (status_value == 0) {
215 if (! g_make_string_buffer(no_error, status_string)) {
216 *minor_status = ENOMEM;
217 return(GSS_S_FAILURE);
218 }
219 *message_context = 0;
220 *minor_status = 0;
221 return(GSS_S_COMPLETE);
222 }
223
224 /*** do routine error */
225
226 if (*message_context == 0) {
227 if ((tmp = GSS_ROUTINE_ERROR(status_value))) {
228 status_value -= tmp;
229 if ((ret = display_routine(minor_status, tmp, status_string)))
230 return(ret);
231 *minor_status = 0;
232 if (status_value) {
233 (*message_context)++;
234 return(GSS_S_COMPLETE);
235 } else {
236 *message_context = 0;
237 return(GSS_S_COMPLETE);
238 }
239 } else {
240 (*message_context)++;
241 }
242 } else {
243 status_value -= GSS_ROUTINE_ERROR(status_value);
244 }
245
246 /*** do calling error */
247
248 if (*message_context == 1) {
249 if ((tmp = GSS_CALLING_ERROR(status_value))) {
250 status_value -= tmp;
251 if ((ret = display_calling(minor_status, tmp, status_string)))
252 return(ret);
253 *minor_status = 0;
254 if (status_value) {
255 (*message_context)++;
256 return(GSS_S_COMPLETE);
257 } else {
258 *message_context = 0;
259 return(GSS_S_COMPLETE);
260 }
261 } else {
262 (*message_context)++;
263 }
264 } else {
265 status_value -= GSS_CALLING_ERROR(status_value);
266 }
267
268 /*** do sinfo bits (*message_context == 2 + number of bits done) */
269
270 tmp = GSS_SUPPLEMENTARY_INFO_FIELD(status_value);
271 /* mask off the bits which have been done */
272 if (*message_context > 2) {
273 tmp &= ~LSBMASK(*message_context-3);
274 status_value &= ~LSBMASK(*message_context-3);
275 }
276
277 if (!tmp) {
278 /* bogon input - there should be something left */
279 *minor_status = (OM_uint32) G_BAD_MSG_CTX;
280 return(GSS_S_FAILURE);
281 }
282
283 /* compute the bit offset */
284 /*SUPPRESS 570*/
285 for (bit=0; (((OM_uint32) 1)<<bit) != LSBGET(tmp); bit++) ;
286
287 /* print it */
288 if ((ret = display_bit(minor_status, bit, status_string)))
289 return(ret);
290
291 /* compute the new status_value/message_context */
292 status_value -= ((OM_uint32) 1)<<bit;
293
294 if (status_value) {
295 *message_context = bit+3;
296 return(GSS_S_COMPLETE);
297 } else {
298 *message_context = 0;
299 return(GSS_S_COMPLETE);
300 }
301 }
302