1 /* -*- mode: c; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 4 */ 5 /* 6 * Copyright 1993 by OpenVision Technologies, Inc. 7 * 8 * Permission to use, copy, modify, distribute, and sell this software 9 * and its documentation for any purpose is hereby granted without fee, 10 * provided that the above copyright notice appears in all copies and 11 * that both that copyright notice and this permission notice appear in 12 * supporting documentation, and that the name of OpenVision not be used 13 * in advertising or publicity pertaining to distribution of the software 14 * without specific, written prior permission. OpenVision makes no 15 * representations about the suitability of this software for any 16 * purpose. It is provided "as is" without express or implied warranty. 17 * 18 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 19 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 20 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR 21 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 22 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 23 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 24 * PERFORMANCE OF THIS SOFTWARE. 25 */ 26 27 #include "gssapiP_krb5.h" 28 #include "com_err.h" 29 #include <syslog.h> 30 /* XXXX internationalization!! */ 31 32 static inline int 33 compare_OM_uint32 (OM_uint32 a, OM_uint32 b) 34 { 35 if (a < b) 36 return -1; 37 else if (a == b) 38 return 0; 39 else 40 return 1; 41 } 42 static inline void 43 free_string (char *s) 44 { 45 free(s); 46 } 47 #include "error_map.h" 48 #include <stdio.h> 49 /* 50 * AKA krb5_gss_get_error_message. See #define in gssapiP_krb5.h. 51 */ 52 char *get_error_message(OM_uint32 minor_code) 53 { 54 gsserrmap *p = k5_getspecific(K5_KEY_GSS_KRB5_ERROR_MESSAGE); 55 char *msg = NULL; 56 57 #ifdef DEBUG 58 fprintf(stderr, "%s(%lu, p=%p)", __func__, (unsigned long) minor_code, 59 (void *) p); 60 #endif 61 if (p) { 62 char **v = gsserrmap_find(p, minor_code); 63 if (v) { 64 msg = *v; 65 #ifdef DEBUG 66 fprintf(stderr, " FOUND!"); 67 #endif 68 } 69 } 70 if (msg == NULL) 71 msg = (char *)error_message((krb5_error_code)minor_code); 72 #ifdef DEBUG 73 fprintf(stderr, " -> %p/%s\n", (void *) msg, msg); 74 #endif 75 76 return msg; 77 } 78 #define save_error_string_nocopy gss_krb5_save_error_string_nocopy 79 static int save_error_string_nocopy(OM_uint32 minor_code, char *msg) 80 { 81 gsserrmap *p; 82 int ret; 83 84 #ifdef DEBUG 85 fprintf(stderr, "%s(%lu, %s)", __func__, (unsigned long) minor_code, msg); 86 #endif 87 p = k5_getspecific(K5_KEY_GSS_KRB5_ERROR_MESSAGE); 88 if (!p) { 89 p = malloc(sizeof(*p)); 90 if (p == NULL) { 91 ret = 1; 92 goto fail; 93 } 94 if (gsserrmap_init(p) != 0) { 95 free(p); 96 p = NULL; 97 ret = 1; 98 goto fail; 99 } 100 if (k5_setspecific(K5_KEY_GSS_KRB5_ERROR_MESSAGE, p) != 0) { 101 gsserrmap_destroy(p); 102 free(p); 103 p = NULL; 104 ret = 1; 105 goto fail; 106 } 107 } 108 ret = gsserrmap_replace_or_insert(p, minor_code, msg); 109 /* Solaris Kerberos */ 110 if (ret) { 111 gsserrmap_destroy(p); 112 free(p); 113 p = NULL; 114 } 115 116 fail: 117 #ifdef DEBUG 118 fprintf(stderr, " p=%p %s\n", (void *)p, ret ? "FAIL" : "SUCCESS"); 119 #endif 120 return ret; 121 } 122 void save_error_string(OM_uint32 minor_code, char *msg) 123 { 124 char *s = strdup(msg); 125 if (s) { 126 if (save_error_string_nocopy(minor_code, s) != 0) 127 free(s); 128 } 129 } 130 void save_error_message(OM_uint32 minor_code, const char *format, ...) 131 { 132 char *s; 133 int n; 134 va_list ap; 135 136 va_start(ap, format); 137 n = vasprintf(&s, format, ap); 138 va_end(ap); 139 if (n >= 0) { 140 if (save_error_string_nocopy(minor_code, s) != 0) 141 free(s); 142 } 143 } 144 void krb5_gss_save_error_info(OM_uint32 minor_code, krb5_context ctx) 145 { 146 char *s; 147 148 #ifdef DEBUG 149 fprintf(stderr, "%s(%lu, ctx=%p)\n", __func__, 150 (unsigned long) minor_code, (void *)ctx); 151 #endif 152 s = (char *)krb5_get_error_message(ctx, (krb5_error_code)minor_code); 153 #ifdef DEBUG 154 fprintf(stderr, "%s(%lu, ctx=%p) saving: %s\n", __func__, 155 (unsigned long) minor_code, (void *)ctx, s); 156 #endif 157 save_error_string(minor_code, s); 158 /* The get_error_message call above resets the error message in 159 ctx. Put it back, in case we make this call again *sigh*. */ 160 krb5_set_error_message(ctx, (krb5_error_code)minor_code, "%s", s); 161 krb5_free_error_message(ctx, s); 162 } 163 void krb5_gss_delete_error_info(void *p) 164 { 165 gsserrmap_destroy(p); 166 } 167 168 /**/ 169 170 OM_uint32 171 krb5_gss_display_status(minor_status, status_value, status_type, 172 mech_type, message_context, status_string) 173 OM_uint32 *minor_status; 174 OM_uint32 status_value; 175 int status_type; 176 gss_OID mech_type; 177 OM_uint32 *message_context; 178 gss_buffer_t status_string; 179 { 180 status_string->length = 0; 181 status_string->value = NULL; 182 183 if ((mech_type != GSS_C_NULL_OID) && 184 !g_OID_equal(gss_mech_krb5, mech_type) && 185 !g_OID_equal(gss_mech_krb5_old, mech_type)) { 186 *minor_status = 0; 187 return(GSS_S_BAD_MECH); 188 } 189 190 if (status_type == GSS_C_GSS_CODE) { 191 return(g_display_major_status(minor_status, status_value, 192 message_context, status_string)); 193 } else if (status_type == GSS_C_MECH_CODE) { 194 (void) gss_krb5int_initialize_library(); 195 196 if (*message_context) { 197 *minor_status = (OM_uint32) G_BAD_MSG_CTX; 198 return(GSS_S_FAILURE); 199 } 200 201 /* If this fails, there's not much we can do... */ 202 /* Solaris Kerberos - cleaned-up/fixed the return checks/values here */ 203 if (!g_make_string_buffer(krb5_gss_get_error_message(status_value), 204 status_string)) { 205 *minor_status = ENOMEM; 206 return(GSS_S_FAILURE); 207 } 208 *minor_status = 0; 209 return(GSS_S_COMPLETE); 210 } else { 211 *minor_status = 0; 212 return(GSS_S_BAD_STATUS); 213 } 214 } 215 216 /* 217 * Solaris Kerberos 218 * Hack alert: workaround obfusicated func name issues for mech_spnego.so. 219 */ 220 OM_uint32 221 krb5_gss_display_status2(minor_status, status_value, status_type, 222 mech_type, message_context, status_string) 223 OM_uint32 *minor_status; 224 OM_uint32 status_value; 225 int status_type; 226 gss_OID mech_type; 227 OM_uint32 *message_context; 228 gss_buffer_t status_string; 229 { 230 return(krb5_gss_display_status(minor_status, status_value, 231 status_type, mech_type, message_context, 232 status_string)); 233 } 234