1/*
2 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "krb5_locl.h"
35#include <err.h>
36
37#undef HEIMDAL_PRINTF_ATTRIBUTE
38#define HEIMDAL_PRINTF_ATTRIBUTE(x)
39#undef HEIMDAL_NORETURN_ATTRIBUTE
40#define HEIMDAL_NORETURN_ATTRIBUTE
41
42static krb5_error_code _warnerr(krb5_context context, int do_errtext,
43	 krb5_error_code code, int level,
44	 void (*logfunc)(const char *fmt, ...) __attribute__((__format__(__printf__, 1, 2))),
45	 const char *fmt, va_list ap)
46	__attribute__((__format__(__printf__, 6, 0)));
47
48static krb5_error_code
49_warnerr(krb5_context context, int do_errtext,
50	 krb5_error_code code, int level,
51	 void (*logfunc)(const char *fmt, ...),
52	 const char *fmt, va_list ap)
53{
54    char xfmt[7] = "";
55    const char *args[2], **arg;
56    char *msg = NULL;
57    const char *err_str = NULL;
58    krb5_error_code ret;
59
60    args[0] = args[1] = NULL;
61    arg = args;
62    if(fmt){
63	strlcat(xfmt, "%s", sizeof(xfmt));
64	if(do_errtext)
65	    strlcat(xfmt, ": ", sizeof(xfmt));
66	ret = vasprintf(&msg, fmt, ap);
67	if(ret < 0 || msg == NULL)
68	    return ENOMEM;
69	*arg++ = msg;
70    }
71    if(context && do_errtext){
72	strlcat(xfmt, "%s", sizeof(xfmt));
73
74	err_str = krb5_get_error_message(context, code);
75	if (err_str != NULL) {
76	    *arg = err_str;
77	} else {
78	    *arg= "<unknown error>";
79	}
80    }
81
82#ifdef __clang__
83#pragma clang diagnostic push
84#pragma clang diagnostic ignored "-Wformat-nonliteral"
85#endif
86
87    if (logfunc)
88	logfunc(xfmt, args[0], args[1]);
89    else if(context && context->warn_dest)
90	krb5_log(context, context->warn_dest, level, xfmt, args[0], args[1]);
91    else
92	warnx(xfmt, args[0], args[1]);
93
94#ifdef __clang__
95#pragma clang diagnostic pop
96#endif
97
98    free(msg);
99    krb5_free_error_message(context, err_str);
100    return 0;
101}
102
103#define FUNC(ETEXT, CODE, LEVEL)					\
104    krb5_error_code ret;						\
105    va_list ap;								\
106    va_start(ap, fmt);							\
107    ret = _warnerr(context, ETEXT, CODE, LEVEL, NULL, fmt, ap); 	\
108    va_end(ap);
109
110/**
111 * Log a warning to the log, default stderr, include the error from
112 * the last failure.
113 *
114 * @param context A Kerberos 5 context.
115 * @param code error code of the last error
116 * @param fmt message to print
117 * @param ap arguments
118 *
119 * @ingroup krb5_error
120 */
121
122KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
123krb5_vwarn(krb5_context context, krb5_error_code code,
124	   const char *fmt, va_list ap)
125    HEIMDAL_PRINTF_ATTRIBUTE((printf, 3, 0))
126{
127    return _warnerr(context, 1, code, 1, NULL, fmt, ap);
128}
129
130/**
131 * Log a warning to the log, default stderr, include the error from
132 * the last failure.
133 *
134 * @param context A Kerberos 5 context.
135 * @param code error code of the last error
136 * @param fmt message to print
137 *
138 * @ingroup krb5_error
139 */
140
141KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
142krb5_warn(krb5_context context, krb5_error_code code, const char *fmt, ...)
143    HEIMDAL_PRINTF_ATTRIBUTE((printf, 3, 4))
144{
145    FUNC(1, code, 1);
146    return ret;
147}
148
149/**
150 * Log a warning to the log, default stderr.
151 *
152 * @param context A Kerberos 5 context.
153 * @param fmt message to print
154 * @param ap arguments
155 *
156 * @ingroup krb5_error
157 */
158
159KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
160krb5_vwarnx(krb5_context context, const char *fmt, va_list ap)
161    HEIMDAL_PRINTF_ATTRIBUTE((printf, 2, 0))
162{
163    return _warnerr(context, 0, 0, 1, NULL, fmt, ap);
164}
165
166/**
167 * Log a warning to the log, default stderr.
168 *
169 * @param context A Kerberos 5 context.
170 * @param fmt message to print
171 *
172 * @ingroup krb5_error
173 */
174
175KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
176krb5_warnx(krb5_context context, const char *fmt, ...)
177    HEIMDAL_PRINTF_ATTRIBUTE((printf, 2, 3))
178{
179    FUNC(0, 0, 1);
180    return ret;
181}
182
183/**
184 * Log a warning to the log, default stderr, include bthe error from
185 * the last failure and then exit.
186 *
187 * @param context A Kerberos 5 context
188 * @param eval the exit code to exit with
189 * @param code error code of the last error
190 * @param fmt message to print
191 * @param ap arguments
192 *
193 * @ingroup krb5_error
194 */
195
196KRB5_LIB_FUNCTION void KRB5_LIB_CALL
197krb5_verr(krb5_context context, int eval, krb5_error_code code,
198	  const char *fmt, va_list ap)
199    HEIMDAL_PRINTF_ATTRIBUTE((printf, 4, 0))
200    HEIMDAL_NORETURN_ATTRIBUTE
201{
202    _warnerr(context, 1, code, 0, NULL, fmt, ap);
203    exit(eval);
204    UNREACHABLE(return 0);
205}
206
207/**
208 * Log a warning to the log, default stderr, include bthe error from
209 * the last failure and then exit.
210 *
211 * @param context A Kerberos 5 context
212 * @param eval the exit code to exit with
213 * @param code error code of the last error
214 * @param fmt message to print
215 *
216 * @ingroup krb5_error
217 */
218
219KRB5_LIB_FUNCTION void KRB5_LIB_CALL
220krb5_err(krb5_context context, int eval, krb5_error_code code,
221	 const char *fmt, ...)
222    HEIMDAL_PRINTF_ATTRIBUTE((printf, 4, 5))
223    HEIMDAL_NORETURN_ATTRIBUTE
224{
225    FUNC(1, code, 0);
226    exit(eval);
227    UNREACHABLE(return 0);
228}
229
230/**
231 * Log a warning to the log, default stderr, and then exit.
232 *
233 * @param context A Kerberos 5 context
234 * @param eval the exit code to exit with
235 * @param fmt message to print
236 * @param ap arguments
237 *
238 * @ingroup krb5_error
239 */
240
241KRB5_LIB_FUNCTION void KRB5_LIB_CALL
242krb5_verrx(krb5_context context, int eval, const char *fmt, va_list ap)
243    HEIMDAL_PRINTF_ATTRIBUTE((printf, 3, 0))
244    HEIMDAL_NORETURN_ATTRIBUTE
245{
246    _warnerr(context, 0, 0, 0, NULL, fmt, ap);
247    exit(eval);
248    UNREACHABLE(return 0);
249}
250
251/**
252 * Log a warning to the log, default stderr, and then exit.
253 *
254 * @param context A Kerberos 5 context
255 * @param eval the exit code to exit with
256 * @param fmt message to print
257 *
258 * @ingroup krb5_error
259 */
260
261KRB5_LIB_FUNCTION void KRB5_LIB_CALL
262krb5_errx(krb5_context context, int eval, const char *fmt, ...)
263    HEIMDAL_PRINTF_ATTRIBUTE((printf, 3, 4))
264    HEIMDAL_NORETURN_ATTRIBUTE
265{
266    FUNC(0, 0, 0);
267    exit(eval);
268    UNREACHABLE(return 0);
269}
270
271/**
272 * Log a warning to the log, default stderr, include bthe error from
273 * the last failure and then abort.
274 *
275 * @param context A Kerberos 5 context
276 * @param code error code of the last error
277 * @param fmt message to print
278 * @param ap arguments
279 *
280 * @ingroup krb5_error
281 */
282
283KRB5_LIB_FUNCTION void KRB5_LIB_CALL
284krb5_vabort(krb5_context context, krb5_error_code code,
285	    const char *fmt, va_list ap)
286    HEIMDAL_PRINTF_ATTRIBUTE((printf, 3, 0))
287    HEIMDAL_NORETURN_ATTRIBUTE
288{
289    _warnerr(context, 1, code, 0, NULL, fmt, ap);
290    abort();
291    UNREACHABLE(return 0);
292}
293
294/**
295 * Log a warning to the log, default stderr, include the error from
296 * the last failure and then abort.
297 *
298 * @param context A Kerberos 5 context
299 * @param code error code of the last error
300 * @param fmt message to print
301 *
302 * @ingroup krb5_error
303 */
304
305KRB5_LIB_FUNCTION void KRB5_LIB_CALL
306krb5_abort(krb5_context context, krb5_error_code code, const char *fmt, ...)
307    HEIMDAL_PRINTF_ATTRIBUTE((printf, 3, 4))
308    HEIMDAL_NORETURN_ATTRIBUTE
309{
310    va_list ap;
311    va_start(ap, fmt);
312    _warnerr(context, 1, code, 0, heim_abort, fmt, ap);
313    va_end(ap);
314    abort();
315    UNREACHABLE(return 0);
316}
317
318KRB5_LIB_FUNCTION void KRB5_LIB_CALL
319krb5_vabortx(krb5_context context, const char *fmt, va_list ap)
320    HEIMDAL_PRINTF_ATTRIBUTE((printf, 2, 0))
321    HEIMDAL_NORETURN_ATTRIBUTE
322{
323    _warnerr(context, 0, 0, 0, heim_abort, fmt, ap);
324    abort();
325    UNREACHABLE(return 0);
326}
327
328/**
329 * Log a warning to the log, default stderr, and then abort.
330 *
331 * @param context A Kerberos 5 context
332 * @param fmt message to print
333 *
334 * @ingroup krb5_error
335 */
336
337KRB5_LIB_FUNCTION void KRB5_LIB_CALL
338krb5_abortx(krb5_context context, const char *fmt, ...)
339    HEIMDAL_PRINTF_ATTRIBUTE((printf, 2, 3))
340    HEIMDAL_NORETURN_ATTRIBUTE
341{
342    FUNC(0, 0, 0);
343    abort();
344    UNREACHABLE(return 0);
345}
346
347/**
348 * Set the default logging facility.
349 *
350 * @param context A Kerberos 5 context
351 * @param fac Facility to use for logging.
352 *
353 * @ingroup krb5_error
354 */
355
356KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
357krb5_set_warn_dest(krb5_context context, krb5_log_facility *fac)
358{
359    if (context->warn_dest)
360	krb5_closelog(context, context->warn_dest);
361    context->warn_dest = fac;
362    return 0;
363}
364
365/**
366 * Get the default logging facility.
367 *
368 * @param context A Kerberos 5 context
369 *
370 * @ingroup krb5_error
371 */
372
373KRB5_LIB_FUNCTION krb5_log_facility * KRB5_LIB_CALL
374krb5_get_warn_dest(krb5_context context)
375{
376    return context->warn_dest;
377}
378
379/**
380 * Set the default debug logging facility.
381 *
382 * @param context A Kerberos 5 context
383 * @param fac Facility to use for logging.
384 *
385 * @ingroup krb5_error
386 */
387
388KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
389krb5_set_debug_dest(krb5_context context, krb5_log_facility *fac)
390{
391    if (context->debug_dest)
392	krb5_closelog(context, context->debug_dest);
393    context->debug_dest = fac;
394    return 0;
395}
396
397/**
398 * Get the default debug logging facility.
399 *
400 * @param context A Kerberos 5 context
401 *
402 * @ingroup krb5_error
403 */
404
405KRB5_LIB_FUNCTION krb5_log_facility * KRB5_LIB_CALL
406krb5_get_debug_dest(krb5_context context)
407{
408    return context->debug_dest;
409}
410