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