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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * glue routine gss_display_status 28 * 29 */ 30 31 #include <mechglueP.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 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 66 if (minor_status != NULL) 67 *minor_status = 0; 68 69 if (status_string != GSS_C_NO_BUFFER) { 70 status_string->length = 0; 71 status_string->value = NULL; 72 } 73 74 if (minor_status == NULL || 75 message_context == NULL || 76 status_string == GSS_C_NO_BUFFER) 77 return (GSS_S_CALL_INACCESSIBLE_WRITE); 78 79 /* we handle major status codes, and the mechs do the minor */ 80 if (status_type == GSS_C_GSS_CODE) 81 return (displayMajor(status_value, message_context, 82 status_string)); 83 84 /* 85 * must be the minor status - let mechs do the work 86 * select the appropriate underlying mechanism routine and 87 * call it. 88 */ 89 mech = __gss_get_mechanism(mech_type); 90 91 if (mech && mech->gss_display_status) { 92 if (mech_type == GSS_C_NULL_OID) 93 mech_type = &mech->mech_type; 94 95 return (mech->gss_display_status(mech->context, minor_status, 96 status_value, status_type, mech_type, 97 message_context, status_string)); 98 } 99 100 if (!mech) 101 return (GSS_S_BAD_MECH); 102 103 return (GSS_S_UNAVAILABLE); 104 } /* gss_display_status */ 105 106 107 /* 108 * function to map the major error codes 109 * it uses case statements so that the strings could be wrapped by gettext 110 * msgCtxt is interpreted as: 111 * 0 - first call 112 * 1 - routine error 113 * >= 2 - the supplementary error code bit shifted by 1 114 */ 115 static OM_uint32 116 displayMajor(status, msgCtxt, outStr) 117 OM_uint32 status; 118 OM_uint32 *msgCtxt; 119 gss_buffer_t outStr; 120 { 121 OM_uint32 oneVal, mask = 0x1, currErr; 122 char *errStr = NULL; 123 int i, haveErr = 0; 124 125 /* take care of the success value first */ 126 if (status == GSS_S_COMPLETE) 127 errStr = dgettext(TEXT_DOMAIN, 128 "The routine completed successfully"); 129 else if (*msgCtxt == 0 && (oneVal = GSS_CALLING_ERROR(status))) { 130 switch (oneVal) { 131 case GSS_S_CALL_INACCESSIBLE_READ: 132 errStr = dgettext(TEXT_DOMAIN, 133 "A required input parameter" 134 " could not be read"); 135 break; 136 137 case GSS_S_CALL_INACCESSIBLE_WRITE: 138 errStr = dgettext(TEXT_DOMAIN, 139 "A required output parameter" 140 " could not be written"); 141 break; 142 143 case GSS_S_CALL_BAD_STRUCTURE: 144 errStr = dgettext(TEXT_DOMAIN, 145 "A parameter was malformed"); 146 break; 147 148 default: 149 errStr = dgettext(TEXT_DOMAIN, 150 "An invalid status code was supplied"); 151 break; 152 } 153 154 /* we now need to determine new value of msgCtxt */ 155 if (GSS_ROUTINE_ERROR(status)) 156 *msgCtxt = 1; 157 else if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0) 158 *msgCtxt = (OM_uint32)(oneVal << 1); 159 else 160 *msgCtxt = 0; 161 162 } else if ((*msgCtxt == 0 || *msgCtxt == 1) && 163 (oneVal = GSS_ROUTINE_ERROR(status))) { 164 switch (oneVal) { 165 case GSS_S_BAD_MECH: 166 errStr = dgettext(TEXT_DOMAIN, 167 "An unsupported mechanism" 168 " was requested"); 169 break; 170 171 case GSS_S_BAD_NAME: 172 errStr = dgettext(TEXT_DOMAIN, 173 "An invalid name was supplied"); 174 break; 175 176 case GSS_S_BAD_NAMETYPE: 177 errStr = dgettext(TEXT_DOMAIN, 178 "A supplied name was of an" 179 " unsupported type"); 180 break; 181 182 case GSS_S_BAD_BINDINGS: 183 errStr = dgettext(TEXT_DOMAIN, 184 "Incorrect channel bindings" 185 " were supplied"); 186 break; 187 188 case GSS_S_BAD_SIG: /* same as GSS_S_BAD_MIC: */ 189 errStr = dgettext(TEXT_DOMAIN, 190 "A token had an invalid Message" 191 " Integrity Check (MIC)"); 192 break; 193 194 case GSS_S_NO_CRED: 195 errStr = dgettext(TEXT_DOMAIN, 196 "No credentials were supplied, or the" 197 " credentials were unavailable or" 198 " inaccessible"); 199 break; 200 201 case GSS_S_NO_CONTEXT: 202 errStr = dgettext(TEXT_DOMAIN, 203 "No context has been established"); 204 break; 205 206 case GSS_S_DEFECTIVE_TOKEN: 207 errStr = dgettext(TEXT_DOMAIN, 208 "Invalid token was supplied"); 209 break; 210 211 case GSS_S_DEFECTIVE_CREDENTIAL: 212 errStr = dgettext(TEXT_DOMAIN, 213 "Invalid credential was supplied"); 214 break; 215 216 case GSS_S_CREDENTIALS_EXPIRED: 217 errStr = dgettext(TEXT_DOMAIN, 218 "The referenced credential has" 219 " expired"); 220 break; 221 222 case GSS_S_CONTEXT_EXPIRED: 223 errStr = dgettext(TEXT_DOMAIN, 224 "The referenced context has expired"); 225 break; 226 227 case GSS_S_FAILURE: 228 errStr = dgettext(TEXT_DOMAIN, 229 "Unspecified GSS failure. Minor code" 230 " may provide more information"); 231 break; 232 233 case GSS_S_BAD_QOP: 234 errStr = dgettext(TEXT_DOMAIN, 235 "The quality-of-protection (QOP) " 236 "requested could not be provided"); 237 break; 238 239 case GSS_S_UNAUTHORIZED: 240 errStr = dgettext(TEXT_DOMAIN, 241 "The operation is forbidden by local" 242 " security policy"); 243 break; 244 245 case GSS_S_UNAVAILABLE: 246 errStr = dgettext(TEXT_DOMAIN, 247 "The operation or option is not" 248 " available or unsupported"); 249 break; 250 251 case GSS_S_DUPLICATE_ELEMENT: 252 errStr = dgettext(TEXT_DOMAIN, 253 "The requested credential element" 254 " already exists"); 255 break; 256 257 case GSS_S_NAME_NOT_MN: 258 errStr = dgettext(TEXT_DOMAIN, 259 "The provided name was not mechanism" 260 " specific (MN)"); 261 break; 262 263 case GSS_S_BAD_STATUS: 264 default: 265 errStr = dgettext(TEXT_DOMAIN, 266 "An invalid status code was supplied"); 267 } 268 269 /* we must determine if the caller should call us again */ 270 if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0) 271 *msgCtxt = (OM_uint32)(oneVal << 1); 272 else 273 *msgCtxt = 0; 274 275 } else if ((*msgCtxt == 0 || *msgCtxt >= 2) && 276 (oneVal = GSS_SUPPLEMENTARY_INFO(status))) { 277 /* 278 * if msgCtxt is not 0, then it should encode 279 * the supplementary error code we should be printing 280 */ 281 if (*msgCtxt >= 2) 282 oneVal = (OM_uint32) (*msgCtxt) >> 1; 283 else 284 oneVal = GSS_SUPPLEMENTARY_INFO(status); 285 286 /* we display the errors LSB first */ 287 for (i = 0; i < 16; i++) { 288 if (oneVal & mask) { 289 haveErr = 1; 290 break; 291 } 292 mask <<= 1; 293 } 294 295 /* isolate the bit or if not found set to illegal value */ 296 if (haveErr) 297 currErr = oneVal & mask; 298 else 299 currErr = 1 << 17; /* illegal value */ 300 301 switch (currErr) { 302 case GSS_S_CONTINUE_NEEDED: 303 errStr = dgettext(TEXT_DOMAIN, 304 "The routine must be called again to" 305 " complete its function"); 306 break; 307 308 case GSS_S_DUPLICATE_TOKEN: 309 errStr = dgettext(TEXT_DOMAIN, 310 "The token was a duplicate of an" 311 " earlier token"); 312 break; 313 314 case GSS_S_OLD_TOKEN: 315 errStr = dgettext(TEXT_DOMAIN, 316 "The token's validity period" 317 " has expired"); 318 break; 319 320 case GSS_S_UNSEQ_TOKEN: 321 errStr = dgettext(TEXT_DOMAIN, 322 "A later token has already been" 323 " processed"); 324 break; 325 326 case GSS_S_GAP_TOKEN: 327 errStr = dgettext(TEXT_DOMAIN, 328 "An expected per-message token was" 329 " not received"); 330 break; 331 332 default: 333 errStr = dgettext(TEXT_DOMAIN, 334 "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 = dgettext(TEXT_DOMAIN, 353 "An invalid status code was supplied"); 354 355 /* now copy the status code and return to caller */ 356 outStr->length = strlen(errStr); 357 outStr->value = malloc((size_t)outStr->length+1); 358 if (outStr->value == NULL) { 359 outStr->length = 0; 360 return (GSS_S_FAILURE); 361 } 362 363 (void) strcpy((char *)outStr->value, errStr); 364 return (GSS_S_COMPLETE); 365 } /* displayMajor */ 366