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