xref: /minix3/crypto/external/bsd/heimdal/dist/lib/krb5/error_string.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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