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