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