1 /*	$NetBSD: error_string.c,v 1.1.1.2 2014/04/24 12:45:49 pettai 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 }
121 
122 /**
123  * Prepend the context full error string for a specific error code.
124  * The error that is stored should be internationalized.
125  *
126  * The if context is NULL, no error string is stored.
127  *
128  * @param context Kerberos 5 context
129  * @param ret The error code
130  * @param fmt Error string for the error code
131  * @param ... printf(3) style parameters.
132  *
133  * @ingroup krb5_error
134  */
135 
136 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_prepend_error_message(krb5_context context,krb5_error_code ret,const char * fmt,...)137 krb5_prepend_error_message(krb5_context context, krb5_error_code ret,
138 			   const char *fmt, ...)
139     __attribute__ ((format (printf, 3, 4)))
140 {
141     va_list ap;
142 
143     va_start(ap, fmt);
144     krb5_vprepend_error_message(context, ret, fmt, ap);
145     va_end(ap);
146 }
147 
148 /**
149  * Prepend the contexts's full error string for a specific error code.
150  *
151  * The if context is NULL, no error string is stored.
152  *
153  * @param context Kerberos 5 context
154  * @param ret The error code
155  * @param fmt Error string for the error code
156  * @param args printf(3) style parameters.
157  *
158  * @ingroup krb5_error
159  */
160 
161 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_vprepend_error_message(krb5_context context,krb5_error_code ret,const char * fmt,va_list args)162 krb5_vprepend_error_message(krb5_context context, krb5_error_code ret,
163 			    const char *fmt, va_list args)
164     __attribute__ ((format (printf, 3, 0)))
165 {
166     char *str = NULL, *str2 = NULL;
167 
168     if (context == NULL)
169 	return;
170 
171     HEIMDAL_MUTEX_lock(context->mutex);
172     if (context->error_code != ret) {
173 	HEIMDAL_MUTEX_unlock(context->mutex);
174 	return;
175     }
176     if (vasprintf(&str, fmt, args) < 0 || str == NULL) {
177 	HEIMDAL_MUTEX_unlock(context->mutex);
178 	return;
179     }
180     if (context->error_string) {
181 	int e;
182 
183 	e = asprintf(&str2, "%s: %s", str, context->error_string);
184 	free(context->error_string);
185 	if (e < 0 || str2 == NULL)
186 	    context->error_string = NULL;
187 	else
188 	    context->error_string = str2;
189 	free(str);
190     } else
191 	context->error_string = str;
192     HEIMDAL_MUTEX_unlock(context->mutex);
193 }
194 
195 
196 /**
197  * Return the error message in context. On error or no error string,
198  * the function returns NULL.
199  *
200  * @param context Kerberos 5 context
201  *
202  * @return an error string, needs to be freed with
203  * krb5_free_error_message(). The functions return NULL on error.
204  *
205  * @ingroup krb5_error
206  */
207 
208 KRB5_LIB_FUNCTION char * KRB5_LIB_CALL
krb5_get_error_string(krb5_context context)209 krb5_get_error_string(krb5_context context)
210 {
211     char *ret = NULL;
212 
213     HEIMDAL_MUTEX_lock(context->mutex);
214     if (context->error_string)
215 	ret = strdup(context->error_string);
216     HEIMDAL_MUTEX_unlock(context->mutex);
217     return ret;
218 }
219 
220 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_have_error_string(krb5_context context)221 krb5_have_error_string(krb5_context context)
222 {
223     char *str;
224     HEIMDAL_MUTEX_lock(context->mutex);
225     str = context->error_string;
226     HEIMDAL_MUTEX_unlock(context->mutex);
227     return str != NULL;
228 }
229 
230 /**
231  * Return the error message for `code' in context. On memory
232  * allocation error the function returns NULL.
233  *
234  * @param context Kerberos 5 context
235  * @param code Error code related to the error
236  *
237  * @return an error string, needs to be freed with
238  * krb5_free_error_message(). The functions return NULL on error.
239  *
240  * @ingroup krb5_error
241  */
242 
243 KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL
krb5_get_error_message(krb5_context context,krb5_error_code code)244 krb5_get_error_message(krb5_context context, krb5_error_code code)
245 {
246     char *str = NULL;
247     const char *cstr = NULL;
248     char buf[128];
249     int free_context = 0;
250 
251     if (code == 0)
252 	return strdup("Success");
253 
254     /*
255      * The MIT version of this function ignores the krb5_context
256      * and several widely deployed applications call krb5_get_error_message()
257      * with a NULL context in order to translate an error code as a
258      * replacement for error_message().  Another reason a NULL context
259      * might be provided is if the krb5_init_context() call itself
260      * failed.
261      */
262     if (context)
263     {
264         HEIMDAL_MUTEX_lock(context->mutex);
265         if (context->error_string &&
266             (code == context->error_code || context->error_code == 0))
267         {
268             str = strdup(context->error_string);
269         }
270         HEIMDAL_MUTEX_unlock(context->mutex);
271 
272         if (str)
273             return str;
274     }
275     else
276     {
277         if (krb5_init_context(&context) == 0)
278             free_context = 1;
279     }
280 
281     if (context)
282         cstr = com_right_r(context->et_list, code, buf, sizeof(buf));
283 
284     if (free_context)
285         krb5_free_context(context);
286 
287     if (cstr)
288         return strdup(cstr);
289 
290     cstr = error_message(code);
291     if (cstr)
292         return strdup(cstr);
293 
294     if (asprintf(&str, "<unknown error: %d>", (int)code) == -1 || str == NULL)
295 	return NULL;
296 
297     return str;
298 }
299 
300 
301 /**
302  * Free the error message returned by krb5_get_error_message().
303  *
304  * @param context Kerberos context
305  * @param msg error message to free, returned byg
306  *        krb5_get_error_message().
307  *
308  * @ingroup krb5_error
309  */
310 
311 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_free_error_message(krb5_context context,const char * msg)312 krb5_free_error_message(krb5_context context, const char *msg)
313 {
314     free(rk_UNCONST(msg));
315 }
316 
317 
318 /**
319  * Return the error string for the error code. The caller must not
320  * free the string.
321  *
322  * This function is deprecated since its not threadsafe.
323  *
324  * @param context Kerberos 5 context.
325  * @param code Kerberos error code.
326  *
327  * @return the error message matching code
328  *
329  * @ingroup krb5
330  */
331 
332 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
krb5_get_err_text(krb5_context context,krb5_error_code code)333 krb5_get_err_text(krb5_context context, krb5_error_code code)
334     KRB5_DEPRECATED_FUNCTION("Use X instead")
335 {
336     const char *p = NULL;
337     if(context != NULL)
338 	p = com_right(context->et_list, code);
339     if(p == NULL)
340 	p = strerror(code);
341     if (p == NULL)
342 	p = "Unknown error";
343     return p;
344 }
345