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