1 /*- 2 * Copyright (c) 2005 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 /* 29 * Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan 30 * (Royal Institute of Technology, Stockholm, Sweden). 31 * All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 37 * 1. Redistributions of source code must retain the above copyright 38 * notice, this list of conditions and the following disclaimer. 39 * 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 44 * 3. Neither the name of the Institute nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 */ 60 /* 61 * Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan 62 * (Royal Institute of Technology, Stockholm, Sweden). 63 * All rights reserved. 64 * 65 * Redistribution and use in source and binary forms, with or without 66 * modification, are permitted provided that the following conditions 67 * are met: 68 * 69 * 1. Redistributions of source code must retain the above copyright 70 * notice, this list of conditions and the following disclaimer. 71 * 72 * 2. Redistributions in binary form must reproduce the above copyright 73 * notice, this list of conditions and the following disclaimer in the 74 * documentation and/or other materials provided with the distribution. 75 * 76 * 3. Neither the name of the Institute nor the names of its contributors 77 * may be used to endorse or promote products derived from this software 78 * without specific prior written permission. 79 * 80 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 81 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 82 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 83 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 84 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 85 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 86 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 87 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 88 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 89 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 90 * SUCH DAMAGE. 91 */ 92 93 #include <gssapi/gssapi.h> 94 #include <stdio.h> 95 #include <string.h> 96 #include <stdlib.h> 97 #include <errno.h> 98 99 #include "mech_switch.h" 100 #include "utils.h" 101 102 static const char * 103 calling_error(OM_uint32 v) 104 { 105 static const char *msgs[] = { 106 NULL, /* 0 */ 107 "A required input parameter could not be read.", /* */ 108 "A required output parameter could not be written.", /* */ 109 "A parameter was malformed" 110 }; 111 112 v >>= GSS_C_CALLING_ERROR_OFFSET; 113 114 if (v == 0) 115 return ""; 116 else if (v >= sizeof(msgs)/sizeof(*msgs)) 117 return "unknown calling error"; 118 else 119 return msgs[v]; 120 } 121 122 static const char * 123 routine_error(OM_uint32 v) 124 { 125 static const char *msgs[] = { 126 "Function completed successfully", /* 0 */ 127 "An unsupported mechanism was requested", 128 "An invalid name was supplied", 129 "A supplied name was of an unsupported type", 130 "Incorrect channel bindings were supplied", 131 "An invalid status code was supplied", 132 "A token had an invalid MIC", 133 "No credentials were supplied, " 134 "or the credentials were unavailable or inaccessible.", 135 "No context has been established", 136 "A token was invalid", 137 "A credential was invalid", 138 "The referenced credentials have expired", 139 "The context has expired", 140 "Miscellaneous failure (see text)", 141 "The quality-of-protection requested could not be provide", 142 "The operation is forbidden by local security policy", 143 "The operation or option is not available", 144 "The requested credential element already exists", 145 "The provided name was not a mechanism name.", 146 }; 147 148 v >>= GSS_C_ROUTINE_ERROR_OFFSET; 149 150 if (v >= sizeof(msgs)/sizeof(*msgs)) 151 return "unknown routine error"; 152 else 153 return msgs[v]; 154 } 155 156 static const char * 157 supplementary_error(OM_uint32 v) 158 { 159 static const char *msgs[] = { 160 "normal completion", 161 "continuation call to routine required", 162 "duplicate per-message token detected", 163 "timed-out per-message token detected", 164 "reordered (early) per-message token detected", 165 "skipped predecessor token(s) detected" 166 }; 167 168 v >>= GSS_C_SUPPLEMENTARY_OFFSET; 169 170 if (v >= sizeof(msgs)/sizeof(*msgs)) 171 return "unknown routine error"; 172 else 173 return msgs[v]; 174 } 175 176 #if defined(__NO_TLS) 177 178 /* 179 * These platforms don't support TLS on FreeBSD - threads will just 180 * have to step on each other's error values for now. 181 */ 182 #define __thread 183 184 #endif 185 186 struct mg_thread_ctx { 187 gss_OID mech; 188 OM_uint32 maj_stat; 189 OM_uint32 min_stat; 190 gss_buffer_desc maj_error; 191 gss_buffer_desc min_error; 192 }; 193 static __thread struct mg_thread_ctx last_error_context; 194 195 static OM_uint32 196 _gss_mg_get_error(const gss_OID mech, OM_uint32 type, 197 OM_uint32 value, gss_buffer_t string) 198 { 199 struct mg_thread_ctx *mg; 200 201 mg = &last_error_context; 202 203 if (mech != NULL && gss_oid_equal(mg->mech, mech) == 0) 204 return (GSS_S_BAD_STATUS); 205 206 switch (type) { 207 case GSS_C_GSS_CODE: { 208 if (value != mg->maj_stat || mg->maj_error.length == 0) 209 break; 210 string->value = malloc(mg->maj_error.length); 211 string->length = mg->maj_error.length; 212 memcpy(string->value, mg->maj_error.value, 213 mg->maj_error.length); 214 return (GSS_S_COMPLETE); 215 } 216 case GSS_C_MECH_CODE: { 217 if (value != mg->min_stat || mg->min_error.length == 0) 218 break; 219 string->value = malloc(mg->min_error.length); 220 string->length = mg->min_error.length; 221 memcpy(string->value, mg->min_error.value, 222 mg->min_error.length); 223 return (GSS_S_COMPLETE); 224 } 225 } 226 string->value = NULL; 227 string->length = 0; 228 return (GSS_S_BAD_STATUS); 229 } 230 231 void 232 _gss_mg_error(struct _gss_mech_switch *m, OM_uint32 maj, OM_uint32 min) 233 { 234 OM_uint32 major_status, minor_status; 235 OM_uint32 message_content; 236 struct mg_thread_ctx *mg; 237 238 mg = &last_error_context; 239 240 gss_release_buffer(&minor_status, &mg->maj_error); 241 gss_release_buffer(&minor_status, &mg->min_error); 242 243 mg->mech = &m->gm_mech_oid; 244 mg->maj_stat = maj; 245 mg->min_stat = min; 246 247 major_status = m->gm_display_status(&minor_status, 248 maj, 249 GSS_C_GSS_CODE, 250 &m->gm_mech_oid, 251 &message_content, 252 &mg->maj_error); 253 if (GSS_ERROR(major_status)) { 254 mg->maj_error.value = NULL; 255 mg->maj_error.length = 0; 256 } 257 major_status = m->gm_display_status(&minor_status, 258 min, 259 GSS_C_MECH_CODE, 260 &m->gm_mech_oid, 261 &message_content, 262 &mg->min_error); 263 if (GSS_ERROR(major_status)) { 264 mg->min_error.value = NULL; 265 mg->min_error.length = 0; 266 } 267 } 268 269 OM_uint32 270 gss_display_status(OM_uint32 *minor_status, 271 OM_uint32 status_value, 272 int status_type, 273 const gss_OID mech_type, 274 OM_uint32 *message_content, 275 gss_buffer_t status_string) 276 { 277 OM_uint32 major_status; 278 279 _gss_buffer_zero(status_string); 280 *message_content = 0; 281 282 major_status = _gss_mg_get_error(mech_type, status_type, 283 status_value, status_string); 284 if (major_status == GSS_S_COMPLETE) { 285 286 *message_content = 0; 287 *minor_status = 0; 288 return (GSS_S_COMPLETE); 289 } 290 291 *minor_status = 0; 292 switch (status_type) { 293 case GSS_C_GSS_CODE: { 294 char *buf; 295 296 if (GSS_SUPPLEMENTARY_INFO(status_value)) 297 asprintf(&buf, "%s", supplementary_error( 298 GSS_SUPPLEMENTARY_INFO(status_value))); 299 else 300 asprintf (&buf, "%s %s", 301 calling_error(GSS_CALLING_ERROR(status_value)), 302 routine_error(GSS_ROUTINE_ERROR(status_value))); 303 304 if (buf == NULL) 305 break; 306 307 status_string->length = strlen(buf); 308 status_string->value = buf; 309 310 return (GSS_S_COMPLETE); 311 } 312 case GSS_C_MECH_CODE: { 313 OM_uint32 maj_junk, min_junk; 314 gss_buffer_desc oid; 315 char *buf; 316 317 maj_junk = gss_oid_to_str(&min_junk, mech_type, &oid); 318 if (maj_junk != GSS_S_COMPLETE) { 319 oid.value = strdup("unknown"); 320 oid.length = 7; 321 } 322 323 asprintf (&buf, "unknown mech-code %lu for mech %.*s", 324 (unsigned long)status_value, 325 (int)oid.length, (char *)oid.value); 326 if (maj_junk == GSS_S_COMPLETE) 327 gss_release_buffer(&min_junk, &oid); 328 329 if (buf == NULL) 330 break; 331 332 status_string->length = strlen(buf); 333 status_string->value = buf; 334 335 return (GSS_S_COMPLETE); 336 } 337 } 338 _gss_buffer_zero(status_string); 339 return (GSS_S_BAD_STATUS); 340 } 341 342 void 343 _gss_mg_collect_error(gss_OID mech, OM_uint32 maj, OM_uint32 min) 344 { 345 struct _gss_mech_switch *m; 346 347 m = _gss_find_mech_switch(mech); 348 if (m != NULL) 349 _gss_mg_error(m, maj, min); 350 } 351