155682Smarkm/*
2233294Sstas * Copyright (c) 1997-2006 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
755682Smarkm *
8233294Sstas * Redistribution and use in source and binary forms, with or without
9233294Sstas * modification, are permitted provided that the following conditions
10233294Sstas * are met:
1155682Smarkm *
12233294Sstas * 1. Redistributions of source code must retain the above copyright
13233294Sstas *    notice, this list of conditions and the following disclaimer.
1455682Smarkm *
15233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
16233294Sstas *    notice, this list of conditions and the following disclaimer in the
17233294Sstas *    documentation and/or other materials provided with the distribution.
1855682Smarkm *
19233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
20233294Sstas *    may be used to endorse or promote products derived from this software
21233294Sstas *    without specific prior written permission.
22233294Sstas *
23233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33233294Sstas * SUCH DAMAGE.
3455682Smarkm */
3555682Smarkm
3655682Smarkm#include "krb5_locl.h"
37233294Sstas#include <vis.h>
3855682Smarkm
3955682Smarkmstruct facility {
4055682Smarkm    int min;
4155682Smarkm    int max;
42178825Sdfr    krb5_log_log_func_t log_func;
43178825Sdfr    krb5_log_close_func_t close_func;
4455682Smarkm    void *data;
4555682Smarkm};
4655682Smarkm
4755682Smarkmstatic struct facility*
4855682Smarkmlog_realloc(krb5_log_facility *f)
4955682Smarkm{
5055682Smarkm    struct facility *fp;
51178825Sdfr    fp = realloc(f->val, (f->len + 1) * sizeof(*f->val));
5255682Smarkm    if(fp == NULL)
5355682Smarkm	return NULL;
54178825Sdfr    f->len++;
5555682Smarkm    f->val = fp;
5655682Smarkm    fp += f->len - 1;
5755682Smarkm    return fp;
5855682Smarkm}
5955682Smarkm
6072445Sassarstruct s2i {
61102644Snectar    const char *s;
6255682Smarkm    int val;
6355682Smarkm};
6455682Smarkm
6555682Smarkm#define L(X) { #X, LOG_ ## X }
6655682Smarkm
6772445Sassarstatic struct s2i syslogvals[] = {
6855682Smarkm    L(EMERG),
6955682Smarkm    L(ALERT),
7055682Smarkm    L(CRIT),
7155682Smarkm    L(ERR),
7255682Smarkm    L(WARNING),
7355682Smarkm    L(NOTICE),
7455682Smarkm    L(INFO),
7555682Smarkm    L(DEBUG),
7655682Smarkm
7755682Smarkm    L(AUTH),
7855682Smarkm#ifdef LOG_AUTHPRIV
7955682Smarkm    L(AUTHPRIV),
8055682Smarkm#endif
8155682Smarkm#ifdef LOG_CRON
8255682Smarkm    L(CRON),
8355682Smarkm#endif
8455682Smarkm    L(DAEMON),
8555682Smarkm#ifdef LOG_FTP
8655682Smarkm    L(FTP),
8755682Smarkm#endif
8855682Smarkm    L(KERN),
8955682Smarkm    L(LPR),
9055682Smarkm    L(MAIL),
9155682Smarkm#ifdef LOG_NEWS
9255682Smarkm    L(NEWS),
9355682Smarkm#endif
9455682Smarkm    L(SYSLOG),
9555682Smarkm    L(USER),
9655682Smarkm#ifdef LOG_UUCP
9755682Smarkm    L(UUCP),
9855682Smarkm#endif
9955682Smarkm    L(LOCAL0),
10055682Smarkm    L(LOCAL1),
10155682Smarkm    L(LOCAL2),
10255682Smarkm    L(LOCAL3),
10355682Smarkm    L(LOCAL4),
10455682Smarkm    L(LOCAL5),
10555682Smarkm    L(LOCAL6),
10655682Smarkm    L(LOCAL7),
10755682Smarkm    { NULL, -1 }
10855682Smarkm};
10955682Smarkm
11055682Smarkmstatic int
11155682Smarkmfind_value(const char *s, struct s2i *table)
11255682Smarkm{
11355682Smarkm    while(table->s && strcasecmp(table->s, s))
11455682Smarkm	table++;
11555682Smarkm    return table->val;
11655682Smarkm}
11755682Smarkm
118233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
11955682Smarkmkrb5_initlog(krb5_context context,
12055682Smarkm	     const char *program,
12155682Smarkm	     krb5_log_facility **fac)
12255682Smarkm{
12355682Smarkm    krb5_log_facility *f = calloc(1, sizeof(*f));
12478527Sassar    if(f == NULL) {
125233294Sstas	krb5_set_error_message(context, ENOMEM,
126233294Sstas			       N_("malloc: out of memory", ""));
12755682Smarkm	return ENOMEM;
12878527Sassar    }
12955682Smarkm    f->program = strdup(program);
13055682Smarkm    if(f->program == NULL){
13155682Smarkm	free(f);
132233294Sstas	krb5_set_error_message(context, ENOMEM,
133233294Sstas			       N_("malloc: out of memory", ""));
13455682Smarkm	return ENOMEM;
13555682Smarkm    }
13655682Smarkm    *fac = f;
13755682Smarkm    return 0;
13855682Smarkm}
13955682Smarkm
140233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
14155682Smarkmkrb5_addlog_func(krb5_context context,
14255682Smarkm		 krb5_log_facility *fac,
14355682Smarkm		 int min,
14455682Smarkm		 int max,
145178825Sdfr		 krb5_log_log_func_t log_func,
146178825Sdfr		 krb5_log_close_func_t close_func,
14755682Smarkm		 void *data)
14855682Smarkm{
14955682Smarkm    struct facility *fp = log_realloc(fac);
15078527Sassar    if(fp == NULL) {
151233294Sstas	krb5_set_error_message(context, ENOMEM,
152233294Sstas			       N_("malloc: out of memory", ""));
15355682Smarkm	return ENOMEM;
15478527Sassar    }
15555682Smarkm    fp->min = min;
15655682Smarkm    fp->max = max;
157178825Sdfr    fp->log_func = log_func;
158178825Sdfr    fp->close_func = close_func;
15955682Smarkm    fp->data = data;
16055682Smarkm    return 0;
16155682Smarkm}
16255682Smarkm
16355682Smarkm
164102644Snectarstruct _heimdal_syslog_data{
16555682Smarkm    int priority;
16655682Smarkm};
16755682Smarkm
168233294Sstasstatic void KRB5_CALLCONV
169178825Sdfrlog_syslog(const char *timestr,
17055682Smarkm	   const char *msg,
17155682Smarkm	   void *data)
172233294Sstas
17355682Smarkm{
174102644Snectar    struct _heimdal_syslog_data *s = data;
17555682Smarkm    syslog(s->priority, "%s", msg);
17655682Smarkm}
17755682Smarkm
178233294Sstasstatic void KRB5_CALLCONV
17955682Smarkmclose_syslog(void *data)
18055682Smarkm{
18155682Smarkm    free(data);
18255682Smarkm    closelog();
18355682Smarkm}
18455682Smarkm
18555682Smarkmstatic krb5_error_code
18655682Smarkmopen_syslog(krb5_context context,
18755682Smarkm	    krb5_log_facility *facility, int min, int max,
18855682Smarkm	    const char *sev, const char *fac)
18955682Smarkm{
190102644Snectar    struct _heimdal_syslog_data *sd = malloc(sizeof(*sd));
19155682Smarkm    int i;
19255682Smarkm
19378527Sassar    if(sd == NULL) {
194233294Sstas	krb5_set_error_message(context, ENOMEM,
195233294Sstas			       N_("malloc: out of memory", ""));
19655682Smarkm	return ENOMEM;
19778527Sassar    }
19855682Smarkm    i = find_value(sev, syslogvals);
19955682Smarkm    if(i == -1)
20055682Smarkm	i = LOG_ERR;
20155682Smarkm    sd->priority = i;
20255682Smarkm    i = find_value(fac, syslogvals);
20355682Smarkm    if(i == -1)
20455682Smarkm	i = LOG_AUTH;
20555682Smarkm    sd->priority |= i;
20655682Smarkm    roken_openlog(facility->program, LOG_PID | LOG_NDELAY, i);
20755682Smarkm    return krb5_addlog_func(context, facility, min, max,
20855682Smarkm			    log_syslog, close_syslog, sd);
20955682Smarkm}
21055682Smarkm
21155682Smarkmstruct file_data{
212102644Snectar    const char *filename;
213102644Snectar    const char *mode;
21455682Smarkm    FILE *fd;
21555682Smarkm    int keep_open;
21655682Smarkm};
21755682Smarkm
218233294Sstasstatic void KRB5_CALLCONV
219178825Sdfrlog_file(const char *timestr,
22055682Smarkm	 const char *msg,
22155682Smarkm	 void *data)
22255682Smarkm{
22355682Smarkm    struct file_data *f = data;
224233294Sstas    char *msgclean;
225233294Sstas    size_t len = strlen(msg);
22655682Smarkm    if(f->keep_open == 0)
22755682Smarkm	f->fd = fopen(f->filename, f->mode);
22855682Smarkm    if(f->fd == NULL)
22955682Smarkm	return;
230233294Sstas    /* make sure the log doesn't contain special chars */
231233294Sstas    msgclean = malloc((len + 1) * 4);
232233294Sstas    if (msgclean == NULL)
233233294Sstas	goto out;
234233294Sstas    strvisx(msgclean, rk_UNCONST(msg), len, VIS_OCTAL);
235233294Sstas    fprintf(f->fd, "%s %s\n", timestr, msgclean);
236233294Sstas    free(msgclean);
237233294Sstas out:
238178825Sdfr    if(f->keep_open == 0) {
23955682Smarkm	fclose(f->fd);
240178825Sdfr	f->fd = NULL;
241178825Sdfr    }
24255682Smarkm}
24355682Smarkm
244233294Sstasstatic void KRB5_CALLCONV
24555682Smarkmclose_file(void *data)
24655682Smarkm{
24755682Smarkm    struct file_data *f = data;
24855682Smarkm    if(f->keep_open && f->filename)
24955682Smarkm	fclose(f->fd);
25055682Smarkm    free(data);
25155682Smarkm}
25255682Smarkm
25355682Smarkmstatic krb5_error_code
25455682Smarkmopen_file(krb5_context context, krb5_log_facility *fac, int min, int max,
255102644Snectar	  const char *filename, const char *mode, FILE *f, int keep_open)
25655682Smarkm{
25755682Smarkm    struct file_data *fd = malloc(sizeof(*fd));
25878527Sassar    if(fd == NULL) {
259233294Sstas	krb5_set_error_message(context, ENOMEM,
260233294Sstas			       N_("malloc: out of memory", ""));
26155682Smarkm	return ENOMEM;
26278527Sassar    }
26355682Smarkm    fd->filename = filename;
26455682Smarkm    fd->mode = mode;
26555682Smarkm    fd->fd = f;
26655682Smarkm    fd->keep_open = keep_open;
26755682Smarkm
26855682Smarkm    return krb5_addlog_func(context, fac, min, max, log_file, close_file, fd);
26955682Smarkm}
27055682Smarkm
27155682Smarkm
27255682Smarkm
273233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
27478527Sassarkrb5_addlog_dest(krb5_context context, krb5_log_facility *f, const char *orig)
27555682Smarkm{
27655682Smarkm    krb5_error_code ret = 0;
27755682Smarkm    int min = 0, max = -1, n;
27855682Smarkm    char c;
27978527Sassar    const char *p = orig;
28078527Sassar
28155682Smarkm    n = sscanf(p, "%d%c%d/", &min, &c, &max);
28255682Smarkm    if(n == 2){
28355682Smarkm	if(c == '/') {
28455682Smarkm	    if(min < 0){
28555682Smarkm		max = -min;
28655682Smarkm		min = 0;
28755682Smarkm	    }else{
28855682Smarkm		max = min;
28955682Smarkm	    }
29055682Smarkm	}
29155682Smarkm    }
29255682Smarkm    if(n){
29355682Smarkm	p = strchr(p, '/');
29478527Sassar	if(p == NULL) {
295233294Sstas	    krb5_set_error_message(context, HEIM_ERR_LOG_PARSE,
296233294Sstas				   N_("failed to parse \"%s\"", ""), orig);
29778527Sassar	    return HEIM_ERR_LOG_PARSE;
29878527Sassar	}
29955682Smarkm	p++;
30055682Smarkm    }
30155682Smarkm    if(strcmp(p, "STDERR") == 0){
30255682Smarkm	ret = open_file(context, f, min, max, NULL, NULL, stderr, 1);
30355682Smarkm    }else if(strcmp(p, "CONSOLE") == 0){
30455682Smarkm	ret = open_file(context, f, min, max, "/dev/console", "w", NULL, 0);
305178825Sdfr    }else if(strncmp(p, "FILE", 4) == 0 && (p[4] == ':' || p[4] == '=')){
30655682Smarkm	char *fn;
30755682Smarkm	FILE *file = NULL;
30855682Smarkm	int keep_open = 0;
30955682Smarkm	fn = strdup(p + 5);
31078527Sassar	if(fn == NULL) {
311233294Sstas	    krb5_set_error_message(context, ENOMEM,
312233294Sstas				   N_("malloc: out of memory", ""));
31355682Smarkm	    return ENOMEM;
31478527Sassar	}
31555682Smarkm	if(p[4] == '='){
316233294Sstas	    int i = open(fn, O_WRONLY | O_CREAT |
31755682Smarkm			 O_TRUNC | O_APPEND, 0666);
31878527Sassar	    if(i < 0) {
31978527Sassar		ret = errno;
320233294Sstas		krb5_set_error_message(context, ret,
321233294Sstas				       N_("open(%s) logile: %s", ""), fn,
32278527Sassar				       strerror(ret));
323178825Sdfr		free(fn);
32478527Sassar		return ret;
32578527Sassar	    }
326233294Sstas	    rk_cloexec(i);
32755682Smarkm	    file = fdopen(i, "a");
32855682Smarkm	    if(file == NULL){
32978527Sassar		ret = errno;
33055682Smarkm		close(i);
331233294Sstas		krb5_set_error_message(context, ret,
332233294Sstas				       N_("fdopen(%s) logfile: %s", ""),
333233294Sstas				       fn, strerror(ret));
334178825Sdfr		free(fn);
33578527Sassar		return ret;
33655682Smarkm	    }
33755682Smarkm	    keep_open = 1;
33855682Smarkm	}
33955682Smarkm	ret = open_file(context, f, min, max, fn, "a", file, keep_open);
340178825Sdfr    }else if(strncmp(p, "DEVICE", 6) == 0 && (p[6] == ':' || p[6] == '=')){
34155682Smarkm	ret = open_file(context, f, min, max, strdup(p + 7), "w", NULL, 0);
342102644Snectar    }else if(strncmp(p, "SYSLOG", 6) == 0 && (p[6] == '\0' || p[6] == ':')){
343102644Snectar	char severity[128] = "";
344102644Snectar	char facility[128] = "";
345102644Snectar	p += 6;
346102644Snectar	if(*p != '\0')
347102644Snectar	    p++;
348102644Snectar	if(strsep_copy(&p, ":", severity, sizeof(severity)) != -1)
349102644Snectar	    strsep_copy(&p, ":", facility, sizeof(facility));
350102644Snectar	if(*severity == '\0')
351102644Snectar	    strlcpy(severity, "ERR", sizeof(severity));
352102644Snectar 	if(*facility == '\0')
353102644Snectar	    strlcpy(facility, "AUTH", sizeof(facility));
35455682Smarkm	ret = open_syslog(context, f, min, max, severity, facility);
35555682Smarkm    }else{
35655682Smarkm	ret = HEIM_ERR_LOG_PARSE; /* XXX */
357233294Sstas	krb5_set_error_message (context, ret,
358233294Sstas				N_("unknown log type: %s", ""), p);
35955682Smarkm    }
36055682Smarkm    return ret;
36155682Smarkm}
36255682Smarkm
36355682Smarkm
364233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
36555682Smarkmkrb5_openlog(krb5_context context,
36655682Smarkm	     const char *program,
36755682Smarkm	     krb5_log_facility **fac)
36855682Smarkm{
36955682Smarkm    krb5_error_code ret;
37055682Smarkm    char **p, **q;
37155682Smarkm
37255682Smarkm    ret = krb5_initlog(context, program, fac);
37355682Smarkm    if(ret)
37455682Smarkm	return ret;
37555682Smarkm
37655682Smarkm    p = krb5_config_get_strings(context, NULL, "logging", program, NULL);
37755682Smarkm    if(p == NULL)
37855682Smarkm	p = krb5_config_get_strings(context, NULL, "logging", "default", NULL);
37955682Smarkm    if(p){
380233294Sstas	for(q = p; *q && ret == 0; q++)
38155682Smarkm	    ret = krb5_addlog_dest(context, *fac, *q);
38255682Smarkm	krb5_config_free_strings(p);
38355682Smarkm    }else
38455682Smarkm	ret = krb5_addlog_dest(context, *fac, "SYSLOG");
385233294Sstas    return ret;
38655682Smarkm}
38755682Smarkm
388233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
38955682Smarkmkrb5_closelog(krb5_context context,
39055682Smarkm	      krb5_log_facility *fac)
39155682Smarkm{
39255682Smarkm    int i;
39355682Smarkm    for(i = 0; i < fac->len; i++)
394178825Sdfr	(*fac->val[i].close_func)(fac->val[i].data);
395178825Sdfr    free(fac->val);
396178825Sdfr    free(fac->program);
397178825Sdfr    fac->val = NULL;
398178825Sdfr    fac->len = 0;
399178825Sdfr    fac->program = NULL;
400178825Sdfr    free(fac);
40155682Smarkm    return 0;
40255682Smarkm}
40355682Smarkm
40455682Smarkm#undef __attribute__
40555682Smarkm#define __attribute__(X)
40655682Smarkm
407233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
40855682Smarkmkrb5_vlog_msg(krb5_context context,
40955682Smarkm	      krb5_log_facility *fac,
41055682Smarkm	      char **reply,
41155682Smarkm	      int level,
41255682Smarkm	      const char *fmt,
41355682Smarkm	      va_list ap)
41455682Smarkm     __attribute__((format (printf, 5, 0)))
41555682Smarkm{
416233294Sstas
417103423Snectar    char *msg = NULL;
418103423Snectar    const char *actual = NULL;
41955682Smarkm    char buf[64];
420103423Snectar    time_t t = 0;
42155682Smarkm    int i;
42255682Smarkm
423103423Snectar    for(i = 0; fac && i < fac->len; i++)
424233294Sstas	if(fac->val[i].min <= level &&
425103423Snectar	   (fac->val[i].max < 0 || fac->val[i].max >= level)) {
426103423Snectar	    if(t == 0) {
427103423Snectar		t = time(NULL);
428103423Snectar		krb5_format_time(context, t, buf, sizeof(buf), TRUE);
429103423Snectar	    }
430103423Snectar	    if(actual == NULL) {
431233294Sstas		int ret = vasprintf(&msg, fmt, ap);
432233294Sstas		if(ret < 0 || msg == NULL)
433103423Snectar		    actual = fmt;
434103423Snectar		else
435103423Snectar		    actual = msg;
436103423Snectar	    }
437178825Sdfr	    (*fac->val[i].log_func)(buf, actual, fac->val[i].data);
438103423Snectar	}
439103423Snectar    if(reply == NULL)
440103423Snectar	free(msg);
441103423Snectar    else
442103423Snectar	*reply = msg;
44355682Smarkm    return 0;
44455682Smarkm}
44555682Smarkm
446233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
44755682Smarkmkrb5_vlog(krb5_context context,
44855682Smarkm	  krb5_log_facility *fac,
44955682Smarkm	  int level,
45055682Smarkm	  const char *fmt,
45155682Smarkm	  va_list ap)
45255682Smarkm     __attribute__((format (printf, 4, 0)))
45355682Smarkm{
454103423Snectar    return krb5_vlog_msg(context, fac, NULL, level, fmt, ap);
45555682Smarkm}
45655682Smarkm
457233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
45855682Smarkmkrb5_log_msg(krb5_context context,
45955682Smarkm	     krb5_log_facility *fac,
46055682Smarkm	     int level,
46155682Smarkm	     char **reply,
46255682Smarkm	     const char *fmt,
46355682Smarkm	     ...)
46455682Smarkm     __attribute__((format (printf, 5, 6)))
46555682Smarkm{
46655682Smarkm    va_list ap;
46755682Smarkm    krb5_error_code ret;
46855682Smarkm
46955682Smarkm    va_start(ap, fmt);
47055682Smarkm    ret = krb5_vlog_msg(context, fac, reply, level, fmt, ap);
47155682Smarkm    va_end(ap);
47255682Smarkm    return ret;
47355682Smarkm}
47455682Smarkm
47555682Smarkm
476233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
47755682Smarkmkrb5_log(krb5_context context,
47855682Smarkm	 krb5_log_facility *fac,
47955682Smarkm	 int level,
48055682Smarkm	 const char *fmt,
48155682Smarkm	 ...)
48255682Smarkm     __attribute__((format (printf, 4, 5)))
48355682Smarkm{
48455682Smarkm    va_list ap;
48555682Smarkm    krb5_error_code ret;
48655682Smarkm
48755682Smarkm    va_start(ap, fmt);
48855682Smarkm    ret = krb5_vlog(context, fac, level, fmt, ap);
48955682Smarkm    va_end(ap);
49055682Smarkm    return ret;
49155682Smarkm}
49255682Smarkm
493233294Sstasvoid KRB5_LIB_FUNCTION
494233294Sstas_krb5_debug(krb5_context context,
495233294Sstas	    int level,
496233294Sstas	    const char *fmt,
497233294Sstas	    ...)
498233294Sstas    __attribute__((format (printf, 3, 4)))
499233294Sstas{
500233294Sstas    va_list ap;
501233294Sstas
502233294Sstas    if (context == NULL || context->debug_dest == NULL)
503233294Sstas	return;
504233294Sstas
505233294Sstas    va_start(ap, fmt);
506233294Sstas    krb5_vlog(context, context->debug_dest, level, fmt, ap);
507233294Sstas    va_end(ap);
508233294Sstas}
509233294Sstas
510233294Sstaskrb5_boolean KRB5_LIB_FUNCTION
511233294Sstas_krb5_have_debug(krb5_context context, int level)
512233294Sstas{
513233294Sstas    if (context == NULL || context->debug_dest == NULL)
514233294Sstas	return 0 ;
515233294Sstas    return 1;
516233294Sstas}
517