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