Bugtraq mailing list archives
[Tim Newsham: ]
From: newsham () uhunix uhcc hawaii edu (Tim Newsham)
Date: Sun, 2 Oct 1994 08:06:07 -1000
/*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
All rights reserved.\n";
#endif not lint
#ifndef lint
static char sccsid[] = "@(#)syslogd.c 1.1 91/11/13 SMI"; /* from UCB 5.18 2/23/87 */
#endif not lint
/*
* syslogd -- log system messages
*
* This program implements a system log. It takes a series of lines.
* Each line may have a priority, signified as "<n>" as
* the first characters of the line. If this is
* not present, a default priority is used.
*
* To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
* cause it to reread its configuration file.
*
* Defined Constants:
*
* MAXLINE -- the maximimum line length that can be handled.
* NLOGS -- the maximum number of simultaneous log files.
* DEFUPRI -- the default priority for user messages
* DEFSPRI -- the default priority for kernel messages
*
* Author: Eric Allman
* extensive changes by Ralph Campbell
*/
#define DEFUPRI (LOG_USER|LOG_NOTICE)
#define DEFSPRI (LOG_KERN|LOG_ERR)
#define PANICPRI (LOG_KERN|LOG_EMERG)
#define NLOGS 20 /* max number of log files */
#define MAXLINE 1024 /* maximum line length */
#define MARKCOUNT /*10*/3 /* ratio of minor to major marks */
#include <errno.h>
#include <stdio.h>
#include <utmp.h>
#include <ctype.h>
#include <signal.h>
#include <sysexits.h>
#include <strings.h>
#include <values.h>
#include <sys/syslog.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/msgbuf.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netdb.h>
char *LogName = "/dev/log";
char *ConfFile = "/etc/syslog.conf";
char *PidFile = "/etc/syslog.pid";
char ctty[] = "/dev/console";
char panic_str[] = "panic:";
#define FDMASK(fd) (1 << (fd))
#define dprintf if (Debug) (void) printf
#define UNAMESZ 8 /* length of a login name */
#define MAXUNAMES 20 /* maximum number of user names */
#define MAXFNAME 200 /* max file pathname length */
#define NOPRI 0x10 /* the "no priority" priority */
#define LOG_MARK (LOG_NFACILITIES << 3) /* mark "facility" */
/*
* Flags to printline().
*/
#define ALL 0 /* all messages allowed */
#define USER_ONLY 1 /* force kernel messages to user */
/*
* Flags to logmsg().
*/
#define IGN_CONS 0x001 /* don't print on console */
#define SYNC_FILE 0x002 /* do fsync on file after printing */
#define NOCOPY 0x004 /* don't suppress duplicate messages */
#define ADDDATE 0x008 /* add a date to the message */
#define MARK 0x010 /* this message is a mark */
/*
* This structure represents the files that will have log
* copies printed.
*/
struct filed {
short f_type; /* entry type, see below */
short f_file; /* file descriptor */
time_t f_time; /* time this was last written */
u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */
union {
char f_uname[MAXUNAMES][UNAMESZ+1];
struct {
char f_hname[MAXHOSTNAMELEN+1];
struct sockaddr_in f_addr;
} f_forw; /* forwarding address */
char f_fname[MAXFNAME];
} f_un;
};
/* values for f_type */
#define F_UNUSED 0 /* unused entry */
#define F_FILE 1 /* regular file */
#define F_TTY 2 /* terminal */
#define F_CONSOLE 3 /* console terminal */
#define F_FORW 4 /* remote machine */
#define F_USERS 5 /* list of users */
#define F_WALL 6 /* everyone logged on */
char *TypeNames[7] = {
"UNUSED", "FILE", "TTY", "CONSOLE",
"FORW", "USERS", "WALL"
};
struct filed Files[NLOGS];
/* simple hash table cache for host names */
#define HASHSIZE 497
struct hashent {
struct hashent *next;
unsigned long addr;
char name[MAXHOSTNAMELEN];
};
struct hashent *Table[HASHSIZE];
int Debug; /* debug flag */
char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */
char *LocalDomain; /* our local domain name */
int InetInuse = 0; /* non-zero if INET sockets are being used */
int LogPort; /* port number for INET connections */
char PrevLine[MAXLINE + 1]; /* copy of last line to supress repeats */
char PrevHost[MAXHOSTNAMELEN+1]; /* previous host */
int PrevFlags;
int PrevPri;
int PrevCount = 0; /* number of times seen */
int FlushTimer; /* timer for flushing messages */
int Initialized = 0; /* set when we have initialized ourselves */
int MarkInterval = 20; /* interval between marks in minutes */
int Marking = 0; /* non-zero if marking some file */
int MarkTimer; /* timer for marks */
int defupri = DEFUPRI; /* default user priority */
int defspri = DEFSPRI; /* default kernel priority */
void init();
extern void exit();
extern int sys_nerr;
extern char *sys_errlist[];
extern char *ctime(), *index();
extern char *malloc();
extern time_t time();
/* Lint does not seem to understand that errno is external. */
#ifdef lint
int errno;
#else lint
extern int errno;
#endif lint
main(argc, argv)
int argc;
char **argv;
{
register int i;
register char *p;
int funix, finet, inetm, fklog, klogm, len;
struct sockaddr_un sunx, fromunix;
struct sockaddr_in sin, frominet;
FILE *fp;
char line[MSG_BSIZE + 1];
void die(), doalarm(), reapchild();
bzero((char *)&sin, sizeof (struct sockaddr_in));
bzero((char *)&sunx, sizeof (struct sockaddr_un));
while (--argc > 0) {
p = *++argv;
if (p[0] != '-')
usage();
switch (p[1]) {
case 'f': /* configuration file */
if (p[2] != '\0')
ConfFile = &p[2];
break;
case 'd': /* debug */
Debug++;
break;
case 'p': /* path */
if (p[2] != '\0')
LogName = &p[2];
break;
case 'm': /* mark interval */
if (p[2] != '\0')
MarkInterval = atoi(&p[2]);
break;
default:
usage();
}
}
if (!Debug) {
if (fork())
exit(0);
for (i = 0; i < 10; i++)
(void) close(i);
(void) open("/", 0);
(void) dup2(0, 1);
(void) dup2(0, 2);
untty();
} else
setlinebuf(stdout);
(void) gethostname(LocalHostName, sizeof LocalHostName);
if (p = index(LocalHostName, '.')) {
*p++ = '\0';
LocalDomain = p;
}
else
LocalDomain = "";
(void) signal(SIGTERM, die);
(void) signal(SIGINT, Debug ? die : SIG_IGN);
(void) signal(SIGQUIT, Debug ? die : SIG_IGN);
(void) signal(SIGCHLD, reapchild);
(void) signal(SIGALRM, doalarm);
(void) unlink(LogName);
sunx.sun_family = AF_UNIX;
(void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path);
funix = socket(AF_UNIX, SOCK_DGRAM, 0);
if (funix < 0 || bind(funix, (struct sockaddr *) &sunx,
sizeof(sunx.sun_family)+strlen(sunx.sun_path)) < 0 ||
chmod(LogName, 0666) < 0) {
(void) sprintf(line, "cannot create %s", LogName);
logerror(line);
dprintf("cannot create %s (%d)\n", LogName, errno);
die(0);
}
finet = socket(AF_INET, SOCK_DGRAM, 0);
if (finet >= 0) {
struct servent *sp;
sp = getservbyname("syslog", "udp");
if (sp == NULL) {
errno = 0;
logerror("syslog/udp: unknown service");
die(0);
}
sin.sin_family = AF_INET;
sin.sin_port = LogPort = sp->s_port;
if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
logerror("bind");
if (!Debug)
die(0);
} else {
inetm = FDMASK(finet);
InetInuse = 1;
}
}
if ((fklog = open("/dev/klog", O_RDONLY)) >= 0)
klogm = FDMASK(fklog);
else {
dprintf("can't open /dev/klog (%d)\n", errno);
klogm = 0;
}
/* tuck my process id away */
fp = fopen(PidFile, "w");
if (fp != NULL) {
(void) fprintf(fp, "%d\n", getpid());
(void) fclose(fp);
}
dprintf("off & running....\n");
init();
(void) signal(SIGHUP, init);
for (;;) {
int nfds, readfds = FDMASK(funix) | inetm | klogm;
errno = 0;
dprintf("readfds = %#x\n", readfds, funix, finet, fklog);
nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL,
(fd_set *) NULL, (struct timeval *) NULL);
dprintf("got a message (%d, %#x)\n", nfds, readfds);
if (nfds == 0)
continue;
if (nfds < 0) {
if (errno != EINTR)
logerror("select");
continue;
}
if (readfds & klogm) {
i = read(fklog, line, sizeof(line) - 1);
if (i > 0) {
line[i] = '\0';
printsys(line);
} else if (i < 0 && errno != EINTR) {
logerror("klog");
fklog = -1;
klogm = 0;
}
}
if (readfds & FDMASK(funix)) {
len = sizeof fromunix;
i = recvfrom(funix, line, MAXLINE, 0,
(struct sockaddr *) &fromunix, &len);
if (i > 0) {
line[i] = '\0';
printline(LocalHostName, line, USER_ONLY);
} else if (i < 0 && errno != EINTR)
logerror("recvfrom unix");
}
if (readfds & inetm) {
len = sizeof frominet;
i = recvfrom(finet, line, MAXLINE, 0,
(struct sockaddr *)&frominet, &len);
if (i > 0) {
extern char *cvthname();
line[i] = '\0';
printline(cvthname(&frominet), line, ALL);
} else if (i < 0 && errno != EINTR)
logerror("recvfrom inet");
}
}
}
usage()
{
(void) fprintf(stderr,
"usage: syslogd [-d] [-mmarkinterval] [-ppath] [-fconffile]\n");
exit(1);
}
untty()
{
int i;
if (!Debug) {
i = open("/dev/tty", O_RDWR);
if (i >= 0) {
(void) ioctl(i, (int) TIOCNOTTY, (char *)0);
(void) close(i);
}
}
}
/*
* Take a raw input line, decode the message, and print the message
* on the appropriate log files.
*/
printline(hname, msg, force_usr)
char *hname;
char *msg;
int force_usr;
{
register char *p, *q;
register int c;
char line[MAXLINE + 1];
int pri;
/* test for special codes */
p = msg;
if (*p == '<' && isdigit(*(p+1))) {
pri = 0;
while (isdigit(*++p))
pri = 10 * pri + (*p - '0');
if (*p == '>')
++p;
dprintf("printline pri= %o\n", pri);
if (pri < 0 || pri >= (LOG_NFACILITIES << 3))
pri = defupri;
} else {
pri = defupri;
}
/* don't allow users to log kernel messages */
if (force_usr && (pri & LOG_PRIMASK) == LOG_KERN)
pri |= LOG_USER;
q = line;
while ((c = *p++ & 0177) != '\0' && c != '\n' &&
q < &line[sizeof(line) - 1]) {
if (iscntrl(c)) {
*q++ = '^';
*q++ = c ^ 0100;
} else
*q++ = c;
}
*q = '\0';
logmsg(pri, line, hname, 0);
}
/*
* Take a raw input line from /dev/klog, split and format similar to syslog().
*/
printsys(msg)
char *msg;
{
register char *p, *q;
register int c;
char line[MAXLINE + 1];
int pri, flags;
char *lp;
time_t now;
(void) time(&now);
(void) sprintf(line, "%.15s vmunix: ", ctime(&now) + 4);
lp = line + strlen(line);
for (p = msg; *p != '\0'; ) {
flags = SYNC_FILE; /* fsync file after write */
if (*p == '<' && isdigit(*(p+1))) {
pri = 0;
while (isdigit(*++p))
pri = 10 * pri + (*p - '0');
if (*p == '>')
++p;
dprintf("printsys pri= %o\n", pri);
if (pri < 0 || pri >= (LOG_NFACILITIES << 3))
pri = defspri;
} else if (*p == panic_str[0] &&
bcmp(panic_str, p, sizeof(panic_str)-1) == 0) {
/* kernel panic's come out on console */
pri = PANICPRI;
flags |= IGN_CONS;
} else {
/* kernel printf's come out on console */
pri = defspri;
flags |= IGN_CONS;
}
q = lp;
while (*p != '\0' && (c = *p++) != '\n' &&
q < &line[MAXLINE])
*q++ = c;
*q = '\0';
logmsg(pri, line, LocalHostName, flags);
}
}
/*
* Log a message to the appropriate log files, users, etc. based on
* the priority.
*/
logmsg(pri, msg, from, flags)
int pri;
char *msg, *from;
int flags;
{
register struct filed *f;
register int l;
int fac, prilev;
time_t now;
int omask;
struct iovec iov[6];
register struct iovec *v = iov;
char line[MAXLINE + 1];
dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", pri, flags,
from, msg);
omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
/*
* Check to see if msg looks non-standard.
*/
if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
flags |= ADDDATE;
if (!(flags & NOCOPY)) {
if (flags & (ADDDATE|MARK))
flushmsg();
else if (!strcmp(msg + 16, PrevLine + 16)) {
/* we found a match, update the time */
(void) strncpy(PrevLine, msg, 15);
if (PrevCount == 0) {
FlushTimer = MarkInterval * 60 / MARKCOUNT;
setalarm(FlushTimer);
}
PrevCount++;
(void) sigsetmask(omask);
return;
} else {
/* new line, save it */
flushmsg();
(void) strcpy(PrevLine, msg);
(void) strcpy(PrevHost, from);
PrevFlags = flags;
PrevPri = pri;
}
}
(void) time(&now);
if (flags & ADDDATE)
v->iov_base = ctime(&now) + 4;
else
v->iov_base = msg;
v->iov_len = 15;
v++;
v->iov_base = " ";
v->iov_len = 1;
v++;
v->iov_base = from;
v->iov_len = strlen(v->iov_base);
v++;
v->iov_base = " ";
v->iov_len = 1;
v++;
if (flags & ADDDATE)
v->iov_base = msg;
else
v->iov_base = msg + 16;
v->iov_len = strlen(v->iov_base);
v++;
/* extract facility and priority level */
fac = (pri & LOG_FACMASK) >> 3;
if (flags & MARK)
fac = LOG_NFACILITIES;
prilev = pri & LOG_PRIMASK;
/* log the message to the particular outputs */
if (!Initialized) {
int cfd = open(ctty, O_WRONLY);
if (cfd >= 0) {
v->iov_base = "\r\n";
v->iov_len = 2;
(void) writev(cfd, iov, 6);
(void) close(cfd);
}
untty();
(void) sigsetmask(omask);
return;
}
for (f = Files; f < &Files[NLOGS]; f++) {
/* skip messages that are incorrect priority */
if (f->f_pmask[fac] < prilev || f->f_pmask[fac] == NOPRI)
continue;
/* don't output marks to recently written files */
if ((flags & MARK) && (now - f->f_time) < (MarkInterval * 60 / 2))
continue;
dprintf("Logging to %s", TypeNames[f->f_type]);
f->f_time = now;
switch (f->f_type) {
case F_UNUSED:
dprintf("\n");
break;
case F_FORW:
dprintf(" %s\n", f->f_un.f_forw.f_hname);
(void) sprintf(line, "<%u>%.15s %s", pri,
iov[0].iov_base, iov[4].iov_base);
l = strlen(line);
if (l > MAXLINE)
l = MAXLINE;
if (sendto(f->f_file, line, l, 0,
(struct sockaddr *)&f->f_un.f_forw.f_addr,
sizeof f->f_un.f_forw.f_addr) != l) {
int e = errno;
(void) close(f->f_file);
f->f_type = F_UNUSED;
errno = e;
logerror("sendto");
}
break;
case F_CONSOLE:
if (flags & IGN_CONS) {
dprintf(" (ignored)\n");
break;
}
case F_TTY:
case F_FILE:
dprintf(" %s\n", f->f_un.f_fname);
if (f->f_type != F_FILE) {
v->iov_base = "\r\n";
v->iov_len = 2;
} else {
v->iov_base = "\n";
v->iov_len = 1;
}
if (writev(f->f_file, iov, 6) < 0) {
int e = errno;
(void) close(f->f_file);
/*
* Check for EBADF on TTY's due to vhangup() XXX
*/
if (e == EBADF && f->f_type != F_FILE) {
f->f_file = open(f->f_un.f_fname, O_WRONLY|O_APPEND);
if (f->f_file < 0) {
f->f_type = F_UNUSED;
logerror(f->f_un.f_fname);
}
untty();
} else {
f->f_type = F_UNUSED;
errno = e;
logerror(f->f_un.f_fname);
}
} else if (flags & SYNC_FILE)
(void) fsync(f->f_file);
break;
case F_USERS:
case F_WALL:
dprintf("\n");
v->iov_base = "\r\n";
v->iov_len = 2;
wallmsg(f, iov);
break;
}
}
(void) sigsetmask(omask);
}
/*
* WALLMSG -- Write a message to the world at large
*
* Write the specified message to either the entire
* world, or a list of approved users.
*/
wallmsg(f, iov)
register struct filed *f;
struct iovec *iov;
{
register char *p;
register int i;
int ttyf, len;
FILE *uf;
static int reenter = 0;
struct utmp ut;
time_t now;
char greetings[200];
if (reenter++)
return;
/* open the user login file */
if ((uf = fopen("/etc/utmp", "r")) == NULL) {
logerror("/etc/utmp");
reenter = 0;
return;
}
(void) time(&now);
(void) sprintf(greetings,
"\r\n\7Message from syslogd@%s at %.24s ...\r\n",
iov[2].iov_base, ctime(&now));
len = strlen(greetings);
/* scan the user login file */
while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
/* is this slot used? */
if (ut.ut_name[0] == '\0')
continue;
/* should we send the message to this user? */
if (f->f_type == F_USERS) {
for (i = 0; i < MAXUNAMES; i++) {
if (!f->f_un.f_uname[i][0]) {
i = MAXUNAMES;
break;
}
if (strncmp(f->f_un.f_uname[i], ut.ut_name,
UNAMESZ) == 0)
break;
}
if (i >= MAXUNAMES)
continue;
}
/* compute the device name */
p = "/dev/12345678";
(void) strncpy(&p[5], ut.ut_line, UNAMESZ);
/*
* Might as well fork instead of using nonblocking I/O
* and doing notty().
*/
if (fork() == 0) {
if (f->f_type == F_WALL) {
iov[0].iov_base = greetings;
iov[0].iov_len = len;
iov[1].iov_len = 0;
}
(void) signal(SIGALRM, SIG_DFL);
(void) alarm(30);
/* open the terminal */
ttyf = open(p, O_WRONLY);
if (ttyf >= 0) {
struct stat statb;
if (fstat(ttyf, &statb) == 0 &&
(statb.st_mode & S_IWRITE))
(void) writev(ttyf, iov, 6);
}
exit(0);
}
}
/* close the user login file */
(void) fclose(uf);
reenter = 0;
}
void
reapchild()
{
union wait status;
while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
;
}
/*
* Return a printable representation of a host address.
*/
char *
cvthname(f)
struct sockaddr_in *f;
{
register char *p;
register struct hashent *h, *last;
struct hostent *hp;
unsigned long addr;
extern char *inet_ntoa();
dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
if (f->sin_family != AF_INET) {
dprintf("Malformed from address\n");
return ("???");
}
/*
* First look in the hash table, and return if
* found. Otherwise malloc a new entry, chain onto
* the end, and do a real host name lookup. Returns
* a pointer to the string part of the table entry.
* Note the parameter must be treated as an UNSIGNED
* integer.
*/
addr = *(unsigned long *)(&f->sin_addr);
h = Table[addr % HASHSIZE];
last = NULL;
while (h != NULL) {
if (h->addr == addr)
return (h->name);
last = h;
h = h->next;
}
h = (struct hashent *)malloc(sizeof (struct hashent));
if (h == NULL)
return (inet_ntoa(f->sin_addr));
h->addr = addr;
h->next = NULL;
if (last == NULL)
Table[addr % HASHSIZE] = h;
else
last->next = h;
hp = gethostbyaddr((char *)&f->sin_addr, 4, AF_INET);
if (hp == NULL) {
dprintf("Host name for your address (%s) unknown\n",
inet_ntoa(f->sin_addr));
(void) strncpy(h->name, inet_ntoa(f->sin_addr),
sizeof (h->name));
} else {
if ((p = index(hp->h_name, '.')) &&
strcmp(p + 1, LocalDomain) == 0)
*p = '\0';
(void) strncpy(h->name, hp->h_name, sizeof (h->name));
}
return (h->name);
}
int curalarm; /* current alarm value */
/*
* If the alarm is more than "secs" seconds in the future, set it to "secs"
* seconds. Adjust any timers by subtracting the time elapsed since the last
* "alarm" call.
*/
setalarm(secs)
int secs;
{
register int alarmval;
register int elapsed;
alarmval = alarm((unsigned)0);
elapsed = curalarm - alarmval;
dprintf("setalarm: curalarm %d alarmval %d\n", curalarm, alarmval);
if (PrevCount > 0)
FlushTimer -= elapsed;
if (Marking)
MarkTimer -= elapsed;
if (secs < alarmval || alarmval == 0)
curalarm = secs;
else
curalarm = alarmval;
(void) alarm((unsigned)curalarm);
dprintf("Next alarm in %d seconds\n", curalarm);
}
/*
* SIGALRM catcher: adjust the timers, call the appropriate timeout routines,
* and set up the next alarm.
*/
void
doalarm()
{
dprintf("doalarm: FlushTimer %d MarkTimer %d curalarm %d\n",
FlushTimer, MarkTimer, curalarm);
if (PrevCount > 0) {
FlushTimer -= curalarm;
if (FlushTimer <= 0)
flushmsg();
}
if (Marking) {
MarkTimer -= curalarm;
if (MarkTimer <= 0) {
logmsg(LOG_INFO, "-- MARK --", LocalHostName,
ADDDATE|MARK);
MarkTimer = MarkInterval * 60;
}
}
curalarm = 0;
if (FlushTimer > 0)
curalarm = FlushTimer;
if (Marking && MarkTimer > 0
&& (MarkTimer < curalarm || curalarm == 0))
curalarm = MarkTimer;
(void) alarm((unsigned)curalarm);
dprintf("Next alarm in %d seconds\n", curalarm);
}
flushmsg()
{
FlushTimer = 0;
if (PrevCount == 0)
return;
if (PrevCount > 1)
(void) sprintf(PrevLine+16, "last message repeated %d times",
PrevCount);
PrevCount = 0;
logmsg(PrevPri, PrevLine, PrevHost, PrevFlags|NOCOPY);
PrevLine[0] = '\0';
}
/*
* Print syslogd errors some place.
*/
logerror(type)
char *type;
{
char buf[100];
if (errno == 0)
(void) sprintf(buf, "syslogd: %s", type);
else if ((unsigned) errno > sys_nerr)
(void) sprintf(buf, "syslogd: %s: error %d", type, errno);
else
(void) sprintf(buf, "syslogd: %s: %s", type, sys_errlist[errno]);
errno = 0;
dprintf("%s\n", buf);
logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
}
void
die(sig)
{
char buf[100];
if (sig) {
dprintf("syslogd: going down on signal %d\n", sig);
flushmsg();
(void) sprintf(buf, "going down on signal %d", sig);
errno = 0;
logerror(buf);
}
(void) unlink(LogName);
exit(0);
}
/*
* INIT -- Initialize syslogd from configuration table
*/
void
init()
{
register int i;
register FILE *cf;
register struct filed *f;
register char *p;
char cline[BUFSIZ];
dprintf("init\n");
/* flush any pending output */
flushmsg();
/*
* Close all open log files.
*/
Initialized = 0;
for (f = Files; f < &Files[NLOGS]; f++) {
switch (f->f_type) {
case F_FILE:
case F_TTY:
case F_FORW:
case F_CONSOLE:
(void) close(f->f_file);
f->f_type = F_UNUSED;
break;
}
}
/* get the list of my addresses */
getmyaddr();
/* open the configuration file */
if ((cf = fopen(ConfFile, "r")) == NULL) {
nofile:
dprintf("cannot open %s\n", ConfFile);
cfline("*.ERR\t/dev/console", 0, &Files[0]);
cfline("*.PANIC\t*", 0, &Files[1]);
return;
}
/*
* Run the configuration file through m4 to handle any ifdefs.
*/
(void) fclose(cf);
(void) sprintf(cline, "echo '%s' | /usr/bin/m4 - %s",
ismyaddr(gethostbyname("loghost")) ? "define(LOGHOST, 1)" : "",
ConfFile);
if ((cf = popen(cline, "r")) == NULL) {
goto nofile;
}
/*
* Foreach line in the conf table, open that file.
*/
f = Files;
i = 0;
while (fgets(cline, sizeof cline, cf) != NULL && f < &Files[NLOGS]) {
i++;
/* check for end-of-section */
if (cline[0] == '\n' || cline[0] == '#')
continue;
/* strip off newline character */
p = index(cline, '\n');
if (p)
*p = '\0';
cfline(cline, i, f++);
}
/* close the configuration file */
(void) fclose(cf);
Initialized = 1;
if (Debug) {
for (f = Files; f < &Files[NLOGS]; f++) {
for (i = 0; i <= LOG_NFACILITIES; i++)
if (f->f_pmask[i] == NOPRI)
(void) printf("X ");
else
(void) printf("%d ", f->f_pmask[i]);
(void) printf("%s: ", TypeNames[f->f_type]);
switch (f->f_type) {
case F_FILE:
case F_TTY:
case F_CONSOLE:
(void) printf("%s", f->f_un.f_fname);
break;
case F_FORW:
(void) printf("%s", f->f_un.f_forw.f_hname);
break;
case F_USERS:
for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
(void) printf("%s, ",
f->f_un.f_uname[i]);
break;
}
(void) printf("\n");
}
}
/*
* See if marks are to be written to any files. If so, set up a
* timeout for marks.
*/
Marking = 0;
for (f = Files; f < &Files[NLOGS]; f++) {
if (f->f_type != F_UNUSED
&& f->f_pmask[LOG_NFACILITIES] != NOPRI)
Marking = 1;
}
if (Marking) {
i = sigblock(sigmask(SIGALRM));
setalarm(MarkInterval * 60);
(void) sigsetmask(i);
}
logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
dprintf("syslogd: restarted\n");
}
/*
* Crack a configuration file line
*/
struct code {
char *c_name;
int c_val;
};
struct code PriNames[] = {
"panic", LOG_EMERG,
"emerg", LOG_EMERG,
"alert", LOG_ALERT,
"crit", LOG_CRIT,
"err", LOG_ERR,
"error", LOG_ERR,
"warn", LOG_WARNING,
"warning", LOG_WARNING,
"notice", LOG_NOTICE,
"info", LOG_INFO,
"debug", LOG_DEBUG,
"none", NOPRI,
NULL, -1
};
struct code FacNames[] = {
"kern", LOG_KERN,
"user", LOG_USER,
"mail", LOG_MAIL,
"daemon", LOG_DAEMON,
"auth", LOG_AUTH,
"security", LOG_AUTH,
"mark", LOG_MARK,
"syslog", LOG_SYSLOG,
"lpr", LOG_LPR,
"news", LOG_NEWS,
"uucp", LOG_UUCP,
"cron", LOG_CRON,
"local0", LOG_LOCAL0,
"local1", LOG_LOCAL1,
"local2", LOG_LOCAL2,
"local3", LOG_LOCAL3,
"local4", LOG_LOCAL4,
"local5", LOG_LOCAL5,
"local6", LOG_LOCAL6,
"local7", LOG_LOCAL7,
NULL, -1
};
cfline(line, lineno, f)
char *line;
int lineno;
register struct filed *f;
{
register char *p;
register char *q;
register int i;
char *bp;
int pri;
struct hostent *hp;
char buf[MAXLINE];
char xbuf[200];
dprintf("cfline(%s)\n", line);
errno = 0; /* keep sys_errlist stuff out of logerror messages */
/* clear out file entry */
bzero((char *) f, sizeof *f);
for (i = 0; i <= LOG_NFACILITIES; i++)
f->f_pmask[i] = NOPRI;
/* scan through the list of selectors */
for (p = line; *p && *p != '\t';) {
/* find the end of this facility name list */
for (q = p; *q && *q != '\t' && *q++ != '.'; )
continue;
/* collect priority name */
for (bp = buf; *q && !index("\t,;", *q); )
*bp++ = *q++;
*bp = '\0';
/* skip cruft */
while (index(", ;", *q))
q++;
/* decode priority name */
pri = decode(buf, PriNames);
if (pri < 0) {
(void) sprintf(xbuf, "line %d: unknown priority name \"%s\"",
lineno, buf);
logerror(xbuf);
return;
}
/* scan facilities */
while (*p && !index("\t.;", *p)) {
for (bp = buf; *p && !index("\t,;.", *p); )
*bp++ = *p++;
*bp = '\0';
if (*buf == '*')
for (i = 0; i < LOG_NFACILITIES; i++)
f->f_pmask[i] = pri;
else {
i = decode(buf, FacNames);
if (i < 0) {
(void) sprintf(xbuf, "line %d: unknown facility name \"%s\"",
lineno, buf);
logerror(xbuf);
return;
}
f->f_pmask[i >> 3] = pri;
}
while (*p == ',' || *p == ' ')
p++;
}
p = q;
}
/* skip to action part */
while (*p == '\t' || *p == ' ')
p++;
switch (*p)
{
case '\0':
(void) sprintf(xbuf, "line %d: no action part", lineno);
errno = 0;
logerror(xbuf);
break;
case '@':
if (!InetInuse)
break;
(void) strcpy(f->f_un.f_forw.f_hname, ++p);
hp = gethostbyname(p);
if (hp == NULL) {
(void) sprintf(xbuf, "line %d: unknown host %s",
lineno, p);
errno = 0;
logerror(xbuf);
break;
}
if (ismyaddr(hp)) {
(void) sprintf(xbuf,
"line %d: host %s is this host - logging loop",
lineno, p);
errno = 0;
logerror(xbuf);
break;
}
bzero((char *) &f->f_un.f_forw.f_addr,
sizeof f->f_un.f_forw.f_addr);
f->f_un.f_forw.f_addr.sin_family = AF_INET;
f->f_un.f_forw.f_addr.sin_port = LogPort;
bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length);
f->f_file = socket(AF_INET, SOCK_DGRAM, 0);
if (f->f_file < 0) {
logerror("socket");
break;
}
f->f_type = F_FORW;
break;
case '/':
(void) strcpy(f->f_un.f_fname, p);
if ((f->f_file = open(p, O_WRONLY|O_APPEND)) < 0) {
logerror(p);
break;
}
if (isatty(f->f_file)) {
f->f_type = F_TTY;
untty();
}
else
f->f_type = F_FILE;
if (strcmp(p, ctty) == 0)
f->f_type = F_CONSOLE;
break;
case '*':
f->f_type = F_WALL;
break;
default:
for (i = 0; i < MAXUNAMES && *p; i++) {
for (q = p; *q && *q != ','; )
q++;
(void) strncpy(f->f_un.f_uname[i], p, UNAMESZ);
if ((q - p) > UNAMESZ)
f->f_un.f_uname[i][UNAMESZ] = '\0';
else
f->f_un.f_uname[i][q - p] = '\0';
while (*q == ',' || *q == ' ')
q++;
p = q;
}
f->f_type = F_USERS;
break;
}
}
/*
* Decode a symbolic name to a numeric value
*/
decode(name, codetab)
char *name;
struct code *codetab;
{
register struct code *c;
register char *p;
char buf[40];
if (isdigit(*name))
return (atoi(name));
(void) strcpy(buf, name);
for (p = buf; *p; p++)
if (isupper(*p))
*p = tolower(*p);
for (c = codetab; c->c_name; c++)
if (!strcmp(buf, c->c_name))
return (c->c_val);
return (-1);
}
char addr_buf[BUFSIZ];
struct ifconf ifc;
getmyaddr()
{
int s;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
logerror("socket");
return;
}
ifc.ifc_len = sizeof (addr_buf);
ifc.ifc_buf = addr_buf;
if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
logerror("ioctl (get interface configuration)");
return;
}
(void) close(s);
}
ismyaddr(hp)
register struct hostent *hp;
{
register struct ifreq *ifr;
register char **ap;
register int len;
if (hp == NULL)
return (0);
ifr = ifc.ifc_req;
for (len = ifc.ifc_len; len; len -= sizeof (struct ifreq)) {
if (hp->h_addrtype == ifr->ifr_addr.sa_family &&
hp->h_addrtype == AF_INET) {
for (ap = hp->h_addr_list; *ap; ap++) {
register struct sockaddr_in *ifin;
ifin = (struct sockaddr_in *)&ifr->ifr_addr;
if (bcmp(*ap, (char *)&ifin->sin_addr,
hp->h_length) == 0)
return (1);
}
}
ifr++;
}
return (0);
}
Current thread:
- [Tim Newsham: ] Tim Newsham (Oct 02)
- <Possible follow-ups>
- [Tim Newsham: ] Tim Newsham (Oct 02)
- [Tim Newsham: ] Tim Newsham (Oct 02)
- [Tim Newsham: ] Brent Chapman (Oct 02)
- [Tim Newsham: ] Brent Chapman (Oct 02)
