/* $CoreSDI: ia_syslog.c,v 1.20 2001/10/05 19:38:31 claudio Exp $ */ /* * Copyright (c) 2000, 2001, Core SDI S.A., Argentina * All rights reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither name of the Core SDI S.A. nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Syslog IA Module * Author: Claudio Castiglia */ #include #ifdef __linux__ #include #endif #include #include #include #include #include #include #include #include #include #include #include "sysdep.h" #include "packet.h" #include "resource.h" #include "modtypes.h" #include "ia_list.h" #include "iaargs.h" #include "log.h" #define IA_SYSLOG "ia syslog: " #define WHITE_SPACE " \f\n\r\t\v" #define PIDFILE0 "/var/run/syslog.pid" #define PIDFILE1 "/var/run/syslogd.pid" #define CONFILE "/etc/syslog.conf" #define INV_LOGFILE "/dev/" #define INV_LOGFILE_LEN 5 #define FORCELOG_SIGNAL ((is_msyslog) ? SIGUSR1 : SIGHUP) #define STOP_SIGNAL ((is_msyslog) ? SIGTSTP : SIGSTOP) #define CONT_SIGNAL SIGCONT static int is_msyslog = 0; /* * _syslog_pid(): * Get syslogd pid and return it; * return 0 if syslogd not running. */ static pid_t _syslog_pid() { char buf[21]; pid_t pid; int fd; pid = 0; if ( (fd = open(PIDFILE0, O_RDONLY)) < 0) fd = open(PIDFILE1, O_RDONLY); if (fd >= 0) { if (read(fd, buf, sizeof(buf)) > 0) pid = (pid_t) strtoul(buf, NULL, 10); close(fd); } return (pid); } /* * _remove_ending_junk(): * Remove ending string junk (white spaces). */ static void _remove_ending_junk(char *p) { size_t i; for (i = strlen(p) - 1; i >= 0 && isspace(p[i]); i--); p[i + 1] = '\0'; } /* * _lock(): * Send STOP signal to [m]syslogd. */ static int _lock(const char *logset) { pid_t pid; int status; log_debug(IA_SYSLOG "Locking '%s'.", logset); if ( (pid = _syslog_pid()) != 0) status = kill(pid, STOP_SIGNAL); else errno = ESRCH; if (pid == 0 || status < 0) { log_err(IA_SYSLOG "Can't send STOP signal to syslog daemon: " "%s.", strerror(errno)); return (-1); } return (0); } /* * _unlock(): * Send CONT signal to [m]syslogd. */ static int _unlock(const char *logset) { pid_t pid; int status; log_debug(IA_SYSLOG "Unlocking '%s'.", logset); if ( (pid = _syslog_pid()) != 0) status = kill(pid, CONT_SIGNAL); else errno = ESRCH; if (pid == 0 || status < 0) { log_err(IA_SYSLOG "Can't send CONT signal to syslog daemon: " "%s.", strerror(errno)); return (-1); } return (0); } /* * _hup(): * Send FORCELOG signal to [m]syslogd. */ /* XXX static void _hup() { pid_t pid; log_debug(IA_SYSLOG "Hup."); if ( (pid = _syslog_pid()) != 0) if (kill(pid, FORCELOG_SIGNAL) < 0) log_warn(IA_SYSLOG "Can't send HUP signal to syslog " "daemon: %s. Ignoring.", strerror(errno)); } */ /* * init(): * Read configuration file and return a pointer to the IA context * or NULL on error and set errno. * NOTE: The returned logset context member is really a RAW_LOGSET * type. You must call to release_raw_logset() after use it. */ IACON * init() { FILE *f; char *p, *np, line[LINE_MAX]; IACON *iacon; CMD_LINE *pcmd, *cmd; RAW_LOGSET *plogset, *logset; int error; log_debug(IA_SYSLOG "Initializing."); /* Create ia context and add space for a RAW_LOGSET pointer */ iacon = (IACON *) malloc(sizeof(IACON)); if (iacon == NULL) { log_err(IA_SYSLOG "Can't create context: %s.", strerror(errno)); return (NULL); } /* Open and parse syslog configuration file */ if ( (f = fopen(CONFILE, "r")) == NULL) { log_err(IA_SYSLOG "Can't open '%s': %s.", CONFILE, strerror(errno)); return (NULL); } plogset = logset = NULL; error = 0; log_debug(IA_SYSLOG "Parsing '%s'.", CONFILE); while (1) { if (fgets(line, sizeof(line), f) == NULL) break; /* Remove beginning white spaces */ p = line + strspn(line, WHITE_SPACE); if (*p == '\0' || *p == '#') continue; /* Jump to action field (see syslog.conf(5)) */ if (strsep(&p, WHITE_SPACE) == NULL) continue; p += strspn(p, WHITE_SPACE); if (*p == '\0') continue; _remove_ending_junk(p); /* Parse standard syslog.conf file */ if (*p != '%') { char buf[LINE_MAX]; /* Detect a valid logfile */ if (*p != '/') continue; if (!strncmp(p, INV_LOGFILE, INV_LOGFILE_LEN)) continue; /* Simulate msyslog classic module */ snprintf(buf, sizeof(buf), "classic %s", p); if ( (cmd = create_cmd_line(NULL, buf)) == NULL) { error = 1; break; } /* Create raw logset item and add it into the list */ logset = create_raw_logset(logset, cmd); if (logset == NULL) { release_cmd_line(cmd); error = 1; break; } if (plogset == NULL) plogset = logset; } else { /* Parse modular syslog configuration file */ is_msyslog = 1; p++; pcmd = cmd = NULL; while (p != NULL) { /* Detect module entry */ if ( (np = strsep(&p, "%")) != NULL) { _remove_ending_junk(np); /* * Create command line item and * add it into the list. */ cmd = create_cmd_line(cmd, np); if (cmd == NULL) { error = 1; break; } if (pcmd == NULL) pcmd = cmd; } } if (!error) { /* * Create raw logset item and * add it into the list. */ logset = create_raw_logset(logset, pcmd); if (logset == NULL) error = 1; else if (plogset == NULL) plogset = logset; } if (error) { release_cmd_line(pcmd); break; } } } fclose(f); if (error) { log_err(IA_SYSLOG "Can't initialize: %s.", strerror(errno)); free(iacon); release_raw_logset(plogset); return (NULL); } remove_raw_logset_dups(plogset); iacon->logset = (LOGSET_INFO *) plogset; return (iacon); } /* * proc_entry() */ int proc_entry(int opcode, IACON *context, void *args) { switch(opcode) { case IA_LOCK: return (_lock(args)); break; case IA_UNLOCK: return (_unlock(args)); break; default: errno = EINVAL; log_err(IA_SYSLOG "Invalid '%d' opcode.", opcode); } return (-1); }