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