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