1/*++
2/* NAME
3/*	msg_syslog 3
4/* SUMMARY
5/*	direct diagnostics to syslog daemon
6/* SYNOPSIS
7/*	#include <msg_syslog.h>
8/*
9/*	void	msg_syslog_init(progname, log_opt, facility)
10/*	const char *progname;
11/*	int	log_opt;
12/*	int	facility;
13/*
14/*	int     msg_syslog_facility(facility_name)
15/*	const char *facility_name;
16/* DESCRIPTION
17/*	This module implements support to report msg(3) diagnostics
18/*	via the syslog daemon.
19/*
20/*	msg_syslog_init() is a wrapper around the openlog(3) routine
21/*	that directs subsequent msg(3) output to the syslog daemon.
22/*
23/*	msg_syslog_facility() is a helper routine that overrides the
24/*	logging facility that is specified with msg_syslog_init().
25/*	The result is zero in case of an unknown facility name.
26/* SEE ALSO
27/*	syslog(3) syslog library
28/*	msg(3)	diagnostics module
29/* BUGS
30/*	Output records are truncated to 2000 characters. This is done in
31/*	order to defend against a buffer overflow problem in some
32/*	implementations of the syslog() library routine.
33/* LICENSE
34/* .ad
35/* .fi
36/*	The Secure Mailer license must be distributed with this software.
37/* AUTHOR(S)
38/*	Wietse Venema
39/*	IBM T.J. Watson Research
40/*	P.O. Box 704
41/*	Yorktown Heights, NY 10598, USA
42/*--*/
43
44/* System libraries. */
45
46#include <sys_defs.h>
47#include <stdlib.h>			/* 44BSD stdarg.h uses abort() */
48#include <stdarg.h>
49#include <errno.h>
50#include <syslog.h>
51#include <string.h>
52#include <time.h>
53
54/* Application-specific. */
55
56#include "vstring.h"
57#include "stringops.h"
58#include "msg.h"
59#include "msg_output.h"
60#include "msg_syslog.h"
61#include "safe.h"
62
63 /*
64  * Stay a little below the 2048-byte limit of older syslog()
65  * implementations.
66  */
67#define MSG_SYSLOG_RECLEN	2000
68
69struct facility_list {
70    const char *name;
71    int     facility;
72};
73
74static struct facility_list facility_list[] = {
75#ifdef LOG_AUTH
76    "auth", LOG_AUTH,
77#endif
78#ifdef LOG_AUTHPRIV
79    "authpriv", LOG_AUTHPRIV,
80#endif
81#ifdef LOG_CRON
82    "cron", LOG_CRON,
83#endif
84#ifdef LOG_DAEMON
85    "daemon", LOG_DAEMON,
86#endif
87#ifdef LOG_FTP
88    "ftp", LOG_FTP,
89#endif
90#ifdef LOG_KERN
91    "kern", LOG_KERN,
92#endif
93#ifdef LOG_LPR
94    "lpr", LOG_LPR,
95#endif
96#ifdef LOG_MAIL
97    "mail", LOG_MAIL,
98#endif
99#ifdef LOG_NEWS
100    "news", LOG_NEWS,
101#endif
102#ifdef LOG_SECURITY
103    "security", LOG_SECURITY,
104#endif
105#ifdef LOG_SYSLOG
106    "syslog", LOG_SYSLOG,
107#endif
108#ifdef LOG_USER
109    "user", LOG_USER,
110#endif
111#ifdef LOG_UUCP
112    "uucp", LOG_UUCP,
113#endif
114#ifdef LOG_LOCAL0
115    "local0", LOG_LOCAL0,
116#endif
117#ifdef LOG_LOCAL1
118    "local1", LOG_LOCAL1,
119#endif
120#ifdef LOG_LOCAL2
121    "local2", LOG_LOCAL2,
122#endif
123#ifdef LOG_LOCAL3
124    "local3", LOG_LOCAL3,
125#endif
126#ifdef LOG_LOCAL4
127    "local4", LOG_LOCAL4,
128#endif
129#ifdef LOG_LOCAL5
130    "local5", LOG_LOCAL5,
131#endif
132#ifdef LOG_LOCAL6
133    "local6", LOG_LOCAL6,
134#endif
135#ifdef LOG_LOCAL7
136    "local7", LOG_LOCAL7,
137#endif
138    0,
139};
140
141static int syslog_facility;
142
143/* msg_syslog_print - log info to syslog daemon */
144
145static void msg_syslog_print(int level, const char *text)
146{
147    static int log_level[] = {
148	LOG_INFO, LOG_WARNING, LOG_ERR, LOG_CRIT, LOG_CRIT,
149    };
150    static char *severity_name[] = {
151	"info", "warning", "error", "fatal", "panic",
152    };
153
154    if (level < 0 || level >= (int) (sizeof(log_level) / sizeof(log_level[0])))
155	msg_panic("msg_syslog_print: invalid severity level: %d", level);
156
157    if (level == MSG_INFO) {
158	syslog(syslog_facility | log_level[level], "%.*s",
159	       (int) MSG_SYSLOG_RECLEN, text);
160    } else {
161	syslog(syslog_facility | log_level[level], "%s: %.*s",
162	       severity_name[level], (int) MSG_SYSLOG_RECLEN, text);
163    }
164}
165
166/* msg_syslog_init - initialize */
167
168void    msg_syslog_init(const char *name, int logopt, int facility)
169{
170    static int first_call = 1;
171
172    /*
173     * XXX If this program is set-gid, then TZ must not be trusted. This
174     * scrubbing code is in the wrong place.
175     */
176    if (unsafe())
177	putenv("TZ=UTC");
178    tzset();
179    openlog(name, LOG_NDELAY | logopt, facility);
180    if (first_call) {
181	first_call = 0;
182	msg_output(msg_syslog_print);
183    }
184}
185
186/* msg_syslog_facility - set logging facility by name */
187
188int     msg_syslog_facility(const char *facility_name)
189{
190    struct facility_list *fnp;
191
192    for (fnp = facility_list; fnp->name; ++fnp) {
193	if (!strcmp(fnp->name, facility_name)) {
194	    syslog_facility = fnp->facility;
195	    return (1);
196	}
197    }
198    return 0;
199}
200
201#ifdef TEST
202
203 /*
204  * Proof-of-concept program to test the syslogging diagnostics interface
205  *
206  * Usage: msg_syslog_test text...
207  */
208
209int     main(int argc, char **argv)
210{
211    VSTRING *vp = vstring_alloc(256);
212
213    msg_syslog_init(argv[0], LOG_PID, LOG_MAIL);
214    if (argc < 2)
215	msg_error("usage: %s text to be logged", argv[0]);
216    while (--argc && *++argv) {
217	vstring_strcat(vp, *argv);
218	if (argv[1])
219	    vstring_strcat(vp, " ");
220    }
221    msg_warn("static text");
222    msg_warn("dynamic text: >%s<", vstring_str(vp));
223    msg_warn("dynamic numeric: >%d<", 42);
224    msg_warn("error text: >%m<");
225    msg_warn("dynamic: >%s<: error: >%m<", vstring_str(vp));
226    vstring_free(vp);
227    return (0);
228}
229
230#endif
231