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