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
compare_OM_uint32(OM_uint32 a,OM_uint32 b)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
free_string(char * s)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
get_error_message(OM_uint32 minor_code)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
save_error_string_nocopy(OM_uint32 minor_code,char * msg)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 }
save_error_string(OM_uint32 minor_code,char * msg)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 }
save_error_message(OM_uint32 minor_code,const char * format,...)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 }
spnego_gss_save_error_info(OM_uint32 minor_code,spnego_gss_ctx_id_t ctx)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 }
spnego_gss_delete_error_info(void * p)171 void spnego_gss_delete_error_info(void *p)
172 {
173 gsserrmap_destroy(p);
174 }
175
176 OM_uint32
spnego_gss_display_status2(minor_status,status_value,status_type,mech_type,message_context,status_string)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