xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/krb5/error_string.c (revision 241bea01a19bbb306af27777a870b86d41cb3fda)
1 /*	$NetBSD: error_string.c,v 1.3 2019/12/15 22:50:50 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2001, 2003, 2005 - 2006 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include "krb5_locl.h"
37 
38 #undef __attribute__
39 #define __attribute__(x)
40 
41 /**
42  * Clears the error message from the Kerberos 5 context.
43  *
44  * @param context The Kerberos 5 context to clear
45  *
46  * @ingroup krb5_error
47  */
48 
49 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_clear_error_message(krb5_context context)50 krb5_clear_error_message(krb5_context context)
51 {
52     HEIMDAL_MUTEX_lock(&context->mutex);
53     if (context->error_string)
54 	free(context->error_string);
55     context->error_code = 0;
56     context->error_string = NULL;
57     HEIMDAL_MUTEX_unlock(&context->mutex);
58 }
59 
60 /**
61  * Set the context full error string for a specific error code.
62  * The error that is stored should be internationalized.
63  *
64  * The if context is NULL, no error string is stored.
65  *
66  * @param context Kerberos 5 context
67  * @param ret The error code
68  * @param fmt Error string for the error code
69  * @param ... printf(3) style parameters.
70  *
71  * @ingroup krb5_error
72  */
73 
74 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_set_error_message(krb5_context context,krb5_error_code ret,const char * fmt,...)75 krb5_set_error_message(krb5_context context, krb5_error_code ret,
76 		       const char *fmt, ...)
77     __attribute__ ((__format__ (__printf__, 3, 4)))
78 {
79     va_list ap;
80 
81     va_start(ap, fmt);
82     krb5_vset_error_message (context, ret, fmt, ap);
83     va_end(ap);
84 }
85 
86 /**
87  * Set the context full error string for a specific error code.
88  *
89  * The if context is NULL, no error string is stored.
90  *
91  * @param context Kerberos 5 context
92  * @param ret The error code
93  * @param fmt Error string for the error code
94  * @param args printf(3) style parameters.
95  *
96  * @ingroup krb5_error
97  */
98 
99 
100 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_vset_error_message(krb5_context context,krb5_error_code ret,const char * fmt,va_list args)101 krb5_vset_error_message (krb5_context context, krb5_error_code ret,
102 			 const char *fmt, va_list args)
103     __attribute__ ((__format__ (__printf__, 3, 0)))
104 {
105     int r;
106 
107     if (context == NULL)
108 	return;
109 
110     HEIMDAL_MUTEX_lock(&context->mutex);
111     if (context->error_string) {
112 	free(context->error_string);
113 	context->error_string = NULL;
114     }
115     context->error_code = ret;
116     r = vasprintf(&context->error_string, fmt, args);
117     if (r < 0)
118 	context->error_string = NULL;
119     HEIMDAL_MUTEX_unlock(&context->mutex);
120     if (context->error_string)
121 	_krb5_debug(context, 100, "error message: %s: %d", context->error_string, ret);
122 }
123 
124 /**
125  * Prepend the context full error string for a specific error code.
126  * The error that is stored should be internationalized.
127  *
128  * The if context is NULL, no error string is stored.
129  *
130  * @param context Kerberos 5 context
131  * @param ret The error code
132  * @param fmt Error string for the error code
133  * @param ... printf(3) style parameters.
134  *
135  * @ingroup krb5_error
136  */
137 
138 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_prepend_error_message(krb5_context context,krb5_error_code ret,const char * fmt,...)139 krb5_prepend_error_message(krb5_context context, krb5_error_code ret,
140 			   const char *fmt, ...)
141     __attribute__ ((__format__ (__printf__, 3, 4)))
142 {
143     va_list ap;
144 
145     va_start(ap, fmt);
146     krb5_vprepend_error_message(context, ret, fmt, ap);
147     va_end(ap);
148 }
149 
150 /**
151  * Prepend the contexts's full error string for a specific error code.
152  *
153  * The if context is NULL, no error string is stored.
154  *
155  * @param context Kerberos 5 context
156  * @param ret The error code
157  * @param fmt Error string for the error code
158  * @param args printf(3) style parameters.
159  *
160  * @ingroup krb5_error
161  */
162 
163 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_vprepend_error_message(krb5_context context,krb5_error_code ret,const char * fmt,va_list args)164 krb5_vprepend_error_message(krb5_context context, krb5_error_code ret,
165 			    const char *fmt, va_list args)
166     __attribute__ ((__format__ (__printf__, 3, 0)))
167 {
168     char *str = NULL, *str2 = NULL;
169 
170     if (context == NULL)
171 	return;
172 
173     HEIMDAL_MUTEX_lock(&context->mutex);
174     if (context->error_code != ret) {
175 	HEIMDAL_MUTEX_unlock(&context->mutex);
176 	return;
177     }
178     if (vasprintf(&str, fmt, args) < 0 || str == NULL) {
179 	HEIMDAL_MUTEX_unlock(&context->mutex);
180 	return;
181     }
182     if (context->error_string) {
183 	int e;
184 
185 	e = asprintf(&str2, "%s: %s", str, context->error_string);
186 	free(context->error_string);
187 	if (e < 0 || str2 == NULL)
188 	    context->error_string = NULL;
189 	else
190 	    context->error_string = str2;
191 	free(str);
192     } else
193 	context->error_string = str;
194     HEIMDAL_MUTEX_unlock(&context->mutex);
195 }
196 
197 /**
198  * Return the error message for `code' in context. On memory
199  * allocation error the function returns NULL.
200  *
201  * @param context Kerberos 5 context
202  * @param code Error code related to the error
203  *
204  * @return an error string, needs to be freed with
205  * krb5_free_error_message(). The functions return NULL on error.
206  *
207  * @ingroup krb5_error
208  */
209 
210 KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL
krb5_get_error_message(krb5_context context,krb5_error_code code)211 krb5_get_error_message(krb5_context context, krb5_error_code code)
212 {
213     char *str = NULL;
214     const char *cstr = NULL;
215     char buf[128];
216     int free_context = 0;
217 
218     if (code == 0)
219 	return strdup("Success");
220 
221     /*
222      * The MIT version of this function ignores the krb5_context
223      * and several widely deployed applications call krb5_get_error_message()
224      * with a NULL context in order to translate an error code as a
225      * replacement for error_message().  Another reason a NULL context
226      * might be provided is if the krb5_init_context() call itself
227      * failed.
228      */
229     if (context)
230     {
231 	HEIMDAL_MUTEX_lock(&context->mutex);
232         if (context->error_string &&
233             (code == context->error_code || context->error_code == 0))
234         {
235             str = strdup(context->error_string);
236         }
237 	HEIMDAL_MUTEX_unlock(&context->mutex);
238 
239         if (str)
240             return str;
241     }
242     else
243     {
244         if (krb5_init_context(&context) == 0)
245             free_context = 1;
246     }
247 
248     if (context)
249         cstr = com_right_r(context->et_list, code, buf, sizeof(buf));
250 
251     if (free_context)
252         krb5_free_context(context);
253 
254     if (cstr)
255         return strdup(cstr);
256 
257     cstr = error_message(code);
258     if (cstr)
259         return strdup(cstr);
260 
261     if (asprintf(&str, "<unknown error: %d>", (int)code) == -1 || str == NULL)
262 	return NULL;
263 
264     return str;
265 }
266 
267 
268 /**
269  * Free the error message returned by krb5_get_error_message().
270  *
271  * @param context Kerberos context
272  * @param msg error message to free, returned byg
273  *        krb5_get_error_message().
274  *
275  * @ingroup krb5_error
276  */
277 
278 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_free_error_message(krb5_context context,const char * msg)279 krb5_free_error_message(krb5_context context, const char *msg)
280 {
281     free(rk_UNCONST(msg));
282 }
283 
284 
285 /**
286  * Return the error string for the error code. The caller must not
287  * free the string.
288  *
289  * This function is deprecated since its not threadsafe.
290  *
291  * @param context Kerberos 5 context.
292  * @param code Kerberos error code.
293  *
294  * @return the error message matching code
295  *
296  * @ingroup krb5
297  */
298 
299 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
krb5_get_err_text(krb5_context context,krb5_error_code code)300 krb5_get_err_text(krb5_context context, krb5_error_code code)
301     KRB5_DEPRECATED_FUNCTION("Use krb5_get_error_message instead")
302 {
303     const char *p = NULL;
304     if(context != NULL)
305 	p = com_right(context->et_list, code);
306     if(p == NULL)
307 	p = strerror(code);
308     if (p == NULL)
309 	p = "Unknown error";
310     return p;
311 }
312 
313