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