Imported Upstream version 1.10.2
[platform/upstream/krb5.git] / src / lib / gssapi / generic / disp_major_status.c
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
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
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
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
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
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 }