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 /* 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 <sys/param.h> 94 #include <gssapi/gssapi.h> 95 #include <stdio.h> 96 #include <string.h> 97 #include <stdlib.h> 98 #include <errno.h> 99 100 #include "mech_switch.h" 101 #include "utils.h" 102 103 static const char * 104 calling_error(OM_uint32 v) 105 { 106 static const char *msgs[] = { 107 [0] = "", 108 [1] = "A required input parameter could not be read.", 109 [2] = "A required output parameter could not be written.", 110 [3] = "A parameter was malformed", 111 }; 112 113 v >>= GSS_C_CALLING_ERROR_OFFSET; 114 115 if (v >= nitems(msgs)) 116 return "unknown calling error"; 117 else 118 return msgs[v]; 119 } 120 121 static const char * 122 routine_error(OM_uint32 v) 123 { 124 static const char *msgs[] = { 125 [0] = "Function completed successfully", 126 [1] = "An unsupported mechanism was requested", 127 [2] = "An invalid name was supplied", 128 [3] = "A supplied name was of an unsupported type", 129 [4] = "Incorrect channel bindings were supplied", 130 [5] = "An invalid status code was supplied", 131 [6] = "A token had an invalid MIC", 132 [7] = ("No credentials were supplied, " 133 "or the credentials were unavailable or inaccessible."), 134 [8] = "No context has been established", 135 [9] = "A token was invalid", 136 [10] = "A credential was invalid", 137 [11] = "The referenced credentials have expired", 138 [12] = "The context has expired", 139 [13] = "Miscellaneous failure (see text)", 140 [14] = "The quality-of-protection requested could not be provide", 141 [15] = "The operation is forbidden by local security policy", 142 [16] = "The operation or option is not available", 143 [17] = "The requested credential element already exists", 144 [18] = "The provided name was not a mechanism name.", 145 }; 146 147 v >>= GSS_C_ROUTINE_ERROR_OFFSET; 148 149 if (v >= nitems(msgs)) 150 return "unknown routine error"; 151 else 152 return msgs[v]; 153 } 154 155 static const char * 156 supplementary_error(OM_uint32 v) 157 { 158 static const char *msgs[] = { 159 [0] = "normal completion", 160 [1] = "continuation call to routine required", 161 [2] = "duplicate per-message token detected", 162 [3] = "timed-out per-message token detected", 163 [4] = "reordered (early) per-message token detected", 164 [5] = "skipped predecessor token(s) detected", 165 }; 166 167 v >>= GSS_C_SUPPLEMENTARY_OFFSET; 168 169 if (v >= nitems(msgs)) 170 return "unknown routine error"; 171 else 172 return msgs[v]; 173 } 174 175 struct mg_thread_ctx { 176 gss_OID mech; 177 OM_uint32 maj_stat; 178 OM_uint32 min_stat; 179 gss_buffer_desc maj_error; 180 gss_buffer_desc min_error; 181 }; 182 static __thread struct mg_thread_ctx last_error_context; 183 184 static OM_uint32 185 _gss_mg_get_error(const gss_OID mech, OM_uint32 type, 186 OM_uint32 value, gss_buffer_t string) 187 { 188 struct mg_thread_ctx *mg; 189 190 mg = &last_error_context; 191 192 if (mech != NULL && gss_oid_equal(mg->mech, mech) == 0) 193 return (GSS_S_BAD_STATUS); 194 195 switch (type) { 196 case GSS_C_GSS_CODE: { 197 if (value != mg->maj_stat || mg->maj_error.length == 0) 198 break; 199 string->value = malloc(mg->maj_error.length); 200 string->length = mg->maj_error.length; 201 memcpy(string->value, mg->maj_error.value, 202 mg->maj_error.length); 203 return (GSS_S_COMPLETE); 204 } 205 case GSS_C_MECH_CODE: { 206 if (value != mg->min_stat || mg->min_error.length == 0) 207 break; 208 string->value = malloc(mg->min_error.length); 209 string->length = mg->min_error.length; 210 memcpy(string->value, mg->min_error.value, 211 mg->min_error.length); 212 return (GSS_S_COMPLETE); 213 } 214 } 215 string->value = NULL; 216 string->length = 0; 217 return (GSS_S_BAD_STATUS); 218 } 219 220 void 221 _gss_mg_error(struct _gss_mech_switch *m, OM_uint32 maj, OM_uint32 min) 222 { 223 OM_uint32 major_status, minor_status; 224 OM_uint32 message_content; 225 struct mg_thread_ctx *mg; 226 227 mg = &last_error_context; 228 229 gss_release_buffer(&minor_status, &mg->maj_error); 230 gss_release_buffer(&minor_status, &mg->min_error); 231 232 mg->mech = &m->gm_mech_oid; 233 mg->maj_stat = maj; 234 mg->min_stat = min; 235 236 major_status = m->gm_display_status(&minor_status, 237 maj, 238 GSS_C_GSS_CODE, 239 &m->gm_mech_oid, 240 &message_content, 241 &mg->maj_error); 242 if (GSS_ERROR(major_status)) { 243 mg->maj_error.value = NULL; 244 mg->maj_error.length = 0; 245 } 246 major_status = m->gm_display_status(&minor_status, 247 min, 248 GSS_C_MECH_CODE, 249 &m->gm_mech_oid, 250 &message_content, 251 &mg->min_error); 252 if (GSS_ERROR(major_status)) { 253 mg->min_error.value = NULL; 254 mg->min_error.length = 0; 255 } 256 } 257 258 OM_uint32 259 gss_display_status(OM_uint32 *minor_status, 260 OM_uint32 status_value, 261 int status_type, 262 const gss_OID mech_type, 263 OM_uint32 *message_content, 264 gss_buffer_t status_string) 265 { 266 OM_uint32 major_status; 267 268 _gss_buffer_zero(status_string); 269 *message_content = 0; 270 271 major_status = _gss_mg_get_error(mech_type, status_type, 272 status_value, status_string); 273 if (major_status == GSS_S_COMPLETE) { 274 275 *message_content = 0; 276 *minor_status = 0; 277 return (GSS_S_COMPLETE); 278 } 279 280 *minor_status = 0; 281 switch (status_type) { 282 case GSS_C_GSS_CODE: { 283 char *buf; 284 285 if (GSS_SUPPLEMENTARY_INFO(status_value)) 286 asprintf(&buf, "%s", supplementary_error( 287 GSS_SUPPLEMENTARY_INFO(status_value))); 288 else 289 asprintf (&buf, "%s %s", 290 calling_error(GSS_CALLING_ERROR(status_value)), 291 routine_error(GSS_ROUTINE_ERROR(status_value))); 292 293 if (buf == NULL) 294 break; 295 296 status_string->length = strlen(buf); 297 status_string->value = buf; 298 299 return (GSS_S_COMPLETE); 300 } 301 case GSS_C_MECH_CODE: { 302 OM_uint32 maj_junk, min_junk; 303 gss_buffer_desc oid; 304 char *buf; 305 306 maj_junk = gss_oid_to_str(&min_junk, mech_type, &oid); 307 if (maj_junk != GSS_S_COMPLETE) { 308 oid.value = strdup("unknown"); 309 oid.length = 7; 310 } 311 312 asprintf (&buf, "unknown mech-code %lu for mech %.*s", 313 (unsigned long)status_value, 314 (int)oid.length, (char *)oid.value); 315 if (maj_junk == GSS_S_COMPLETE) 316 gss_release_buffer(&min_junk, &oid); 317 318 if (buf == NULL) 319 break; 320 321 status_string->length = strlen(buf); 322 status_string->value = buf; 323 324 return (GSS_S_COMPLETE); 325 } 326 } 327 _gss_buffer_zero(status_string); 328 return (GSS_S_BAD_STATUS); 329 } 330 331 void 332 _gss_mg_collect_error(gss_OID mech, OM_uint32 maj, OM_uint32 min) 333 { 334 struct _gss_mech_switch *m; 335 336 m = _gss_find_mech_switch(mech); 337 if (m != NULL) 338 _gss_mg_error(m, maj, min); 339 } 340