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
compare_OM_uint32(OM_uint32 a,OM_uint32 b)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
free_string(char * s)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 */
get_error_message(OM_uint32 minor_code)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
save_error_string_nocopy(OM_uint32 minor_code,char * msg)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 }
save_error_string(OM_uint32 minor_code,char * msg)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 }
save_error_message(OM_uint32 minor_code,const char * format,...)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 }
krb5_gss_save_error_info(OM_uint32 minor_code,krb5_context ctx)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 }
krb5_gss_delete_error_info(void * p)163 void krb5_gss_delete_error_info(void *p)
164 {
165 gsserrmap_destroy(p);
166 }
167
168 /**/
169
170 OM_uint32
krb5_gss_display_status(minor_status,status_value,status_type,mech_type,message_context,status_string)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
krb5_gss_display_status2(minor_status,status_value,status_type,mech_type,message_context,status_string)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