Index: ossp-pkg/l2/l2_ch_syslog.c RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_ch_syslog.c,v rcsdiff -q -kk '-r1.20' '-r1.21' -u '/v/ossp/cvs/ossp-pkg/l2/l2_ch_syslog.c,v' 2>/dev/null --- 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 +#include +#include +#include +#include /* 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; Index: ossp-pkg/l2/l2_test.c RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_test.c,v rcsdiff -q -kk '-r1.22' '-r1.23' -u '/v/ossp/cvs/ossp-pkg/l2/l2_test.c,v' 2>/dev/null --- l2_test.c 2001/09/14 18:49:36 1.22 +++ l2_test.c 2001/09/14 19:11:00 1.23 @@ -162,8 +162,8 @@ if ((chSyslog = l2_channel_create(&l2_handler_syslog)) == NULL) /* Syslog */ die("failed to create syslog channel"); - if (l2_channel_configure(chSyslog, "ident,facility,target", - "L2-Test", "user", "local") != L2_OK) + if (l2_channel_configure(chSyslog, "ident,facility,target,remotehost,logpid", + "L2-Test", "user", "remote", "en1", 1) != L2_OK) die("failed to configure syslog channel"); if (l2_channel_open(chSyslog) != L2_OK)