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