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