1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * glue routine gss_display_status 27 * 28 */ 29 30 #include <mechglueP.h> 31 #include "gssapiP_generic.h" 32 #include <stdio.h> 33 #ifdef HAVE_STDLIB_H 34 #include <stdlib.h> 35 #endif 36 #include <string.h> 37 #include <libintl.h> 38 #include <errno.h> 39 #include <syslog.h> 40 #ifndef TEXT_DOMAIN 41 #error TEXT_DOMAIN not defined 42 #endif 43 44 /* local function */ 45 static OM_uint32 displayMajor(OM_uint32, OM_uint32 *, gss_buffer_t); 46 47 48 OM_uint32 49 gss_display_status(minor_status, 50 status_value, 51 status_type, 52 req_mech_type, 53 message_context, 54 status_string) 55 56 OM_uint32 *minor_status; 57 OM_uint32 status_value; 58 int status_type; 59 const gss_OID req_mech_type; 60 OM_uint32 *message_context; 61 gss_buffer_t status_string; 62 { 63 gss_OID mech_type = (gss_OID) req_mech_type; 64 gss_mechanism mech; 65 gss_OID_desc m_oid = { 0, 0 }; 66 67 if (minor_status != NULL) 68 *minor_status = 0; 69 70 if (status_string != GSS_C_NO_BUFFER) { 71 status_string->length = 0; 72 status_string->value = NULL; 73 } 74 75 if (minor_status == NULL || 76 message_context == NULL || 77 status_string == GSS_C_NO_BUFFER) 78 return (GSS_S_CALL_INACCESSIBLE_WRITE); 79 80 /* we handle major status codes, and the mechs do the minor */ 81 if (status_type == GSS_C_GSS_CODE) 82 return (displayMajor(status_value, message_context, 83 status_string)); 84 85 /* 86 * must be the minor status - let mechs do the work 87 * select the appropriate underlying mechanism routine and 88 * call it. 89 */ 90 91 /* In this version, we only handle status codes that have been 92 mapped to a flat numbering space. Look up the value we got 93 passed. If it's not found, complain. */ 94 if (status_value == 0) { 95 status_string->value = strdup("Unknown error"); 96 if (status_string->value == NULL) { 97 *minor_status = ENOMEM; 98 map_errcode(minor_status); 99 return GSS_S_FAILURE; 100 } 101 status_string->length = strlen(status_string->value); 102 *message_context = 0; 103 *minor_status = 0; 104 return GSS_S_COMPLETE; 105 } 106 { 107 int err; 108 OM_uint32 m_status = 0, status; 109 110 err = gssint_mecherrmap_get(status_value, &m_oid, &m_status); 111 if (err) { 112 *minor_status = err; 113 map_errcode(minor_status); 114 return GSS_S_BAD_STATUS; 115 } 116 117 if (m_oid.length == 0) { 118 /* Magic flag for com_err values. */ 119 status = gssint_g_display_com_err_status(minor_status, 120 m_status, 121 status_string); 122 if (status != GSS_S_COMPLETE) 123 map_errcode(minor_status); 124 return status; 125 } 126 mech_type = &m_oid; 127 status_value = m_status; 128 } 129 130 mech = __gss_get_mechanism(mech_type); 131 132 if (mech && mech->gss_display_status) { 133 OM_uint32 r; 134 135 if (mech_type == GSS_C_NULL_OID) 136 mech_type = &mech->mech_type; 137 138 r = mech->gss_display_status(mech->context, minor_status, 139 status_value, status_type, mech_type, 140 message_context, status_string); 141 /* How's this for weird? If we get an error returning the 142 mechanism-specific error code, we save away the 143 mechanism-specific error code describing the error. */ 144 if (r != GSS_S_COMPLETE) 145 map_error(minor_status, mech); 146 return r; 147 } 148 149 if (!mech) 150 return (GSS_S_BAD_MECH); 151 152 return (GSS_S_UNAVAILABLE); 153 } /* gss_display_status */ 154 155 156 /* 157 * function to map the major error codes 158 * it uses case statements so that the strings could be wrapped by gettext 159 * msgCtxt is interpreted as: 160 * 0 - first call 161 * 1 - routine error 162 * >= 2 - the supplementary error code bit shifted by 1 163 */ 164 static OM_uint32 165 displayMajor(status, msgCtxt, outStr) 166 OM_uint32 status; 167 OM_uint32 *msgCtxt; 168 gss_buffer_t outStr; 169 { 170 OM_uint32 oneVal, mask = 0x1, currErr; 171 char *errStr = NULL; 172 int i, haveErr = 0; 173 174 /* take care of the success value first */ 175 if (status == GSS_S_COMPLETE) 176 errStr = dgettext(TEXT_DOMAIN, 177 "The routine completed successfully"); 178 else if (*msgCtxt == 0 && (oneVal = GSS_CALLING_ERROR(status))) { 179 switch (oneVal) { 180 case GSS_S_CALL_INACCESSIBLE_READ: 181 errStr = dgettext(TEXT_DOMAIN, 182 "A required input parameter" 183 " could not be read"); 184 break; 185 186 case GSS_S_CALL_INACCESSIBLE_WRITE: 187 errStr = dgettext(TEXT_DOMAIN, 188 "A required output parameter" 189 " could not be written"); 190 break; 191 192 case GSS_S_CALL_BAD_STRUCTURE: 193 errStr = dgettext(TEXT_DOMAIN, 194 "A parameter was malformed"); 195 break; 196 197 default: 198 errStr = dgettext(TEXT_DOMAIN, 199 "An invalid status code was supplied"); 200 break; 201 } 202 203 /* we now need to determine new value of msgCtxt */ 204 if (GSS_ROUTINE_ERROR(status)) 205 *msgCtxt = 1; 206 else if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0) 207 *msgCtxt = (OM_uint32)(oneVal << 1); 208 else 209 *msgCtxt = 0; 210 211 } else if ((*msgCtxt == 0 || *msgCtxt == 1) && 212 (oneVal = GSS_ROUTINE_ERROR(status))) { 213 switch (oneVal) { 214 case GSS_S_BAD_MECH: 215 errStr = dgettext(TEXT_DOMAIN, 216 "An unsupported mechanism" 217 " was requested"); 218 break; 219 220 case GSS_S_BAD_NAME: 221 errStr = dgettext(TEXT_DOMAIN, 222 "An invalid name was supplied"); 223 break; 224 225 case GSS_S_BAD_NAMETYPE: 226 errStr = dgettext(TEXT_DOMAIN, 227 "A supplied name was of an" 228 " unsupported type"); 229 break; 230 231 case GSS_S_BAD_BINDINGS: 232 errStr = dgettext(TEXT_DOMAIN, 233 "Incorrect channel bindings" 234 " were supplied"); 235 break; 236 237 case GSS_S_BAD_SIG: /* same as GSS_S_BAD_MIC: */ 238 errStr = dgettext(TEXT_DOMAIN, 239 "A token had an invalid Message" 240 " Integrity Check (MIC)"); 241 break; 242 243 case GSS_S_NO_CRED: 244 errStr = dgettext(TEXT_DOMAIN, 245 "No credentials were supplied, or the" 246 " credentials were unavailable or" 247 " inaccessible"); 248 break; 249 250 case GSS_S_NO_CONTEXT: 251 errStr = dgettext(TEXT_DOMAIN, 252 "No context has been established"); 253 break; 254 255 case GSS_S_DEFECTIVE_TOKEN: 256 errStr = dgettext(TEXT_DOMAIN, 257 "Invalid token was supplied"); 258 break; 259 260 case GSS_S_DEFECTIVE_CREDENTIAL: 261 errStr = dgettext(TEXT_DOMAIN, 262 "Invalid credential was supplied"); 263 break; 264 265 case GSS_S_CREDENTIALS_EXPIRED: 266 errStr = dgettext(TEXT_DOMAIN, 267 "The referenced credential has" 268 " expired"); 269 break; 270 271 case GSS_S_CONTEXT_EXPIRED: 272 errStr = dgettext(TEXT_DOMAIN, 273 "The referenced context has expired"); 274 break; 275 276 case GSS_S_FAILURE: 277 errStr = dgettext(TEXT_DOMAIN, 278 "Unspecified GSS failure. Minor code" 279 " may provide more information"); 280 break; 281 282 case GSS_S_BAD_QOP: 283 errStr = dgettext(TEXT_DOMAIN, 284 "The quality-of-protection (QOP) " 285 "requested could not be provided"); 286 break; 287 288 case GSS_S_UNAUTHORIZED: 289 errStr = dgettext(TEXT_DOMAIN, 290 "The operation is forbidden by local" 291 " security policy"); 292 break; 293 294 case GSS_S_UNAVAILABLE: 295 errStr = dgettext(TEXT_DOMAIN, 296 "The operation or option is not" 297 " available or unsupported"); 298 break; 299 300 case GSS_S_DUPLICATE_ELEMENT: 301 errStr = dgettext(TEXT_DOMAIN, 302 "The requested credential element" 303 " already exists"); 304 break; 305 306 case GSS_S_NAME_NOT_MN: 307 errStr = dgettext(TEXT_DOMAIN, 308 "The provided name was not mechanism" 309 " specific (MN)"); 310 break; 311 312 case GSS_S_BAD_STATUS: 313 default: 314 errStr = dgettext(TEXT_DOMAIN, 315 "An invalid status code was supplied"); 316 } 317 318 /* we must determine if the caller should call us again */ 319 if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0) 320 *msgCtxt = (OM_uint32)(oneVal << 1); 321 else 322 *msgCtxt = 0; 323 324 } else if ((*msgCtxt == 0 || *msgCtxt >= 2) && 325 (oneVal = GSS_SUPPLEMENTARY_INFO(status))) { 326 /* 327 * if msgCtxt is not 0, then it should encode 328 * the supplementary error code we should be printing 329 */ 330 if (*msgCtxt >= 2) 331 oneVal = (OM_uint32) (*msgCtxt) >> 1; 332 else 333 oneVal = GSS_SUPPLEMENTARY_INFO(status); 334 335 /* we display the errors LSB first */ 336 for (i = 0; i < 16; i++) { 337 if (oneVal & mask) { 338 haveErr = 1; 339 break; 340 } 341 mask <<= 1; 342 } 343 344 /* isolate the bit or if not found set to illegal value */ 345 if (haveErr) 346 currErr = oneVal & mask; 347 else 348 currErr = 1 << 17; /* illegal value */ 349 350 switch (currErr) { 351 case GSS_S_CONTINUE_NEEDED: 352 errStr = dgettext(TEXT_DOMAIN, 353 "The routine must be called again to" 354 " complete its function"); 355 break; 356 357 case GSS_S_DUPLICATE_TOKEN: 358 errStr = dgettext(TEXT_DOMAIN, 359 "The token was a duplicate of an" 360 " earlier token"); 361 break; 362 363 case GSS_S_OLD_TOKEN: 364 errStr = dgettext(TEXT_DOMAIN, 365 "The token's validity period" 366 " has expired"); 367 break; 368 369 case GSS_S_UNSEQ_TOKEN: 370 errStr = dgettext(TEXT_DOMAIN, 371 "A later token has already been" 372 " processed"); 373 break; 374 375 case GSS_S_GAP_TOKEN: 376 errStr = dgettext(TEXT_DOMAIN, 377 "An expected per-message token was" 378 " not received"); 379 break; 380 381 default: 382 errStr = dgettext(TEXT_DOMAIN, 383 "An invalid status code was supplied"); 384 } 385 386 /* 387 * we must check if there is any other supplementary errors 388 * if found, then turn off current bit, and store next value 389 * in msgCtxt shifted by 1 bit 390 */ 391 if (!haveErr) 392 *msgCtxt = 0; 393 else if (GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) 394 *msgCtxt = (OM_uint32) 395 ((GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) << 1); 396 else 397 *msgCtxt = 0; 398 } 399 400 if (errStr == NULL) 401 errStr = dgettext(TEXT_DOMAIN, 402 "An invalid status code was supplied"); 403 404 /* now copy the status code and return to caller */ 405 outStr->length = strlen(errStr); 406 outStr->value = strdup(errStr); 407 if (outStr->value == NULL) { 408 outStr->length = 0; 409 return (GSS_S_FAILURE); 410 } 411 412 return (GSS_S_COMPLETE); 413 } /* displayMajor */ 414