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