xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/krb5/error_string.c (revision 241bea01a19bbb306af27777a870b86d41cb3fda)
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