xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/krb5/log.c (revision 241bea01a19bbb306af27777a870b86d41cb3fda)
1*241bea01Schristos /*	$NetBSD: log.c,v 1.3 2019/12/15 22:50:50 christos Exp $	*/
2ca1c9b0cSelric 
3ca1c9b0cSelric /*
4ca1c9b0cSelric  * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
5ca1c9b0cSelric  * (Royal Institute of Technology, Stockholm, Sweden).
6ca1c9b0cSelric  * All rights reserved.
7ca1c9b0cSelric  *
8ca1c9b0cSelric  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
9ca1c9b0cSelric  *
10ca1c9b0cSelric  * Redistribution and use in source and binary forms, with or without
11ca1c9b0cSelric  * modification, are permitted provided that the following conditions
12ca1c9b0cSelric  * are met:
13ca1c9b0cSelric  *
14ca1c9b0cSelric  * 1. Redistributions of source code must retain the above copyright
15ca1c9b0cSelric  *    notice, this list of conditions and the following disclaimer.
16ca1c9b0cSelric  *
17ca1c9b0cSelric  * 2. Redistributions in binary form must reproduce the above copyright
18ca1c9b0cSelric  *    notice, this list of conditions and the following disclaimer in the
19ca1c9b0cSelric  *    documentation and/or other materials provided with the distribution.
20ca1c9b0cSelric  *
21ca1c9b0cSelric  * 3. Neither the name of the Institute nor the names of its contributors
22ca1c9b0cSelric  *    may be used to endorse or promote products derived from this software
23ca1c9b0cSelric  *    without specific prior written permission.
24ca1c9b0cSelric  *
25ca1c9b0cSelric  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26ca1c9b0cSelric  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27ca1c9b0cSelric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28ca1c9b0cSelric  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29ca1c9b0cSelric  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30ca1c9b0cSelric  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31ca1c9b0cSelric  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32ca1c9b0cSelric  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33ca1c9b0cSelric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34ca1c9b0cSelric  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35ca1c9b0cSelric  * SUCH DAMAGE.
36ca1c9b0cSelric  */
37ca1c9b0cSelric 
38ca1c9b0cSelric #include "krb5_locl.h"
39ca1c9b0cSelric #include <vis.h>
40ca1c9b0cSelric 
41ca1c9b0cSelric struct facility {
42ca1c9b0cSelric     int min;
43ca1c9b0cSelric     int max;
44ca1c9b0cSelric     krb5_log_log_func_t log_func;
45ca1c9b0cSelric     krb5_log_close_func_t close_func;
46ca1c9b0cSelric     void *data;
47ca1c9b0cSelric };
48ca1c9b0cSelric 
49ca1c9b0cSelric static struct facility*
log_realloc(krb5_log_facility * f)50ca1c9b0cSelric log_realloc(krb5_log_facility *f)
51ca1c9b0cSelric {
52ca1c9b0cSelric     struct facility *fp;
53ca1c9b0cSelric     fp = realloc(f->val, (f->len + 1) * sizeof(*f->val));
54ca1c9b0cSelric     if(fp == NULL)
55ca1c9b0cSelric 	return NULL;
56ca1c9b0cSelric     f->len++;
57ca1c9b0cSelric     f->val = fp;
58ca1c9b0cSelric     fp += f->len - 1;
59ca1c9b0cSelric     return fp;
60ca1c9b0cSelric }
61ca1c9b0cSelric 
62ca1c9b0cSelric struct s2i {
63ca1c9b0cSelric     const char *s;
64ca1c9b0cSelric     int val;
65ca1c9b0cSelric };
66ca1c9b0cSelric 
67ca1c9b0cSelric #define L(X) { #X, LOG_ ## X }
68ca1c9b0cSelric 
69ca1c9b0cSelric static struct s2i syslogvals[] = {
70ca1c9b0cSelric     L(EMERG),
71ca1c9b0cSelric     L(ALERT),
72ca1c9b0cSelric     L(CRIT),
73ca1c9b0cSelric     L(ERR),
74ca1c9b0cSelric     L(WARNING),
75ca1c9b0cSelric     L(NOTICE),
76ca1c9b0cSelric     L(INFO),
77ca1c9b0cSelric     L(DEBUG),
78ca1c9b0cSelric 
79ca1c9b0cSelric     L(AUTH),
80ca1c9b0cSelric #ifdef LOG_AUTHPRIV
81ca1c9b0cSelric     L(AUTHPRIV),
82ca1c9b0cSelric #endif
83ca1c9b0cSelric #ifdef LOG_CRON
84ca1c9b0cSelric     L(CRON),
85ca1c9b0cSelric #endif
86ca1c9b0cSelric     L(DAEMON),
87ca1c9b0cSelric #ifdef LOG_FTP
88ca1c9b0cSelric     L(FTP),
89ca1c9b0cSelric #endif
90ca1c9b0cSelric     L(KERN),
91ca1c9b0cSelric     L(LPR),
92ca1c9b0cSelric     L(MAIL),
93ca1c9b0cSelric #ifdef LOG_NEWS
94ca1c9b0cSelric     L(NEWS),
95ca1c9b0cSelric #endif
96ca1c9b0cSelric     L(SYSLOG),
97ca1c9b0cSelric     L(USER),
98ca1c9b0cSelric #ifdef LOG_UUCP
99ca1c9b0cSelric     L(UUCP),
100ca1c9b0cSelric #endif
101ca1c9b0cSelric     L(LOCAL0),
102ca1c9b0cSelric     L(LOCAL1),
103ca1c9b0cSelric     L(LOCAL2),
104ca1c9b0cSelric     L(LOCAL3),
105ca1c9b0cSelric     L(LOCAL4),
106ca1c9b0cSelric     L(LOCAL5),
107ca1c9b0cSelric     L(LOCAL6),
108ca1c9b0cSelric     L(LOCAL7),
109ca1c9b0cSelric     { NULL, -1 }
110ca1c9b0cSelric };
111ca1c9b0cSelric 
112ca1c9b0cSelric static int
find_value(const char * s,struct s2i * table)113ca1c9b0cSelric find_value(const char *s, struct s2i *table)
114ca1c9b0cSelric {
115ca1c9b0cSelric     while(table->s && strcasecmp(table->s, s))
116ca1c9b0cSelric 	table++;
117ca1c9b0cSelric     return table->val;
118ca1c9b0cSelric }
119ca1c9b0cSelric 
120ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_initlog(krb5_context context,const char * program,krb5_log_facility ** fac)121ca1c9b0cSelric krb5_initlog(krb5_context context,
122ca1c9b0cSelric 	     const char *program,
123ca1c9b0cSelric 	     krb5_log_facility **fac)
124ca1c9b0cSelric {
125ca1c9b0cSelric     krb5_log_facility *f = calloc(1, sizeof(*f));
126b9d004c6Schristos     if (f == NULL)
127b9d004c6Schristos 	return krb5_enomem(context);
128ca1c9b0cSelric     f->program = strdup(program);
129ca1c9b0cSelric     if(f->program == NULL){
130ca1c9b0cSelric 	free(f);
131b9d004c6Schristos 	return krb5_enomem(context);
132ca1c9b0cSelric     }
133ca1c9b0cSelric     *fac = f;
134ca1c9b0cSelric     return 0;
135ca1c9b0cSelric }
136ca1c9b0cSelric 
137ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_addlog_func(krb5_context context,krb5_log_facility * fac,int min,int max,krb5_log_log_func_t log_func,krb5_log_close_func_t close_func,void * data)138ca1c9b0cSelric krb5_addlog_func(krb5_context context,
139ca1c9b0cSelric 		 krb5_log_facility *fac,
140ca1c9b0cSelric 		 int min,
141ca1c9b0cSelric 		 int max,
142ca1c9b0cSelric 		 krb5_log_log_func_t log_func,
143ca1c9b0cSelric 		 krb5_log_close_func_t close_func,
144ca1c9b0cSelric 		 void *data)
145ca1c9b0cSelric {
146ca1c9b0cSelric     struct facility *fp = log_realloc(fac);
147b9d004c6Schristos     if (fp == NULL)
148b9d004c6Schristos 	return krb5_enomem(context);
149ca1c9b0cSelric     fp->min = min;
150ca1c9b0cSelric     fp->max = max;
151ca1c9b0cSelric     fp->log_func = log_func;
152ca1c9b0cSelric     fp->close_func = close_func;
153ca1c9b0cSelric     fp->data = data;
154ca1c9b0cSelric     return 0;
155ca1c9b0cSelric }
156ca1c9b0cSelric 
157ca1c9b0cSelric 
158ca1c9b0cSelric struct _heimdal_syslog_data{
159ca1c9b0cSelric     int priority;
160ca1c9b0cSelric };
161ca1c9b0cSelric 
162ca1c9b0cSelric static void KRB5_CALLCONV
log_syslog(const char * timestr,const char * msg,void * data)163ca1c9b0cSelric log_syslog(const char *timestr,
164ca1c9b0cSelric 	   const char *msg,
165ca1c9b0cSelric 	   void *data)
166ca1c9b0cSelric 
167ca1c9b0cSelric {
168ca1c9b0cSelric     struct _heimdal_syslog_data *s = data;
169ca1c9b0cSelric     syslog(s->priority, "%s", msg);
170ca1c9b0cSelric }
171ca1c9b0cSelric 
172ca1c9b0cSelric static void KRB5_CALLCONV
close_syslog(void * data)173ca1c9b0cSelric close_syslog(void *data)
174ca1c9b0cSelric {
175ca1c9b0cSelric     free(data);
176ca1c9b0cSelric     closelog();
177ca1c9b0cSelric }
178ca1c9b0cSelric 
179ca1c9b0cSelric static krb5_error_code
open_syslog(krb5_context context,krb5_log_facility * facility,int min,int max,const char * sev,const char * fac)180ca1c9b0cSelric open_syslog(krb5_context context,
181ca1c9b0cSelric 	    krb5_log_facility *facility, int min, int max,
182ca1c9b0cSelric 	    const char *sev, const char *fac)
183ca1c9b0cSelric {
184ca1c9b0cSelric     struct _heimdal_syslog_data *sd = malloc(sizeof(*sd));
185ca1c9b0cSelric     int i;
186ca1c9b0cSelric 
187b9d004c6Schristos     if (sd == NULL)
188b9d004c6Schristos 	return krb5_enomem(context);
189ca1c9b0cSelric     i = find_value(sev, syslogvals);
190ca1c9b0cSelric     if(i == -1)
191ca1c9b0cSelric 	i = LOG_ERR;
192ca1c9b0cSelric     sd->priority = i;
193ca1c9b0cSelric     i = find_value(fac, syslogvals);
194ca1c9b0cSelric     if(i == -1)
195ca1c9b0cSelric 	i = LOG_AUTH;
196ca1c9b0cSelric     sd->priority |= i;
197ca1c9b0cSelric     roken_openlog(facility->program, LOG_PID | LOG_NDELAY, i);
198ca1c9b0cSelric     return krb5_addlog_func(context, facility, min, max,
199ca1c9b0cSelric 			    log_syslog, close_syslog, sd);
200ca1c9b0cSelric }
201ca1c9b0cSelric 
202ca1c9b0cSelric struct file_data{
203ca1c9b0cSelric     const char *filename;
204ca1c9b0cSelric     const char *mode;
205ca1c9b0cSelric     FILE *fd;
206ca1c9b0cSelric     int keep_open;
207b9d004c6Schristos     int freefilename;
208ca1c9b0cSelric };
209ca1c9b0cSelric 
210ca1c9b0cSelric static void KRB5_CALLCONV
log_file(const char * timestr,const char * msg,void * data)211ca1c9b0cSelric log_file(const char *timestr,
212ca1c9b0cSelric 	 const char *msg,
213ca1c9b0cSelric 	 void *data)
214ca1c9b0cSelric {
215ca1c9b0cSelric     struct file_data *f = data;
216ca1c9b0cSelric     char *msgclean;
217ca1c9b0cSelric     size_t len = strlen(msg);
218ca1c9b0cSelric     if(f->keep_open == 0)
219ca1c9b0cSelric 	f->fd = fopen(f->filename, f->mode);
220ca1c9b0cSelric     if(f->fd == NULL)
221ca1c9b0cSelric 	return;
222ca1c9b0cSelric     /* make sure the log doesn't contain special chars */
223ca1c9b0cSelric     msgclean = malloc((len + 1) * 4);
224ca1c9b0cSelric     if (msgclean == NULL)
225ca1c9b0cSelric 	goto out;
226ca1c9b0cSelric     strvisx(msgclean, rk_UNCONST(msg), len, VIS_OCTAL);
227ca1c9b0cSelric     fprintf(f->fd, "%s %s\n", timestr, msgclean);
228ca1c9b0cSelric     free(msgclean);
229ca1c9b0cSelric  out:
230ca1c9b0cSelric     if(f->keep_open == 0) {
231ca1c9b0cSelric 	fclose(f->fd);
232ca1c9b0cSelric 	f->fd = NULL;
233ca1c9b0cSelric     }
234ca1c9b0cSelric }
235ca1c9b0cSelric 
236ca1c9b0cSelric static void KRB5_CALLCONV
close_file(void * data)237ca1c9b0cSelric close_file(void *data)
238ca1c9b0cSelric {
239ca1c9b0cSelric     struct file_data *f = data;
240ca1c9b0cSelric     if(f->keep_open && f->filename)
241ca1c9b0cSelric 	fclose(f->fd);
242b9d004c6Schristos     if (f->filename && f->freefilename)
243b9d004c6Schristos 	free((char *)f->filename);
244ca1c9b0cSelric     free(data);
245ca1c9b0cSelric }
246ca1c9b0cSelric 
247ca1c9b0cSelric static krb5_error_code
open_file(krb5_context context,krb5_log_facility * fac,int min,int max,const char * filename,const char * mode,FILE * f,int keep_open,int freefilename)248ca1c9b0cSelric open_file(krb5_context context, krb5_log_facility *fac, int min, int max,
249b9d004c6Schristos 	  const char *filename, const char *mode, FILE *f, int keep_open,
250b9d004c6Schristos 	  int freefilename)
251ca1c9b0cSelric {
252ca1c9b0cSelric     struct file_data *fd = malloc(sizeof(*fd));
253ca1c9b0cSelric     if (fd == NULL) {
254b9d004c6Schristos 	if (freefilename && filename)
255b9d004c6Schristos 	    free((char *)filename);
256b9d004c6Schristos 	return krb5_enomem(context);
257ca1c9b0cSelric     }
258ca1c9b0cSelric     fd->filename = filename;
259ca1c9b0cSelric     fd->mode = mode;
260ca1c9b0cSelric     fd->fd = f;
261ca1c9b0cSelric     fd->keep_open = keep_open;
262b9d004c6Schristos     fd->freefilename = freefilename;
263ca1c9b0cSelric 
264ca1c9b0cSelric     return krb5_addlog_func(context, fac, min, max, log_file, close_file, fd);
265ca1c9b0cSelric }
266ca1c9b0cSelric 
267ca1c9b0cSelric 
268ca1c9b0cSelric 
269ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_addlog_dest(krb5_context context,krb5_log_facility * f,const char * orig)270ca1c9b0cSelric krb5_addlog_dest(krb5_context context, krb5_log_facility *f, const char *orig)
271ca1c9b0cSelric {
272ca1c9b0cSelric     krb5_error_code ret = 0;
273ca1c9b0cSelric     int min = 0, max = -1, n;
274ca1c9b0cSelric     char c;
275ca1c9b0cSelric     const char *p = orig;
276b9d004c6Schristos #ifdef _WIN32
277b9d004c6Schristos     const char *q;
278b9d004c6Schristos #endif
279ca1c9b0cSelric 
280ca1c9b0cSelric     n = sscanf(p, "%d%c%d/", &min, &c, &max);
281ca1c9b0cSelric     if(n == 2){
282b9d004c6Schristos 	if(ISPATHSEP(c)) {
283ca1c9b0cSelric 	    if(min < 0){
284ca1c9b0cSelric 		max = -min;
285ca1c9b0cSelric 		min = 0;
286ca1c9b0cSelric 	    }else{
287ca1c9b0cSelric 		max = min;
288ca1c9b0cSelric 	    }
289ca1c9b0cSelric 	}
290ca1c9b0cSelric     }
291ca1c9b0cSelric     if(n){
292b9d004c6Schristos #ifdef _WIN32
293b9d004c6Schristos 	q = strrchr(p, '\\');
294b9d004c6Schristos 	if (q != NULL)
295b9d004c6Schristos 	    p = q;
296b9d004c6Schristos 	else
297b9d004c6Schristos #endif
298ca1c9b0cSelric 	p = strchr(p, '/');
299ca1c9b0cSelric 	if(p == NULL) {
300ca1c9b0cSelric 	    krb5_set_error_message(context, HEIM_ERR_LOG_PARSE,
301ca1c9b0cSelric 				   N_("failed to parse \"%s\"", ""), orig);
302ca1c9b0cSelric 	    return HEIM_ERR_LOG_PARSE;
303ca1c9b0cSelric 	}
304ca1c9b0cSelric 	p++;
305ca1c9b0cSelric     }
306ca1c9b0cSelric     if(strcmp(p, "STDERR") == 0){
307b9d004c6Schristos 	ret = open_file(context, f, min, max, NULL, NULL, stderr, 1, 0);
308ca1c9b0cSelric     }else if(strcmp(p, "CONSOLE") == 0){
309b9d004c6Schristos 	ret = open_file(context, f, min, max, "/dev/console", "w", NULL, 0, 0);
310ca1c9b0cSelric     }else if(strncmp(p, "FILE", 4) == 0 && (p[4] == ':' || p[4] == '=')){
311ca1c9b0cSelric 	char *fn;
312ca1c9b0cSelric 	FILE *file = NULL;
313ca1c9b0cSelric 	int keep_open = 0;
314ca1c9b0cSelric 	fn = strdup(p + 5);
315b9d004c6Schristos 	if (fn == NULL)
316b9d004c6Schristos 	    return krb5_enomem(context);
317ca1c9b0cSelric 	if(p[4] == '='){
318ca1c9b0cSelric 	    int i = open(fn, O_WRONLY | O_CREAT |
319ca1c9b0cSelric 			 O_TRUNC | O_APPEND, 0666);
320ca1c9b0cSelric 	    if(i < 0) {
321ca1c9b0cSelric 		ret = errno;
322ca1c9b0cSelric 		krb5_set_error_message(context, ret,
323b9d004c6Schristos 				       N_("open(%s) logfile: %s", ""), fn,
324ca1c9b0cSelric 				       strerror(ret));
325ca1c9b0cSelric 		free(fn);
326ca1c9b0cSelric 		return ret;
327ca1c9b0cSelric 	    }
328ca1c9b0cSelric 	    rk_cloexec(i);
329ca1c9b0cSelric 	    file = fdopen(i, "a");
330ca1c9b0cSelric 	    if(file == NULL){
331ca1c9b0cSelric 		ret = errno;
332ca1c9b0cSelric 		close(i);
333ca1c9b0cSelric 		krb5_set_error_message(context, ret,
334ca1c9b0cSelric 				       N_("fdopen(%s) logfile: %s", ""),
335ca1c9b0cSelric 				       fn, strerror(ret));
336ca1c9b0cSelric 		free(fn);
337ca1c9b0cSelric 		return ret;
338ca1c9b0cSelric 	    }
339ca1c9b0cSelric 	    keep_open = 1;
340ca1c9b0cSelric 	}
341b9d004c6Schristos 	ret = open_file(context, f, min, max, fn, "a", file, keep_open, 1);
342ca1c9b0cSelric     }else if(strncmp(p, "DEVICE", 6) == 0 && (p[6] == ':' || p[6] == '=')){
343b9d004c6Schristos 	ret = open_file(context, f, min, max, strdup(p + 7), "w", NULL, 0, 1);
344ca1c9b0cSelric     }else if(strncmp(p, "SYSLOG", 6) == 0 && (p[6] == '\0' || p[6] == ':')){
345ca1c9b0cSelric 	char severity[128] = "";
346ca1c9b0cSelric 	char facility[128] = "";
347ca1c9b0cSelric 	p += 6;
348ca1c9b0cSelric 	if(*p != '\0')
349ca1c9b0cSelric 	    p++;
350ca1c9b0cSelric 	if(strsep_copy(&p, ":", severity, sizeof(severity)) != -1)
351ca1c9b0cSelric 	    strsep_copy(&p, ":", facility, sizeof(facility));
352ca1c9b0cSelric 	if(*severity == '\0')
353ca1c9b0cSelric 	    strlcpy(severity, "ERR", sizeof(severity));
354ca1c9b0cSelric  	if(*facility == '\0')
355ca1c9b0cSelric 	    strlcpy(facility, "AUTH", sizeof(facility));
356ca1c9b0cSelric 	ret = open_syslog(context, f, min, max, severity, facility);
357ca1c9b0cSelric     }else{
358ca1c9b0cSelric 	ret = HEIM_ERR_LOG_PARSE; /* XXX */
359ca1c9b0cSelric 	krb5_set_error_message (context, ret,
360ca1c9b0cSelric 				N_("unknown log type: %s", ""), p);
361ca1c9b0cSelric     }
362ca1c9b0cSelric     return ret;
363ca1c9b0cSelric }
364ca1c9b0cSelric 
365ca1c9b0cSelric 
366ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_openlog(krb5_context context,const char * program,krb5_log_facility ** fac)367ca1c9b0cSelric krb5_openlog(krb5_context context,
368ca1c9b0cSelric 	     const char *program,
369ca1c9b0cSelric 	     krb5_log_facility **fac)
370ca1c9b0cSelric {
371ca1c9b0cSelric     krb5_error_code ret;
372ca1c9b0cSelric     char **p, **q;
373ca1c9b0cSelric 
374ca1c9b0cSelric     ret = krb5_initlog(context, program, fac);
375ca1c9b0cSelric     if(ret)
376ca1c9b0cSelric 	return ret;
377ca1c9b0cSelric 
378ca1c9b0cSelric     p = krb5_config_get_strings(context, NULL, "logging", program, NULL);
379ca1c9b0cSelric     if(p == NULL)
380ca1c9b0cSelric 	p = krb5_config_get_strings(context, NULL, "logging", "default", NULL);
381ca1c9b0cSelric     if(p){
382ca1c9b0cSelric 	for(q = p; *q && ret == 0; q++)
383ca1c9b0cSelric 	    ret = krb5_addlog_dest(context, *fac, *q);
384ca1c9b0cSelric 	krb5_config_free_strings(p);
385ca1c9b0cSelric     }else
386ca1c9b0cSelric 	ret = krb5_addlog_dest(context, *fac, "SYSLOG");
387ca1c9b0cSelric     return ret;
388ca1c9b0cSelric }
389ca1c9b0cSelric 
390ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_closelog(krb5_context context,krb5_log_facility * fac)391ca1c9b0cSelric krb5_closelog(krb5_context context,
392ca1c9b0cSelric 	      krb5_log_facility *fac)
393ca1c9b0cSelric {
394ca1c9b0cSelric     int i;
395ca1c9b0cSelric     for(i = 0; i < fac->len; i++)
396ca1c9b0cSelric 	(*fac->val[i].close_func)(fac->val[i].data);
397ca1c9b0cSelric     free(fac->val);
398ca1c9b0cSelric     free(fac->program);
399ca1c9b0cSelric     fac->val = NULL;
400ca1c9b0cSelric     fac->len = 0;
401ca1c9b0cSelric     fac->program = NULL;
402ca1c9b0cSelric     free(fac);
403ca1c9b0cSelric     return 0;
404ca1c9b0cSelric }
405ca1c9b0cSelric 
406ca1c9b0cSelric #undef __attribute__
407ca1c9b0cSelric #define __attribute__(X)
408ca1c9b0cSelric 
409ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_vlog_msg(krb5_context context,krb5_log_facility * fac,char ** reply,int level,const char * fmt,va_list ap)410ca1c9b0cSelric krb5_vlog_msg(krb5_context context,
411ca1c9b0cSelric 	      krb5_log_facility *fac,
412ca1c9b0cSelric 	      char **reply,
413ca1c9b0cSelric 	      int level,
414ca1c9b0cSelric 	      const char *fmt,
415ca1c9b0cSelric 	      va_list ap)
416d3273b5bSchristos      __attribute__ ((__format__ (__printf__, 5, 0)))
417ca1c9b0cSelric {
418ca1c9b0cSelric 
419ca1c9b0cSelric     char *msg = NULL;
420ca1c9b0cSelric     const char *actual = NULL;
421ca1c9b0cSelric     char buf[64];
422ca1c9b0cSelric     time_t t = 0;
423ca1c9b0cSelric     int i;
424ca1c9b0cSelric 
425ca1c9b0cSelric     for(i = 0; fac && i < fac->len; i++)
426ca1c9b0cSelric 	if(fac->val[i].min <= level &&
427ca1c9b0cSelric 	   (fac->val[i].max < 0 || fac->val[i].max >= level)) {
428ca1c9b0cSelric 	    if(t == 0) {
429ca1c9b0cSelric 		t = time(NULL);
430ca1c9b0cSelric 		krb5_format_time(context, t, buf, sizeof(buf), TRUE);
431ca1c9b0cSelric 	    }
432ca1c9b0cSelric 	    if(actual == NULL) {
433ca1c9b0cSelric 		int ret = vasprintf(&msg, fmt, ap);
434ca1c9b0cSelric 		if(ret < 0 || msg == NULL)
435ca1c9b0cSelric 		    actual = fmt;
436ca1c9b0cSelric 		else
437ca1c9b0cSelric 		    actual = msg;
438ca1c9b0cSelric 	    }
439ca1c9b0cSelric 	    (*fac->val[i].log_func)(buf, actual, fac->val[i].data);
440ca1c9b0cSelric 	}
441ca1c9b0cSelric     if(reply == NULL)
442ca1c9b0cSelric 	free(msg);
443ca1c9b0cSelric     else
444ca1c9b0cSelric 	*reply = msg;
445ca1c9b0cSelric     return 0;
446ca1c9b0cSelric }
447ca1c9b0cSelric 
448ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_vlog(krb5_context context,krb5_log_facility * fac,int level,const char * fmt,va_list ap)449ca1c9b0cSelric krb5_vlog(krb5_context context,
450ca1c9b0cSelric 	  krb5_log_facility *fac,
451ca1c9b0cSelric 	  int level,
452ca1c9b0cSelric 	  const char *fmt,
453ca1c9b0cSelric 	  va_list ap)
454d3273b5bSchristos      __attribute__ ((__format__ (__printf__, 4, 0)))
455ca1c9b0cSelric {
456ca1c9b0cSelric     return krb5_vlog_msg(context, fac, NULL, level, fmt, ap);
457ca1c9b0cSelric }
458ca1c9b0cSelric 
459ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_log_msg(krb5_context context,krb5_log_facility * fac,int level,char ** reply,const char * fmt,...)460ca1c9b0cSelric krb5_log_msg(krb5_context context,
461ca1c9b0cSelric 	     krb5_log_facility *fac,
462ca1c9b0cSelric 	     int level,
463ca1c9b0cSelric 	     char **reply,
464ca1c9b0cSelric 	     const char *fmt,
465ca1c9b0cSelric 	     ...)
466d3273b5bSchristos      __attribute__ ((__format__ (__printf__, 5, 6)))
467ca1c9b0cSelric {
468ca1c9b0cSelric     va_list ap;
469ca1c9b0cSelric     krb5_error_code ret;
470ca1c9b0cSelric 
471ca1c9b0cSelric     va_start(ap, fmt);
472ca1c9b0cSelric     ret = krb5_vlog_msg(context, fac, reply, level, fmt, ap);
473ca1c9b0cSelric     va_end(ap);
474ca1c9b0cSelric     return ret;
475ca1c9b0cSelric }
476ca1c9b0cSelric 
477ca1c9b0cSelric 
478ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_log(krb5_context context,krb5_log_facility * fac,int level,const char * fmt,...)479ca1c9b0cSelric krb5_log(krb5_context context,
480ca1c9b0cSelric 	 krb5_log_facility *fac,
481ca1c9b0cSelric 	 int level,
482ca1c9b0cSelric 	 const char *fmt,
483ca1c9b0cSelric 	 ...)
484d3273b5bSchristos      __attribute__ ((__format__ (__printf__, 4, 5)))
485ca1c9b0cSelric {
486ca1c9b0cSelric     va_list ap;
487ca1c9b0cSelric     krb5_error_code ret;
488ca1c9b0cSelric 
489ca1c9b0cSelric     va_start(ap, fmt);
490ca1c9b0cSelric     ret = krb5_vlog(context, fac, level, fmt, ap);
491ca1c9b0cSelric     va_end(ap);
492ca1c9b0cSelric     return ret;
493ca1c9b0cSelric }
494ca1c9b0cSelric 
495ca1c9b0cSelric void KRB5_LIB_FUNCTION
_krb5_debug(krb5_context context,int level,const char * fmt,...)496ca1c9b0cSelric _krb5_debug(krb5_context context,
497ca1c9b0cSelric 	    int level,
498ca1c9b0cSelric 	    const char *fmt,
499ca1c9b0cSelric 	    ...)
500d3273b5bSchristos     __attribute__ ((__format__ (__printf__, 3, 4)))
501ca1c9b0cSelric {
502ca1c9b0cSelric     va_list ap;
503ca1c9b0cSelric 
504ca1c9b0cSelric     if (context == NULL || context->debug_dest == NULL)
505ca1c9b0cSelric 	return;
506ca1c9b0cSelric 
507ca1c9b0cSelric     va_start(ap, fmt);
508ca1c9b0cSelric     krb5_vlog(context, context->debug_dest, level, fmt, ap);
509ca1c9b0cSelric     va_end(ap);
510ca1c9b0cSelric }
511ca1c9b0cSelric 
512b9d004c6Schristos KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
_krb5_have_debug(krb5_context context,int level)513ca1c9b0cSelric _krb5_have_debug(krb5_context context, int level)
514ca1c9b0cSelric {
515ca1c9b0cSelric     if (context == NULL || context->debug_dest == NULL)
516ca1c9b0cSelric 	return 0 ;
517ca1c9b0cSelric     return 1;
518ca1c9b0cSelric }
519b9d004c6Schristos 
520b9d004c6Schristos KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_set_debug_dest(krb5_context context,const char * program,const char * log_spec)521b9d004c6Schristos krb5_set_debug_dest(krb5_context context, const char *program,
522b9d004c6Schristos                     const char *log_spec)
523b9d004c6Schristos {
524b9d004c6Schristos     krb5_error_code ret;
525b9d004c6Schristos 
526b9d004c6Schristos     if (context->debug_dest == NULL) {
527b9d004c6Schristos         ret = krb5_initlog(context, program, &context->debug_dest);
528b9d004c6Schristos         if (ret)
529b9d004c6Schristos             return ret;
530b9d004c6Schristos     }
531b9d004c6Schristos 
532b9d004c6Schristos     ret = krb5_addlog_dest(context, context->debug_dest, log_spec);
533b9d004c6Schristos     if (ret)
534b9d004c6Schristos         return ret;
535b9d004c6Schristos     return 0;
536b9d004c6Schristos }
537