--- l2_ch_syslog.c 2001/09/12 09:42:34 1.20
+++ l2_ch_syslog.c 2001/09/14 19:11:00 1.21
@@ -28,33 +28,123 @@
*/
#include "l2.h"
+#include "l2_p.h"
#include <syslog.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
/* declare private channel configuration */
typedef struct {
- char *pszIdent; /* String to prepend to each syslog message */
- int iLogopt; /* Manipulates how kernel interacts with syslogd */
- int iFacility; /* Which part of the system generates this message */
- int iPriority; /* EMERG, ALERT, CRIT, ERR, WARNING, NOTICE, INFO... */
- int iMaskpri; /* Controls which priorities are or are not logged */
+ char *szTarget;
+ char *szRemoteHost;
+ int nRemotePort;
+ char *szLocalHost;
+ char *szFacility;
+ int nFacility;
+ char *szIdent;
+ int bLogPid;
+ sa_t *saRemoteSock;
+ sa_addr_t *saaRemoteAddr;
} l2_ch_syslog_t;
+/* mapping from L2 log levels to syslog(3) log levels */
+static struct {
+ int levelL2;
+ int levelSL;
+} l2_ch_syslog_L2toSL[] = {
+ { L2_LEVEL_PANIC, LOG_EMERG },
+ { L2_LEVEL_CRITICAL, LOG_CRIT },
+ { L2_LEVEL_ERROR, LOG_ERR },
+ { L2_LEVEL_WARNING, LOG_WARNING },
+ { L2_LEVEL_NOTICE, LOG_NOTICE },
+ { L2_LEVEL_INFO, LOG_INFO },
+ { L2_LEVEL_TRACE, LOG_INFO },
+ { L2_LEVEL_DEBUG, LOG_DEBUG },
+ { -1, -1 }
+};
+
+/* Syslog Facility Table */
+static struct {
+ char *name; /* the common name */
+ int numREMOTE; /* number according to RFC3164 */
+ int numLOCAL; /* local encoding */
+} l2_ch_syslog_SLfac[] = {
+ { "kern", 0, LOG_KERN },
+ { "user", 1, LOG_USER },
+ { "mail", 2, LOG_MAIL },
+ { "daemon", 3, LOG_DAEMON },
+ { "auth", 4, LOG_AUTH },
+#ifndef LOG_SYSLOG
+#define LOG_SYSLOG (5 << 3)
+#endif
+ { "syslog", 5, LOG_SYSLOG },
+ { "lpr", 6, LOG_LPR },
+ { "news", 7, LOG_NEWS },
+ { "uucp", 8, LOG_UUCP },
+ { "cron", 9, LOG_CRON },
+#ifndef LOG_AUTHPRIV
+#define LOG_AUTHPRIV (10 << 3)
+#endif
+ { "authpriv", 10, LOG_AUTHPRIV },
+ { "ftp", 11, LOG_FTP },
+#ifndef LOG_NTP
+#define LOG_NTP (12 << 3)
+#endif
+ { "ntp", 12, LOG_NTP },
+#ifndef LOG_SECURITY
+#define LOG_SECURITY (13 << 3)
+#endif
+ { "security", 13, LOG_SECURITY },
+#ifndef LOG_CONSOLE
+#define LOG_CONSOLE (14 << 3)
+#endif
+ { "console", 14, LOG_CONSOLE },
+#ifndef LOG_CLOCK
+#define LOG_CLOCK (15 << 3)
+#endif
+ { "clock", 15, LOG_CLOCK },
+ { "local0", 16, LOG_LOCAL0 },
+ { "local1", 17, LOG_LOCAL1 },
+ { "local2", 18, LOG_LOCAL2 },
+ { "local3", 19, LOG_LOCAL3 },
+ { "local4", 20, LOG_LOCAL4 },
+ { "local5", 21, LOG_LOCAL5 },
+ { "local6", 22, LOG_LOCAL6 },
+ { "local7", 23, LOG_LOCAL7 },
+ { NULL, 0, 0 }
+};
+
/* create channel */
static l2_result_t hook_create(l2_context_t *ctx, l2_channel_t *ch)
{
l2_ch_syslog_t *cfg;
+ struct utsname uts;
+ char *cp;
/* allocate private channel configuration */
if ((cfg = (l2_ch_syslog_t *)malloc(sizeof(l2_ch_syslog_t))) == NULL)
return L2_ERR_MEM;
/* initialize configuration with reasonable defaults */
- cfg->pszIdent = NULL;
- cfg->iLogopt = 0;
- cfg->iFacility = LOG_USER;
- cfg->iPriority = (LOG_DEBUG|LOG_ERR);
- cfg->iMaskpri = (0xFFFFFFFF); /* Allow all priorities to pass through */
+ cfg->szTarget = strdup("local");
+ cfg->szRemoteHost = NULL;
+ cfg->nRemotePort = 514;
+ if (uname(&uts) == 0) {
+ cfg->szLocalHost = strdup(uts.nodename);
+ if ((cp = strchr(cfg->szLocalHost, '.')) != NULL)
+ *cp = '\0';
+ }
+ else
+ cfg->szLocalHost = strdup("localhost");
+ cfg->szFacility = strdup("user");
+ cfg->nFacility = LOG_USER;
+ cfg->szIdent = NULL;
+ cfg->bLogPid = FALSE;
+ cfg->saRemoteSock = NULL;
+ cfg->saaRemoteAddr = NULL;
/* link private channel configuration into channel context */
ctx->vp = cfg;
@@ -66,18 +156,45 @@
static l2_result_t hook_configure(l2_context_t *ctx, l2_channel_t *ch, const char *fmt, va_list ap)
{
l2_ch_syslog_t *cfg = (l2_ch_syslog_t *)ctx->vp;
- l2_param_t pa[6];
+ l2_param_t pa[8];
l2_result_t rv;
+ int i;
/* feed and call generic parameter parsing engine */
- L2_PARAM_SET(pa[0], ident, CHARPTR, &cfg->pszIdent);
- L2_PARAM_SET(pa[1], logopts, INT, &cfg->iLogopt);
- L2_PARAM_SET(pa[2], facility, INT, &cfg->iFacility);
- L2_PARAM_SET(pa[3], priority, INT, &cfg->iPriority);
- L2_PARAM_SET(pa[4], maskpriority, INT, &cfg->iMaskpri);
- L2_PARAM_END(pa[5]);
- rv = l2_util_setparams(pa, fmt, ap);
+ L2_PARAM_SET(pa[0], target, STRING, &cfg->szTarget);
+ L2_PARAM_SET(pa[1], remotehost, STRING, &cfg->szRemoteHost);
+ L2_PARAM_SET(pa[2], remoteport, INT, &cfg->nRemotePort);
+ L2_PARAM_SET(pa[3], localhost, STRING, &cfg->szLocalHost);
+ L2_PARAM_SET(pa[4], facility, STRING, &cfg->szFacility);
+ L2_PARAM_SET(pa[5], ident, STRING, &cfg->szIdent);
+ L2_PARAM_SET(pa[6], logpid, INT, &cfg->bLogPid);
+ L2_PARAM_END(pa[7]);
+ /* sanity checking & post-processing */
+ rv = l2_util_setparams(pa, fmt, ap);
+ if (cfg->szTarget == NULL || cfg->szFacility == NULL)
+ return L2_ERR_USE;
+ if (!( strcmp(cfg->szTarget, "local") == 0
+ || strcmp(cfg->szTarget, "remote") == 0))
+ return L2_ERR_USE;
+ for (i = 0; l2_ch_syslog_SLfac[i].name != NULL; i++)
+ if (strcmp(l2_ch_syslog_SLfac[i].name, cfg->szFacility) == 0)
+ break;
+ if (l2_ch_syslog_SLfac[i].name == NULL)
+ return L2_ERR_USE;
+ if (strcmp(cfg->szTarget, "local") == 0)
+ cfg->nFacility = l2_ch_syslog_SLfac[i].numLOCAL;
+ else
+ cfg->nFacility = (l2_ch_syslog_SLfac[i].numREMOTE << 3);
+ if ( strcmp(cfg->szTarget, "remote") == 0
+ && (cfg->szRemoteHost == NULL
+ || (cfg->nRemotePort <= 0 || cfg->nRemotePort >= 65536)))
+ return L2_ERR_USE;
+ if ( cfg->szLocalHost == NULL
+ || strchr(cfg->szLocalHost, '.') != NULL)
+ return L2_ERR_USE;
+ if (cfg->szIdent != NULL && strlen(cfg->szIdent) > (32-(1+5+1)))
+ return L2_ERR_USE;
return rv;
}
@@ -85,11 +202,36 @@
static l2_result_t hook_open(l2_context_t *ctx, l2_channel_t *ch)
{
l2_ch_syslog_t *cfg = (l2_ch_syslog_t *)ctx->vp;
-
- /* open channel syslog */
- openlog(cfg->pszIdent, cfg->iLogopt, cfg->iFacility);
- setlogmask(cfg->iMaskpri);
-
+ int opt;
+ sa_rc_t rc;
+ sa_addr_t *la;
+
+ if (cfg->szIdent == NULL)
+ return L2_ERR_USE;
+ if (strcmp(cfg->szTarget, "local") == 0) {
+ /* open local syslog connection via syslog(3) */
+ opt = 0;
+ if (cfg->bLogPid)
+ opt |= LOG_PID;
+ openlog(cfg->szIdent, opt, cfg->nFacility);
+ /* setlogmask(0); */
+ }
+ else {
+ /* open remote syslog connection via UDP socket */
+ if (cfg->szRemoteHost == NULL)
+ return L2_ERR_USE;
+ if ((rc = sa_u2a(&cfg->saaRemoteAddr, "udp://%s:%d",
+ cfg->szRemoteHost, cfg->nRemotePort)) != SA_OK)
+ return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT);
+ if ((rc = sa_create(&cfg->saRemoteSock)) != SA_OK)
+ return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT);
+ sa_timeout(cfg->saRemoteSock, 10, 0);
+ /* FIXME: if uid == 0 -> use port 514 */
+ if ((rc = sa_u2a(&la, "udp://0.0.0.0:0")) != SA_OK)
+ return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT);
+ if ((rc = sa_bind(cfg->saRemoteSock, la)) != SA_OK)
+ return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT);
+ }
return L2_OK;
}
@@ -98,9 +240,56 @@
l2_level_t level, const char *buf, size_t buf_size)
{
l2_ch_syslog_t *cfg = (l2_ch_syslog_t *)ctx->vp;
-
- /* write message to channel syslog */
- syslog(cfg->iPriority, buf);
+ int prio;
+ int i;
+ char caTime[15+1];
+ char caBuf[2048];
+ time_t t;
+ struct tm *tm;
+ size_t n;
+ sa_rc_t rc;
+
+ /* determine syslog priority */
+ prio = 0;
+ for (i = 0; l2_ch_syslog_L2toSL[i].levelL2 != -1; i++) {
+ if (l2_ch_syslog_L2toSL[i].levelL2 == level) {
+ prio = l2_ch_syslog_L2toSL[i].levelSL;
+ break;
+ }
+ }
+ if (l2_ch_syslog_L2toSL[i].levelL2 == -1)
+ return L2_ERR_USE;
+
+ /* FIXME: nul-terminate buf? */
+
+ if (strcmp(cfg->szTarget, "local") == 0) {
+ /* send to local syslogd via syslog(3) */
+ syslog(prio, buf);
+ }
+ else {
+ /* send to remote syslogd via UDP */
+ if (strlen(buf) > 1024)
+ return L2_ERR_MEM;
+ prio += cfg->nFacility;
+ t = time(NULL);
+ tm = localtime(&t);
+ strftime(caTime, sizeof(caTime), "%b %d %H:%M:%S", tm);
+ if (caTime[4] == '0')
+ caTime[4] = ' ';
+ if (cfg->bLogPid)
+ sprintf(caBuf, "<%d>%s %s %s[%lu]: %s",
+ prio, caTime, cfg->szLocalHost,
+ cfg->szIdent, (unsigned long)getpid(), buf);
+ else
+ sprintf(caBuf, "<%d>%s %s %s: %s",
+ prio, caTime, cfg->szLocalHost,
+ cfg->szIdent, buf);
+ if ((n = strlen(caBuf)) > 1024)
+ return L2_ERR_IO;
+ if ((rc = sa_writeto(cfg->saRemoteSock, caBuf, n,
+ NULL, cfg->saaRemoteAddr)) != SA_OK)
+ return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_IO);
+ }
return L2_OK;
}
@@ -108,9 +297,21 @@
/* close channel */
static l2_result_t hook_close(l2_context_t *ctx, l2_channel_t *ch)
{
- /* close channel syslog */
- closelog();
+ l2_ch_syslog_t *cfg = (l2_ch_syslog_t *)ctx->vp;
+ if (strcmp(cfg->szTarget, "local") == 0) {
+ closelog();
+ }
+ else {
+ if (cfg->saRemoteSock != NULL) {
+ sa_destroy(cfg->saRemoteSock);
+ cfg->saRemoteSock = NULL;
+ }
+ if (cfg->saaRemoteAddr != NULL) {
+ free(cfg->saaRemoteAddr);
+ cfg->saaRemoteAddr = NULL;
+ }
+ }
return L2_OK;
}
@@ -120,6 +321,20 @@
l2_ch_syslog_t *cfg = (l2_ch_syslog_t *)ctx->vp;
/* destroy channel configuration */
+ if (cfg->szTarget != NULL)
+ free(cfg->szTarget);
+ if (cfg->szRemoteHost != NULL)
+ free(cfg->szRemoteHost);
+ if (cfg->szLocalHost != NULL)
+ free(cfg->szLocalHost);
+ if (cfg->szFacility != NULL)
+ free(cfg->szFacility);
+ if (cfg->szIdent != NULL)
+ free(cfg->szIdent);
+ if (cfg->saRemoteSock != NULL)
+ sa_destroy(cfg->saRemoteSock);
+ if (cfg->saaRemoteAddr != NULL)
+ free(cfg->saaRemoteAddr);
free(cfg);
return L2_OK;
|