1 /* #pragma ident "@(#)g_dsp_status.c 1.17 04/02/23 SMI" */ 2 3 /* 4 * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used 11 * in advertising or publicity pertaining to distribution of the software 12 * without specific, written prior permission. Sun Microsystems 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 * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL SUN MICROSYSTEMS 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 /* 26 * glue routine gss_display_status 27 * 28 */ 29 30 #include "mglueP.h" 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 35 /* local function */ 36 static OM_uint32 displayMajor(OM_uint32, OM_uint32 *, gss_buffer_t); 37 38 OM_uint32 KRB5_CALLCONV 39 gss_display_status (minor_status, 40 status_value, 41 status_type, 42 req_mech_type, 43 message_context, 44 status_string) 45 46 OM_uint32 * minor_status; 47 OM_uint32 status_value; 48 int status_type; 49 gss_OID req_mech_type; 50 OM_uint32 * message_context; 51 gss_buffer_t status_string; 52 53 { 54 gss_OID mech_type = (gss_OID) req_mech_type; 55 gss_mechanism mech; 56 gss_OID_desc m_oid = { 0, 0 }; 57 58 if (minor_status != NULL) 59 *minor_status = 0; 60 61 if (status_string != GSS_C_NO_BUFFER) { 62 status_string->length = 0; 63 status_string->value = NULL; 64 } 65 66 if (minor_status == NULL || 67 message_context == NULL || 68 status_string == GSS_C_NO_BUFFER) 69 70 return (GSS_S_CALL_INACCESSIBLE_WRITE); 71 72 /* we handle major status codes, and the mechs do the minor */ 73 if (status_type == GSS_C_GSS_CODE) 74 return (displayMajor(status_value, message_context, 75 status_string)); 76 77 /* 78 * must be the minor status - let mechs do the work 79 * select the appropriate underlying mechanism routine and 80 * call it. 81 */ 82 83 /* In this version, we only handle status codes that have been 84 mapped to a flat numbering space. Look up the value we got 85 passed. If it's not found, complain. */ 86 if (status_value == 0) { 87 status_string->value = gssalloc_strdup("Unknown error"); 88 if (status_string->value == NULL) { 89 *minor_status = ENOMEM; 90 map_errcode(minor_status); 91 return GSS_S_FAILURE; 92 } 93 status_string->length = strlen(status_string->value); 94 *message_context = 0; 95 *minor_status = 0; 96 return GSS_S_COMPLETE; 97 } 98 { 99 int err; 100 OM_uint32 m_status = 0, status; 101 102 err = gssint_mecherrmap_get(status_value, &m_oid, &m_status); 103 if (err) { 104 *minor_status = err; 105 map_errcode(minor_status); 106 return GSS_S_BAD_STATUS; 107 } 108 if (m_oid.length == 0) { 109 /* Magic flag for com_err values. */ 110 status = g_display_com_err_status(minor_status, m_status, status_string); 111 if (status != GSS_S_COMPLETE) 112 map_errcode(minor_status); 113 return status; 114 } 115 mech_type = &m_oid; 116 status_value = m_status; 117 } 118 119 mech = gssint_get_mechanism (mech_type); 120 121 if (mech && mech->gss_display_status) { 122 OM_uint32 r; 123 124 r = mech->gss_display_status(minor_status, 125 status_value, status_type, mech_type, 126 message_context, status_string); 127 /* How's this for weird? If we get an error returning the 128 mechanism-specific error code, we save away the 129 mechanism-specific error code describing the error. */ 130 if (r != GSS_S_COMPLETE) 131 map_error(minor_status, mech); 132 return r; 133 } 134 135 if (!mech) 136 return (GSS_S_BAD_MECH); 137 138 return (GSS_S_UNAVAILABLE); 139 } 140 141 /* 142 * function to map the major error codes 143 * it uses case statements so that the strings could be wrapped by gettext 144 * msgCtxt is interpreted as: 145 * 0 - first call 146 * 1 - routine error 147 * >= 2 - the supplementary error code bit shifted by 1 148 */ 149 static OM_uint32 150 displayMajor(status, msgCtxt, outStr) 151 OM_uint32 status; 152 OM_uint32 *msgCtxt; 153 gss_buffer_t outStr; 154 { 155 OM_uint32 oneVal, mask = 0x1, currErr; 156 char *errStr = NULL; 157 int i, haveErr = 0; 158 159 /* take care of the success value first */ 160 if (status == GSS_S_COMPLETE) 161 errStr = _("The routine completed successfully"); 162 else if (*msgCtxt == 0 && (oneVal = GSS_CALLING_ERROR(status))) { 163 switch (oneVal) { 164 case GSS_S_CALL_INACCESSIBLE_READ: 165 errStr = _("A required input parameter could not be " 166 "read"); 167 break; 168 169 case GSS_S_CALL_INACCESSIBLE_WRITE: 170 errStr = _("A required output parameter could not be " 171 "written"); 172 break; 173 174 case GSS_S_CALL_BAD_STRUCTURE: 175 errStr = _("A parameter was malformed"); 176 break; 177 178 default: 179 errStr = _("An invalid status code was supplied"); 180 break; 181 } 182 183 /* we now need to determine new value of msgCtxt */ 184 if (GSS_ROUTINE_ERROR(status)) 185 *msgCtxt = 1; 186 else if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0) 187 *msgCtxt = (OM_uint32)(oneVal << 1); 188 else 189 *msgCtxt = 0; 190 191 } else if ((*msgCtxt == 0 || *msgCtxt == 1) && 192 (oneVal = GSS_ROUTINE_ERROR(status))) { 193 switch (oneVal) { 194 case GSS_S_BAD_MECH: 195 errStr = _("An unsupported mechanism was requested"); 196 break; 197 198 case GSS_S_BAD_NAME: 199 errStr = _("An invalid name was supplied"); 200 break; 201 202 case GSS_S_BAD_NAMETYPE: 203 errStr = _("A supplied name was of an unsupported " 204 "type"); 205 break; 206 207 case GSS_S_BAD_BINDINGS: 208 errStr = _("Incorrect channel bindings were supplied"); 209 break; 210 211 case GSS_S_BAD_SIG: /* same as GSS_S_BAD_MIC: */ 212 errStr = _("A token had an invalid Message Integrity " 213 "Check (MIC)"); 214 break; 215 216 case GSS_S_NO_CRED: 217 errStr = _("No credentials were supplied, or the " 218 "credentials were unavailable or " 219 "inaccessible"); 220 break; 221 222 case GSS_S_NO_CONTEXT: 223 errStr = _("No context has been established"); 224 break; 225 226 case GSS_S_DEFECTIVE_TOKEN: 227 errStr = _("Invalid token was supplied"); 228 break; 229 230 case GSS_S_DEFECTIVE_CREDENTIAL: 231 errStr = _("Invalid credential was supplied"); 232 break; 233 234 case GSS_S_CREDENTIALS_EXPIRED: 235 errStr = _("The referenced credential has expired"); 236 break; 237 238 case GSS_S_CONTEXT_EXPIRED: 239 errStr = _("The referenced context has expired"); 240 break; 241 242 case GSS_S_FAILURE: 243 errStr = _("Unspecified GSS failure. Minor code " 244 "may provide more information"); 245 break; 246 247 case GSS_S_BAD_QOP: 248 errStr = _("The quality-of-protection (QOP) " 249 "requested could not be provided"); 250 break; 251 252 case GSS_S_UNAUTHORIZED: 253 errStr = _("The operation is forbidden by local " 254 "security policy"); 255 break; 256 257 case GSS_S_UNAVAILABLE: 258 errStr = _("The operation or option is not " 259 "available or unsupported"); 260 break; 261 262 case GSS_S_DUPLICATE_ELEMENT: 263 errStr = _("The requested credential element " 264 "already exists"); 265 break; 266 267 case GSS_S_NAME_NOT_MN: 268 errStr = _("The provided name was not mechanism " 269 "specific (MN)"); 270 break; 271 272 case GSS_S_BAD_STATUS: 273 default: 274 errStr = _("An invalid status code was supplied"); 275 } 276 277 /* we must determine if the caller should call us again */ 278 if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0) 279 *msgCtxt = (OM_uint32)(oneVal << 1); 280 else 281 *msgCtxt = 0; 282 283 } else if ((*msgCtxt == 0 || *msgCtxt >= 2) && 284 (oneVal = GSS_SUPPLEMENTARY_INFO(status))) { 285 /* 286 * if msgCtxt is not 0, then it should encode 287 * the supplementary error code we should be printing 288 */ 289 if (*msgCtxt >= 2) 290 oneVal = (OM_uint32) (*msgCtxt) >> 1; 291 else 292 oneVal = GSS_SUPPLEMENTARY_INFO(status); 293 294 /* we display the errors LSB first */ 295 for (i = 0; i < 16; i++) { 296 if (oneVal & mask) { 297 haveErr = 1; 298 break; 299 } 300 mask <<= 1; 301 } 302 303 /* isolate the bit or if not found set to illegal value */ 304 if (haveErr) 305 currErr = oneVal & mask; 306 else 307 currErr = 1 << 17; /* illegal value */ 308 309 switch (currErr) { 310 case GSS_S_CONTINUE_NEEDED: 311 errStr = _("The routine must be called again to " 312 "complete its function"); 313 break; 314 315 case GSS_S_DUPLICATE_TOKEN: 316 errStr = _("The token was a duplicate of an earlier " 317 "token"); 318 break; 319 320 case GSS_S_OLD_TOKEN: 321 errStr = _("The token's validity period has expired"); 322 break; 323 324 case GSS_S_UNSEQ_TOKEN: 325 errStr = _("A later token has already been processed"); 326 break; 327 328 case GSS_S_GAP_TOKEN: 329 errStr = _("An expected per-message token was not " 330 "received"); 331 break; 332 333 default: 334 errStr = _("An invalid status code was supplied"); 335 } 336 337 /* 338 * we must check if there is any other supplementary errors 339 * if found, then turn off current bit, and store next value 340 * in msgCtxt shifted by 1 bit 341 */ 342 if (!haveErr) 343 *msgCtxt = 0; 344 else if (GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) 345 *msgCtxt = (OM_uint32) 346 ((GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) << 1); 347 else 348 *msgCtxt = 0; 349 } 350 351 if (errStr == NULL) 352 errStr = "An invalid status code was supplied"; 353 354 /* now copy the status code and return to caller */ 355 outStr->length = strlen(errStr); 356 outStr->value = gssalloc_strdup(errStr); 357 if (outStr->value == NULL) { 358 outStr->length = 0; 359 return (GSS_S_FAILURE); 360 } 361 362 return (GSS_S_COMPLETE); 363 } /* displayMajor */ 364