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 struct mg_thread_ctx { 178 gss_OID mech; 179 OM_uint32 maj_stat; 180 OM_uint32 min_stat; 181 gss_buffer_desc maj_error; 182 gss_buffer_desc min_error; 183 }; 184 static __thread struct mg_thread_ctx last_error_context; 185 186 static OM_uint32 187 _gss_mg_get_error(const gss_OID mech, OM_uint32 type, 188 OM_uint32 value, gss_buffer_t string) 189 { 190 struct mg_thread_ctx *mg; 191 192 mg = &last_error_context; 193 194 if (mech != NULL && gss_oid_equal(mg->mech, mech) == 0) 195 return (GSS_S_BAD_STATUS); 196 197 switch (type) { 198 case GSS_C_GSS_CODE: { 199 if (value != mg->maj_stat || mg->maj_error.length == 0) 200 break; 201 string->value = malloc(mg->maj_error.length); 202 string->length = mg->maj_error.length; 203 memcpy(string->value, mg->maj_error.value, 204 mg->maj_error.length); 205 return (GSS_S_COMPLETE); 206 } 207 case GSS_C_MECH_CODE: { 208 if (value != mg->min_stat || mg->min_error.length == 0) 209 break; 210 string->value = malloc(mg->min_error.length); 211 string->length = mg->min_error.length; 212 memcpy(string->value, mg->min_error.value, 213 mg->min_error.length); 214 return (GSS_S_COMPLETE); 215 } 216 } 217 string->value = NULL; 218 string->length = 0; 219 return (GSS_S_BAD_STATUS); 220 } 221 222 void 223 _gss_mg_error(struct _gss_mech_switch *m, OM_uint32 maj, OM_uint32 min) 224 { 225 OM_uint32 major_status, minor_status; 226 OM_uint32 message_content; 227 struct mg_thread_ctx *mg; 228 229 mg = &last_error_context; 230 231 gss_release_buffer(&minor_status, &mg->maj_error); 232 gss_release_buffer(&minor_status, &mg->min_error); 233 234 mg->mech = &m->gm_mech_oid; 235 mg->maj_stat = maj; 236 mg->min_stat = min; 237 238 major_status = m->gm_display_status(&minor_status, 239 maj, 240 GSS_C_GSS_CODE, 241 &m->gm_mech_oid, 242 &message_content, 243 &mg->maj_error); 244 if (GSS_ERROR(major_status)) { 245 mg->maj_error.value = NULL; 246 mg->maj_error.length = 0; 247 } 248 major_status = m->gm_display_status(&minor_status, 249 min, 250 GSS_C_MECH_CODE, 251 &m->gm_mech_oid, 252 &message_content, 253 &mg->min_error); 254 if (GSS_ERROR(major_status)) { 255 mg->min_error.value = NULL; 256 mg->min_error.length = 0; 257 } 258 } 259 260 OM_uint32 261 gss_display_status(OM_uint32 *minor_status, 262 OM_uint32 status_value, 263 int status_type, 264 const gss_OID mech_type, 265 OM_uint32 *message_content, 266 gss_buffer_t status_string) 267 { 268 OM_uint32 major_status; 269 270 _gss_buffer_zero(status_string); 271 *message_content = 0; 272 273 major_status = _gss_mg_get_error(mech_type, status_type, 274 status_value, status_string); 275 if (major_status == GSS_S_COMPLETE) { 276 277 *message_content = 0; 278 *minor_status = 0; 279 return (GSS_S_COMPLETE); 280 } 281 282 *minor_status = 0; 283 switch (status_type) { 284 case GSS_C_GSS_CODE: { 285 char *buf; 286 287 if (GSS_SUPPLEMENTARY_INFO(status_value)) 288 asprintf(&buf, "%s", supplementary_error( 289 GSS_SUPPLEMENTARY_INFO(status_value))); 290 else 291 asprintf (&buf, "%s %s", 292 calling_error(GSS_CALLING_ERROR(status_value)), 293 routine_error(GSS_ROUTINE_ERROR(status_value))); 294 295 if (buf == NULL) 296 break; 297 298 status_string->length = strlen(buf); 299 status_string->value = buf; 300 301 return (GSS_S_COMPLETE); 302 } 303 case GSS_C_MECH_CODE: { 304 OM_uint32 maj_junk, min_junk; 305 gss_buffer_desc oid; 306 char *buf; 307 308 maj_junk = gss_oid_to_str(&min_junk, mech_type, &oid); 309 if (maj_junk != GSS_S_COMPLETE) { 310 oid.value = strdup("unknown"); 311 oid.length = 7; 312 } 313 314 asprintf (&buf, "unknown mech-code %lu for mech %.*s", 315 (unsigned long)status_value, 316 (int)oid.length, (char *)oid.value); 317 if (maj_junk == GSS_S_COMPLETE) 318 gss_release_buffer(&min_junk, &oid); 319 320 if (buf == NULL) 321 break; 322 323 status_string->length = strlen(buf); 324 status_string->value = buf; 325 326 return (GSS_S_COMPLETE); 327 } 328 } 329 _gss_buffer_zero(status_string); 330 return (GSS_S_BAD_STATUS); 331 } 332 333 void 334 _gss_mg_collect_error(gss_OID mech, OM_uint32 maj, OM_uint32 min) 335 { 336 struct _gss_mech_switch *m; 337 338 m = _gss_find_mech_switch(mech); 339 if (m != NULL) 340 _gss_mg_error(m, maj, min); 341 } 342