1779 lines
39 KiB
C
Executable File
1779 lines
39 KiB
C
Executable File
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#pragma ident "@(#)syslogd.c 1.32 95/09/29 SMI"
|
|
|
|
#ident "@(#)syslogd.c 1.12 92/08/03 SMI" /* SVr4.0 1.7 */
|
|
|
|
/* from "@(#)syslogd.c 1.11 88/02/07 SMI"; from UCB 5.18 2/23/87 */
|
|
|
|
/*
|
|
* PROPRIETARY NOTICE (Combined)
|
|
*
|
|
* This source code is unpublished proprietary information
|
|
* constituting, or derived under license from AT&T's Unix(r) System V.
|
|
* In addition, portions of such source code were derived from Berkeley
|
|
* 4.3 BSD under license from the Regents of the University of
|
|
* California.
|
|
*
|
|
*
|
|
*
|
|
* Copyright Notice
|
|
*
|
|
* Notice of copyright on this source code product does not indicate
|
|
* publication.
|
|
*
|
|
* (c) 1986,1987,1988,1989 Sun Microsystems, Inc.
|
|
* (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
/*
|
|
* 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.
|
|
* NINLOGS -- the maximum number of inputs we can receive messages from.
|
|
*
|
|
*/
|
|
|
|
#define NLOGS 20 /* max number of log files */
|
|
#define NINLOGS 10 /* max number of inputs */
|
|
#define MAXLINE 1024 /* maximum line length */
|
|
#define DEFUPRI (LOG_USER|LOG_INFO)
|
|
#define DEFSPRI (LOG_KERN|LOG_CRIT)
|
|
#define MARKCOUNT /*10*/3 /* ratio of minor to major marks */
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <netconfig.h>
|
|
#include <netdir.h>
|
|
#include <pwd.h>
|
|
#include <tiuser.h>
|
|
#include <utmp.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/fcntl.h>
|
|
#include <sys/stropts.h>
|
|
#include <sys/syslog.h>
|
|
#include <sys/strlog.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <sys/utsname.h>
|
|
#include <sys/poll.h>
|
|
#include <sys/wait.h>
|
|
|
|
char *LogName = "/dev/log";
|
|
char *ConfFile = "/etc/syslog.conf";
|
|
char *PidFile = "/etc/syslog.pid";
|
|
char ctty[] = "/dev/console";
|
|
|
|
#define dprintf if (Debug) (void) printf
|
|
|
|
#define UNAMESZ 8 /* length of a login name */
|
|
#define UDEVSZ 12 /* length of a login device name */
|
|
#define MAXUNAMES 20 /* maximum number of user names */
|
|
|
|
#define NOPRI 0x10 /* the "no priority" priority */
|
|
#define LOG_MARK (LOG_NFACILITIES << 3) /* mark "facility" */
|
|
|
|
/*
|
|
* 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][SYS_NMLN];
|
|
struct {
|
|
char f_hname[SYS_NMLN];
|
|
struct netbuf f_addr;
|
|
} f_forw; /* forwarding address */
|
|
char f_fname[MAXPATHLEN];
|
|
} f_un;
|
|
};
|
|
|
|
typedef struct host_list {
|
|
int hl_cnt;
|
|
char **hl_hosts;
|
|
} HOST_LIST;
|
|
|
|
|
|
/*
|
|
* write lock on whole pid file
|
|
*/
|
|
flock_t flk = {F_WRLCK, 0, 0, 0};
|
|
|
|
/* 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 */
|
|
|
|
struct hashent {
|
|
struct hashent *next;
|
|
unsigned char *addr;
|
|
unsigned int len;
|
|
HOST_LIST *hlp;
|
|
};
|
|
|
|
struct hashtab {
|
|
struct hashent *list;
|
|
unsigned char idx;
|
|
};
|
|
|
|
#define TABSZ 7
|
|
|
|
struct hashtab Table[TABSZ][256]; /* idx 0 unused */
|
|
|
|
int Debug; /* debug flag */
|
|
HOST_LIST LocalHostName; /* 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 */
|
|
HOST_LIST PrevHost; /* 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 Ninputs = 0; /* number of inputs */
|
|
|
|
struct pollfd Pfd[NINLOGS];
|
|
struct netconfig Ncf[NINLOGS];
|
|
struct netbuf *Myaddrs[NINLOGS];
|
|
struct t_unitdata *Udp[NINLOGS];
|
|
struct t_uderr *Errp[NINLOGS];
|
|
|
|
void usage(), untty(), printsys(), printline(), getnets(), init();
|
|
void logmsg(), wallmsg(), doalarm(), flushmsg(), logerror();
|
|
void die(), cfline(), add();
|
|
|
|
extern int errno;
|
|
extern int t_errno, t_nerr;
|
|
extern char *t_errlist[];
|
|
extern char *optarg;
|
|
extern char *ctime();
|
|
extern time_t time();
|
|
|
|
#define bzero(ADDR, SIZE) memset((ADDR), 0, (SIZE))
|
|
#define bcopy(FROM, TO, SIZE) memcpy((TO), (FROM), (SIZE))
|
|
|
|
main(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
register int i;
|
|
int funix;
|
|
int fd;
|
|
struct utsname *up;
|
|
struct strioctl str;
|
|
char line[MAXLINE + 1];
|
|
char *uap;
|
|
|
|
while ((i = getopt(argc, argv, "df:p:m:")) != EOF) {
|
|
switch (i) {
|
|
case 'f': /* configuration file */
|
|
ConfFile = optarg;
|
|
break;
|
|
|
|
case 'd': /* debug */
|
|
Debug++;
|
|
break;
|
|
|
|
case 'p': /* path */
|
|
LogName = optarg;
|
|
break;
|
|
|
|
case 'm': /* mark interval */
|
|
MarkInterval = atoi(optarg);
|
|
break;
|
|
|
|
default:
|
|
usage();
|
|
}
|
|
}
|
|
if (optind < argc)
|
|
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();
|
|
}
|
|
up = (struct utsname *)malloc(sizeof(struct utsname));
|
|
uname(up);
|
|
LocalHostName.hl_cnt = 1;
|
|
LocalHostName.hl_hosts = (char **) malloc(sizeof (char *));
|
|
LocalHostName.hl_hosts[0] = strdup(up->nodename);
|
|
(void) free(up);
|
|
PrevHost.hl_cnt = 1;
|
|
PrevHost.hl_hosts = (char **) malloc(sizeof (char *));
|
|
PrevHost.hl_hosts[0] = (char *) malloc(SYS_NMLN);
|
|
LocalDomain = "";
|
|
(void) signal(SIGTERM, die);
|
|
(void) signal(SIGINT, Debug ? die : SIG_IGN);
|
|
(void) signal(SIGQUIT, Debug ? die : SIG_IGN);
|
|
(void) signal(SIGCHLD, SIG_IGN);
|
|
(void) signal(SIGALRM, doalarm);
|
|
(void) signal(SIGPIPE, SIG_IGN); /* In case one of our log files
|
|
* turns out to be a named pipe
|
|
*/
|
|
|
|
funix = open(LogName, O_RDONLY);
|
|
if (funix < 0) {
|
|
(void) sprintf(line, "cannot open %s", LogName);
|
|
logerror(line);
|
|
dprintf("cannot create %s (%d)\n", LogName, errno);
|
|
die(0);
|
|
}
|
|
str.ic_cmd = I_CONSLOG;
|
|
str.ic_timout = 0;
|
|
str.ic_len = 0;
|
|
str.ic_dp = NULL;
|
|
if (ioctl(funix, I_STR, &str) < 0) {
|
|
logerror("cannot register to log console messages");
|
|
dprintf("cannot register to log console messages (%d)\n" , errno);
|
|
die(0);
|
|
}
|
|
Pfd[Ninputs].fd = funix;
|
|
Pfd[Ninputs].events = POLLIN;
|
|
Ninputs++;
|
|
getnets();
|
|
/* tuck my process id away */
|
|
fd = open(PidFile, O_RDWR | O_CREAT, 0644);
|
|
if (fd >= 0) {
|
|
/*
|
|
* syslogd holds the write lock to indicate
|
|
* that it is active. If it dies, the lock
|
|
* will go away. This enables syslog to determine
|
|
* if the syslogd is really running
|
|
*
|
|
* try and aquire the write lock
|
|
*/
|
|
while (fcntl(fd, F_SETLK, &flk) == -1) {
|
|
struct flock ftst;
|
|
|
|
/*
|
|
* oops, didn't get it. Check to make sure
|
|
* that some other syslogd doesn't own it
|
|
*/
|
|
ftst.l_type = F_WRLCK;
|
|
ftst.l_whence = 0;
|
|
ftst.l_start = 0;
|
|
ftst.l_len = 0;
|
|
fcntl(fd, F_GETLK, &ftst);
|
|
if (ftst.l_type == F_WRLCK) {
|
|
(void) sprintf(line, "syslogd pid %d arlready running. Cannot start another syslogd %d", ftst.l_pid, getpid());
|
|
logerror(line);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/* fix for 1088721 - file should be 0644, not 0666 */
|
|
(void) fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
|
(void) sprintf(line, "%d\n", getpid());
|
|
write(fd, line, strlen(line) + 1);
|
|
/*
|
|
* Must reaquire the lock so that pid info gets
|
|
* written to the PidFile
|
|
*/
|
|
if (fcntl(fd, F_SETLKW, &flk) == -1) {
|
|
(void) sprintf(line, "cannot apply write lock to pid file %s", PidFile);
|
|
logerror(line);
|
|
dprintf("cannot lock pid file %s (%d)\n", PidFile, errno);
|
|
}
|
|
} else {
|
|
(void) sprintf(line, "cannot create pid file %s", PidFile);
|
|
logerror(line);
|
|
dprintf("cannot create pid file %s (%d)\n", PidFile, errno);
|
|
}
|
|
|
|
dprintf("off & running....\n");
|
|
|
|
init();
|
|
|
|
/*
|
|
* Use sigset() rather than signal() to make sure the signal is not
|
|
* temporarily marked as not caught (the old SYSV behaviour that
|
|
* signal() gives).
|
|
*/
|
|
|
|
(void) sigset(SIGHUP, init);
|
|
|
|
for (;;) {
|
|
int nfds;
|
|
struct strbuf ctl;
|
|
struct strbuf dat;
|
|
int flags = 0;
|
|
struct log_ctl hdr;
|
|
struct t_unitdata *udp;
|
|
struct t_uderr *errp;
|
|
char buf[MAXLINE+1];
|
|
char *lastline;
|
|
|
|
errno = 0;
|
|
t_errno = 0;
|
|
nfds = poll(Pfd, Ninputs, -1);
|
|
dprintf("got a message (%d, %#x)\n", nfds, Ninputs);
|
|
if (nfds == 0)
|
|
continue;
|
|
if (nfds < 0) {
|
|
if (errno != EINTR)
|
|
logerror("poll");
|
|
continue;
|
|
}
|
|
if (Pfd[0].revents & POLLIN) {
|
|
dat.maxlen = MAXLINE;
|
|
dat.buf = buf;
|
|
ctl.maxlen = sizeof(struct log_ctl);
|
|
ctl.buf = (caddr_t)&hdr;
|
|
|
|
while ((i = getmsg(Pfd[0].fd, &ctl, &dat, &flags))
|
|
== MOREDATA) {
|
|
|
|
lastline = &dat.buf[dat.len];
|
|
*lastline = '\0';
|
|
|
|
while (*lastline != '\n' && lastline != buf)
|
|
lastline--;
|
|
|
|
if (lastline != buf)
|
|
*lastline++ = '\0';
|
|
|
|
printsys(&hdr, buf);
|
|
|
|
if (lastline != buf) {
|
|
strcpy(buf, lastline);
|
|
dat.maxlen = MAXLINE - strlen(buf);
|
|
dat.buf = &buf[strlen(buf)];
|
|
} else {
|
|
dat.maxlen = MAXLINE;
|
|
dat.buf = buf;
|
|
}
|
|
}
|
|
|
|
if (i == 0 && dat.len > 0) {
|
|
dat.buf[dat.len] = '\0';
|
|
printsys(&hdr, buf);
|
|
nfds--;
|
|
} else if (i < 0 && errno != EINTR) {
|
|
logerror("klog");
|
|
(void) close(Pfd[0].fd);
|
|
Pfd[0].fd = -1;
|
|
nfds--;
|
|
}
|
|
} else if (Pfd[0].revents & (POLLNVAL|POLLHUP|POLLERR)) {
|
|
logerror("klog");
|
|
(void) close(Pfd[0].fd);
|
|
Pfd[0].fd = -1;
|
|
}
|
|
i = 1;
|
|
while (nfds > 0 && i < NINLOGS) {
|
|
if (Pfd[i].revents & POLLIN) {
|
|
udp = Udp[i];
|
|
udp->udata.buf = buf;
|
|
udp->udata.maxlen = MAXLINE;
|
|
udp->udata.len = 0;
|
|
flags = 0;
|
|
if (t_rcvudata(Pfd[i].fd, udp, &flags) < 0) {
|
|
errp = Errp[i];
|
|
if (t_errno == TLOOK) {
|
|
if (t_rcvuderr(Pfd[i].fd, errp) < 0) {
|
|
logerror("t_rcvuderr");
|
|
t_close(Pfd[i].fd);
|
|
Pfd[i].fd = -1;
|
|
}
|
|
} else {
|
|
logerror("t_rcvudata");
|
|
t_close(Pfd[i].fd);
|
|
Pfd[i].fd = -1;
|
|
}
|
|
nfds--;
|
|
continue;
|
|
}
|
|
nfds--;
|
|
if (udp->udata.len > 0) {
|
|
extern HOST_LIST *cvthname();
|
|
struct netconfig *ncp;
|
|
|
|
/* Force EOL in buffer */
|
|
buf[udp->udata.len] = '\0';
|
|
ncp = (struct netconfig *)&Ncf[i];
|
|
if ((uap = taddr2uaddr(ncp,
|
|
&udp->addr)) != (char *)NULL) {
|
|
dprintf("recieved messaged from %s\n", uap);
|
|
}
|
|
free(uap);
|
|
printline(cvthname(&udp->addr,ncp), &udp->udata);
|
|
}
|
|
} else if (Pfd[i].revents & (POLLNVAL|POLLHUP|POLLERR)) {
|
|
logerror("POLLNVAL|POLLHUP|POLLERR");
|
|
(void) t_close(Pfd[i].fd);
|
|
Pfd[i].fd = -1;
|
|
nfds--;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
usage()
|
|
{
|
|
(void) fprintf(stderr,
|
|
"usage: syslogd [-d] [-mmarkinterval] [-ppath] [-fconffile]\n");
|
|
exit(1);
|
|
}
|
|
|
|
void
|
|
untty()
|
|
{
|
|
if (!Debug)
|
|
setsid();
|
|
}
|
|
|
|
/*
|
|
* Take a raw input line, decode the message, and print the message
|
|
* on the appropriate log files.
|
|
*/
|
|
void
|
|
printline(hlp, nbp)
|
|
HOST_LIST *hlp;
|
|
struct netbuf *nbp;
|
|
{
|
|
register char *p, *q;
|
|
register int i;
|
|
register int c;
|
|
int pri;
|
|
char line[MAXLINE + 1];
|
|
|
|
/* test for special codes */
|
|
pri = DEFUPRI;
|
|
p = nbp->buf;
|
|
if (*p == '<' && isdigit(*(p+1))) {
|
|
pri = 0;
|
|
while (isdigit(*++p))
|
|
pri = 10 * pri + (*p - '0');
|
|
if (*p == '>')
|
|
++p;
|
|
if (pri <= 0 || pri >= (LOG_NFACILITIES << 3))
|
|
pri = DEFUPRI;
|
|
}
|
|
|
|
/* don't allow users to log kernel messages */
|
|
if ((pri & LOG_PRIMASK) == LOG_KERN)
|
|
pri |= LOG_USER;
|
|
|
|
q = line;
|
|
i = 0;
|
|
while ((c = *p++ & 0177) != '\0' && c != '\n' && i < MAXLINE) {
|
|
if (iscntrl(c)) {
|
|
*q++ = '^';
|
|
*q++ = c ^ 0100;
|
|
i += 2;
|
|
} else {
|
|
*q++ = c;
|
|
i++;
|
|
}
|
|
}
|
|
*q = '\0';
|
|
logmsg(hlp, pri, line, 0);
|
|
}
|
|
|
|
void
|
|
printsys(lp, msg)
|
|
struct log_ctl *lp;
|
|
char *msg;
|
|
{
|
|
register char *p, *q;
|
|
register int c;
|
|
register int i;
|
|
int flags;
|
|
time_t now;
|
|
char line[MAXLINE + 1];
|
|
|
|
(void) time(&now);
|
|
flags = SYNC_FILE; /* fsync file after write */
|
|
|
|
/*
|
|
* If "mid" and "sid" are 0 then this message came to us
|
|
* by way of writekmsg() in the kernel and has already
|
|
* been printed on the console.
|
|
*
|
|
* NOTE: This is only a convention and does not gaurantee
|
|
* that other callers have avoided using 0 for these values.
|
|
*/
|
|
if (lp->mid == 0 && lp->sid == 0)
|
|
flags |= IGN_CONS;
|
|
for (p = msg; *p != '\0'; ) {
|
|
|
|
/* extract facility */
|
|
if ((lp->pri & LOG_FACMASK) == LOG_KERN)
|
|
(void) sprintf(line, "%.15s unix: ", ctime(&now) + 4);
|
|
else
|
|
(void) sprintf(line, "");
|
|
q = line + strlen(line);
|
|
i = 0;
|
|
while (*p != '\0' && (c = *p++) != '\n' && i < MAXLINE) {
|
|
*q++ = isprint(c) ? c : ' ';
|
|
i++;
|
|
}
|
|
*q = '\0';
|
|
if (i != 0)
|
|
logmsg(&LocalHostName, lp->pri, line, flags);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Log a message to the appropriate log files, users, etc. based on
|
|
* the priority.
|
|
*/
|
|
void
|
|
logmsg(hlp, pri, msg, flags)
|
|
HOST_LIST *hlp;
|
|
int pri;
|
|
char *msg;
|
|
int flags;
|
|
{
|
|
register struct filed *f;
|
|
register int l;
|
|
register char *cp;
|
|
int fac, prilev;
|
|
time_t now;
|
|
sigset_t osigs, sigs;
|
|
char *text;
|
|
struct t_unitdata ud;
|
|
char line[MAXLINE*2]; /* watch for overflow */
|
|
char line2[MAXLINE*2];
|
|
char *eomp, *eomp2;
|
|
char *from;
|
|
int i;
|
|
int forwardingloop = 0;
|
|
char *errmsg =
|
|
" %s to %s forwarding loop detected, message not forwarded\n";
|
|
|
|
if (hlp == (HOST_LIST *)NULL)
|
|
from = "???";
|
|
else
|
|
from = hlp->hl_hosts[0];
|
|
|
|
|
|
dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", pri, flags,
|
|
from, msg);
|
|
|
|
sigemptyset(&osigs);
|
|
sigemptyset(&sigs);
|
|
sigprocmask(SIG_BLOCK, NULL, &osigs);
|
|
sigs = osigs;
|
|
sigaddset(&sigs, SIGALRM);
|
|
sigaddset(&sigs, SIGHUP);
|
|
sigprocmask(SIG_SETMASK, &sigs, NULL);
|
|
|
|
/*
|
|
* Check to see if msg looks non-standard.
|
|
*/
|
|
if ((int) 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++;
|
|
sigprocmask(SIG_SETMASK, &osigs, NULL);
|
|
return;
|
|
} else {
|
|
/* new line, save it */
|
|
flushmsg();
|
|
(void) strcpy(PrevLine, msg);
|
|
(void) strcpy(PrevHost.hl_hosts[0], from);
|
|
PrevFlags = flags;
|
|
PrevPri = pri;
|
|
}
|
|
}
|
|
|
|
(void) time(&now);
|
|
cp = line;
|
|
if (flags & ADDDATE)
|
|
strncpy(cp, ctime(&now) + 4, 15);
|
|
else
|
|
strncpy(cp, msg, 15);
|
|
line[15] = '\0';
|
|
strcat(cp, " ");
|
|
strcat(cp, from);
|
|
strcat(cp, " ");
|
|
text = cp + strlen(cp);
|
|
if (flags & ADDDATE)
|
|
strcat(cp, msg);
|
|
else
|
|
strcat(cp, msg+16);
|
|
eomp = cp + strlen(cp);
|
|
|
|
/* 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|O_NOCTTY);
|
|
|
|
if (cfd >= 0) {
|
|
untty();
|
|
strcat(cp, "\r\n");
|
|
(void) write(cfd, cp, strlen(cp));
|
|
(void) close(cfd);
|
|
}
|
|
sigprocmask(SIG_SETMASK, &osigs, NULL);
|
|
return;
|
|
}
|
|
for (f = Files; f < &Files[NLOGS]; f++) {
|
|
|
|
/* skip messages that are incorrect priority */
|
|
if (f->f_pmask[fac] < (unsigned)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;
|
|
errno = 0;
|
|
t_errno = 0;
|
|
switch (f->f_type) {
|
|
case F_UNUSED:
|
|
dprintf("\n");
|
|
break;
|
|
|
|
case F_FORW:
|
|
/*
|
|
* can not forward message if we do
|
|
* not have a host to forward to
|
|
*/
|
|
if (hlp == (HOST_LIST *)NULL)
|
|
break;
|
|
|
|
/*
|
|
* a forwarding loop is created on machines with
|
|
* multiple interfaces because the network address
|
|
* of the sender is different to the reciever even
|
|
* though it is the same machine. Instead, if the
|
|
* hostname the source and target are the same the
|
|
* message if thrown away
|
|
*/
|
|
for (i=0; i<hlp->hl_cnt; i++) {
|
|
if (strcmp(hlp->hl_hosts[i],
|
|
f->f_un.f_forw.f_hname) == 0) {
|
|
dprintf(errmsg, f->f_un.f_forw.f_hname,
|
|
hlp->hl_hosts[i]);
|
|
forwardingloop = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (forwardingloop == 1)
|
|
break;
|
|
|
|
dprintf(" %s\n", f->f_un.f_forw.f_hname);
|
|
(void) sprintf(line2, "<%d>%.15s %s", pri, cp, text);
|
|
l = strlen(line2);
|
|
if (l > MAXLINE)
|
|
l = MAXLINE;
|
|
ud.opt.buf = NULL;
|
|
ud.opt.len = 0;
|
|
ud.udata.buf = line2;
|
|
ud.udata.len = l;
|
|
ud.addr.maxlen = f->f_un.f_forw.f_addr.maxlen;
|
|
ud.addr.buf = f->f_un.f_forw.f_addr.buf;
|
|
ud.addr.len = f->f_un.f_forw.f_addr.len;
|
|
if (t_sndudata(f->f_file, &ud) < 0) {
|
|
logerror("t_sndudata");
|
|
(void) t_close(f->f_file);
|
|
f->f_type = F_UNUSED;
|
|
}
|
|
break;
|
|
|
|
case F_CONSOLE:
|
|
if (flags & IGN_CONS) {
|
|
dprintf(" (ignored)\n");
|
|
break;
|
|
}
|
|
/* fall through */
|
|
|
|
case F_TTY:
|
|
case F_FILE:
|
|
dprintf(" %s\n", f->f_un.f_fname);
|
|
if (f->f_type != F_FILE) {
|
|
strcpy(eomp, "\r\n");
|
|
} else {
|
|
if ((eomp2 = strchr(cp, '\r')) != NULL)
|
|
strcpy(eomp2, "\n");
|
|
else
|
|
strcpy(eomp, "\n");
|
|
}
|
|
if (write(f->f_file, cp, strlen(cp)) < 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|O_NOCTTY);
|
|
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");
|
|
strcpy(eomp, "\r\n");
|
|
wallmsg(f, from, cp);
|
|
break;
|
|
}
|
|
}
|
|
sigprocmask(SIG_SETMASK, &osigs, NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* WALLMSG -- Write a message to the world at large
|
|
*
|
|
* Write the specified message to either the entire
|
|
* world, or a list of approved users.
|
|
*/
|
|
void
|
|
wallmsg(f, from, msg)
|
|
register struct filed *f;
|
|
char *from;
|
|
register char *msg;
|
|
{
|
|
register int i;
|
|
register char *cp;
|
|
int ttyf, len;
|
|
static int reenter = 0;
|
|
struct utmp *utp;
|
|
time_t now;
|
|
char dev[100];
|
|
char line[MAXLINE*2];
|
|
struct stat statbuf;
|
|
|
|
dprintf("wallmsg called\n");
|
|
|
|
if (reenter++)
|
|
return;
|
|
|
|
if (access(UTMP_FILE, R_OK) != 0 || stat(UTMP_FILE, &statbuf) != 0) {
|
|
logerror(UTMP_FILE);
|
|
reenter = 0;
|
|
return;
|
|
}
|
|
else if (statbuf.st_uid != 0 || (statbuf.st_mode & 07777) != 0644) {
|
|
sprintf(line, "%s %s%s%s%s", UTMP_FILE,
|
|
"not owned by root or\n",
|
|
"not mode 644. This file must be owned by root and not writable by\n",
|
|
"anyone other than root. This alert is being dropped because of\n",
|
|
"this problem.");
|
|
logerror(line);
|
|
reenter = 0;
|
|
return;
|
|
}
|
|
|
|
if (f->f_type == F_WALL) {
|
|
(void) time(&now);
|
|
(void) sprintf(line,
|
|
"\r\n\7Message from syslogd@%s at %.24s ...\r\n",
|
|
from, ctime(&now));
|
|
(void) strcat(line, msg+16);
|
|
cp = line;
|
|
len = strlen(line);
|
|
} else {
|
|
cp = msg;
|
|
len = strlen(msg);
|
|
}
|
|
|
|
/* scan the user login file */
|
|
setutent();
|
|
while ((utp = getutent()) != NULL) {
|
|
/* is this slot used? */
|
|
if (utp->ut_name[0] == '\0' || utp->ut_line[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], utp->ut_name,
|
|
UNAMESZ) == 0)
|
|
break;
|
|
}
|
|
if (i >= MAXUNAMES)
|
|
continue;
|
|
}
|
|
|
|
/* compute the device name */
|
|
strcpy(dev, "/dev/");
|
|
(void) strncat(dev, utp->ut_line, UDEVSZ);
|
|
dprintf("write to '%s'\n", dev);
|
|
|
|
/*
|
|
* Might as well fork instead of using nonblocking I/O
|
|
* and doing notty().
|
|
*/
|
|
if (fork() == 0) {
|
|
char errorbuf[100];
|
|
|
|
(void) signal(SIGALRM, SIG_DFL);
|
|
(void) alarm(30);
|
|
/* open the terminal */
|
|
ttyf = open(dev, O_WRONLY|O_NOCTTY);
|
|
if (ttyf >= 0) {
|
|
struct stat statb;
|
|
struct passwd *pwent;
|
|
|
|
if (fstat(ttyf, &statb) != 0) {
|
|
dprintf("Can't stat '%s'\n", dev);
|
|
sprintf(errorbuf, "Can't stat '%s'", dev);
|
|
errno = 0;
|
|
logerror(errorbuf);
|
|
}
|
|
else if (!(statb.st_mode & S_IWRITE)) {
|
|
dprintf("Can't write to '%s'\n", dev);
|
|
}
|
|
else if (! isatty(ttyf)) {
|
|
dprintf("'%s' not a tty\n", dev);
|
|
sprintf(errorbuf, "'%s' not a tty", dev);
|
|
errno = 0;
|
|
logerror(errorbuf);
|
|
}
|
|
else if ((pwent = getpwuid(statb.st_uid)) == NULL) {
|
|
dprintf("Can't determine owner of '%s'\n", dev);
|
|
sprintf(errorbuf,
|
|
"Can't determine owner of '%s'", dev);
|
|
errno = 0;
|
|
logerror(errorbuf);
|
|
}
|
|
else if (strncmp(pwent->pw_name, utp->ut_name,
|
|
UNAMESZ) != 0) {
|
|
dprintf("Bad terminal owner '%s'\n", dev);
|
|
sprintf(errorbuf, "%s %s owns '%s' %s %.*s",
|
|
"Bad terminal owner;",
|
|
pwent->pw_name, dev,
|
|
"but utmp says", UNAMESZ,
|
|
utp->ut_name);
|
|
errno = 0;
|
|
logerror(errorbuf);
|
|
}
|
|
else if (write(ttyf, cp, len) != len) {
|
|
dprintf("Write failed to '%s'\n", dev);
|
|
sprintf(errorbuf, "Write failed to '%s'", dev);
|
|
errno = 0;
|
|
logerror(errorbuf);
|
|
}
|
|
}
|
|
else {
|
|
dprintf("Can't open '%s'\n", dev);
|
|
}
|
|
exit(0);
|
|
}
|
|
}
|
|
/* close the user login file */
|
|
endutent();
|
|
reenter = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Return a printable representation of a host address.
|
|
*/
|
|
HOST_LIST *
|
|
cvthname(nbp,ncp)
|
|
register struct netbuf *nbp;
|
|
register struct netconfig *ncp;
|
|
{
|
|
register char *p;
|
|
register struct hashent *h;
|
|
register int len;
|
|
struct nd_hostservlist *hsp;
|
|
struct nd_hostserv *hspp;
|
|
int i;
|
|
|
|
/*
|
|
* 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.
|
|
* We keep a hash list because the alternative borders
|
|
* on the brink of insanity.
|
|
*/
|
|
len = 1;
|
|
p = nbp->buf;
|
|
while (len < TABSZ && len <= nbp->len && Table[len][*p].idx != 0) {
|
|
p++;
|
|
}
|
|
if ((h = Table[len][*p].list) != NULL) {
|
|
for (; h; h = h->next) {
|
|
if (h->len == nbp->len &&
|
|
same(nbp->buf, h->addr, nbp->len))
|
|
return(h->hlp);
|
|
}
|
|
}
|
|
h = (struct hashent *)malloc(sizeof(struct hashent));
|
|
if (h == NULL)
|
|
return((HOST_LIST *) NULL);
|
|
h->addr = (unsigned char *)malloc(nbp->len);
|
|
if (h->addr == NULL) {
|
|
free(h);
|
|
return((HOST_LIST *) NULL);
|
|
}
|
|
memcpy(h->addr, nbp->buf, nbp->len);
|
|
h->len = nbp->len;
|
|
|
|
if (ncp->nc_semantics == NC_TPI_CLTS) {
|
|
if (netdir_getbyaddr(ncp, &hsp, nbp) == 0) {
|
|
if (hsp->h_cnt > 0) {
|
|
hspp = hsp->h_hostservs;
|
|
h->hlp = (HOST_LIST *)malloc(sizeof(HOST_LIST));
|
|
h->hlp->hl_cnt = hsp->h_cnt;
|
|
h->hlp->hl_hosts = (char **) malloc(sizeof
|
|
(char *) * (h->hlp->hl_cnt));
|
|
for (i=0; i<hsp->h_cnt; i++) {
|
|
dprintf("cvthname() found %s, %s\n",
|
|
hspp->h_host, hspp->h_serv);
|
|
h->hlp->hl_hosts[i] = strdup(hspp->h_host);
|
|
hspp++;
|
|
}
|
|
} else {
|
|
free(h->addr);
|
|
free(h);
|
|
netdir_free((void *)hsp, ND_HOSTSERVLIST);
|
|
return((HOST_LIST *) NULL);
|
|
}
|
|
netdir_free((void *)hsp, ND_HOSTSERVLIST);
|
|
}
|
|
}
|
|
|
|
h->next = Table[len][*p].list;
|
|
Table[len][*p].list = h;
|
|
return (h->hlp);
|
|
}
|
|
|
|
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(&LocalHostName, LOG_INFO, "-- MARK --",
|
|
ADDDATE|MARK);
|
|
MarkTimer = MarkInterval * 60;
|
|
}
|
|
}
|
|
curalarm = 0;
|
|
if (FlushTimer > 0)
|
|
curalarm = FlushTimer;
|
|
if (Marking && MarkTimer > 0
|
|
&& (MarkTimer < curalarm || curalarm == 0))
|
|
curalarm = MarkTimer;
|
|
|
|
/*
|
|
* Reset signal handler since the signal's disposition has
|
|
* been set to SIG_DFL (System V signals) before this routine
|
|
* is called.
|
|
*/
|
|
(void) signal(SIGALRM, (void (*)())doalarm);
|
|
(void) alarm((unsigned)curalarm);
|
|
dprintf("Next alarm in %d seconds\n", curalarm);
|
|
}
|
|
|
|
void
|
|
flushmsg()
|
|
{
|
|
FlushTimer = 0;
|
|
if (PrevCount == 0)
|
|
return;
|
|
if (PrevCount > 1)
|
|
(void) sprintf(PrevLine+16, "last message repeated %d times",
|
|
PrevCount);
|
|
PrevCount = 0;
|
|
logmsg(&PrevHost, PrevPri, PrevLine, PrevFlags|NOCOPY);
|
|
PrevLine[0] = '\0';
|
|
/* Next statement affects strcmp of previous line in logmsg routine */
|
|
PrevLine[15] = '\0'; /* Make sure match fails next time */
|
|
}
|
|
|
|
/*
|
|
* Print syslogd errors some place.
|
|
*/
|
|
void
|
|
logerror(type)
|
|
char *type;
|
|
{
|
|
char buf[MAXLINE+1];
|
|
|
|
if (t_errno == 0 || t_errno == TSYSERR) {
|
|
char *errstr;
|
|
|
|
if (errno == 0)
|
|
(void) sprintf(buf, "syslogd: %.*s", MAXLINE, type);
|
|
else if ((errstr = strerror(errno)) == (char *) NULL)
|
|
(void) sprintf(buf, "syslogd: %s: error %d", type, errno);
|
|
else
|
|
(void) sprintf(buf, "syslogd: %s: %s", type, errstr);
|
|
} else {
|
|
if ((unsigned)t_errno > t_nerr)
|
|
(void) sprintf(buf, "syslogd: %s: t_error %d", type, t_errno);
|
|
else
|
|
(void) sprintf(buf, "syslogd: %s: %s", type, t_errlist[t_errno]);
|
|
}
|
|
errno = 0;
|
|
t_errno = 0;
|
|
dprintf("%s\n", buf);
|
|
logmsg(&LocalHostName, LOG_SYSLOG|LOG_ERR, buf, 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);
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
/*
|
|
* INIT -- Initialize syslogd from configuration table
|
|
*/
|
|
void
|
|
init()
|
|
{
|
|
register int i;
|
|
register FILE *cf;
|
|
register struct filed *f;
|
|
register char *p;
|
|
sigset_t osigs, sigs;
|
|
char cline[BUFSIZ];
|
|
int iamloghost = 0;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* open the configuration file */
|
|
if ((cf = fopen(ConfFile, "r")) == NULL) {
|
|
nofile:
|
|
dprintf("cannot open %s\n", ConfFile);
|
|
cfline("*.ERR\t/dev/syscon", 0, &Files[0]);
|
|
cfline("*.PANIC\t*", 0, &Files[1]);
|
|
return;
|
|
}
|
|
|
|
if ((iamloghost = amiloghost()) == 1)
|
|
dprintf("I am loghost\n");
|
|
|
|
/*
|
|
* Run the configuration file through m4 to handle any ifdefs.
|
|
*/
|
|
(void) fclose(cf);
|
|
(void) sprintf(cline, "echo '%s' | /usr/ccs/bin/m4 - %s",
|
|
iamloghost ? "define(LOGHOST, 1)" : "", ConfFile);
|
|
if ((cf = popen(cline, "r")) == NULL) {
|
|
(void) sprintf(cline, "echo '%s' | /usr/bin/m4 - %s",
|
|
iamloghost ? "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 = strchr(cline, '\n');
|
|
if (p)
|
|
*p = '\0';
|
|
cfline(cline, i, f++);
|
|
}
|
|
|
|
/* close the configuration file */
|
|
(void) pclose(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) {
|
|
sigemptyset(&osigs);
|
|
sigemptyset(&sigs);
|
|
sigaddset(&sigs, SIGALRM);
|
|
sigprocmask(SIG_SETMASK, &sigs, &osigs);
|
|
setalarm(MarkInterval * 60);
|
|
sigprocmask(SIG_SETMASK, &osigs, NULL);
|
|
}
|
|
logmsg(&LocalHostName, LOG_SYSLOG|LOG_INFO, "syslogd: restart", 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
|
|
};
|
|
|
|
void
|
|
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;
|
|
char buf[MAXLINE];
|
|
char xbuf[200];
|
|
char ebuf[100];
|
|
|
|
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 && !strchr("\t,;", *q); )
|
|
*bp++ = *q++;
|
|
*bp = '\0';
|
|
|
|
/* skip cruft */
|
|
while (strchr(", ;", *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 && !strchr("\t.;", *p)) {
|
|
for (bp = buf; *p && !strchr("\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 '@':
|
|
(void) strcpy(f->f_un.f_forw.f_hname, ++p);
|
|
if (logforward(f, ebuf) != 0) {
|
|
(void) sprintf(xbuf, "line %d: %s", lineno, ebuf);
|
|
logerror(xbuf);
|
|
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|O_NOCTTY)) < 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);
|
|
}
|
|
|
|
ismyaddr(nbp)
|
|
register struct netbuf *nbp;
|
|
{
|
|
register int i;
|
|
register int Jinputs;
|
|
|
|
if (nbp == NULL)
|
|
return (0);
|
|
Jinputs = ((Ninputs < NINLOGS) ? Ninputs : NINLOGS);
|
|
|
|
for (i = 1; i < Jinputs; i++) {
|
|
if (nbp->len == Myaddrs[i]->len &&
|
|
same(nbp->buf, Myaddrs[i]->buf, nbp->len))
|
|
return(1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
getnets()
|
|
{
|
|
struct nd_hostserv hs;
|
|
struct netconfig *ncp;
|
|
struct nd_addrlist *nap;
|
|
struct netbuf *nbp;
|
|
int i;
|
|
void *handle;
|
|
char *uap;
|
|
|
|
hs.h_host = HOST_SELF;
|
|
hs.h_serv = "syslog";
|
|
|
|
if ((handle = setnetconfig()) == NULL)
|
|
return;
|
|
while ((ncp = getnetconfig(handle)) != NULL) {
|
|
if (ncp->nc_semantics == NC_TPI_CLTS) {
|
|
if (netdir_getbyname(ncp, &hs, &nap) == 0) {
|
|
if (!nap)
|
|
continue;
|
|
dprintf("getnets() found %d addresses",
|
|
nap->n_cnt);
|
|
nbp = nap->n_addrs;
|
|
if (nap->n_cnt > 0)
|
|
dprintf(", they are: ");
|
|
for (i = 0; i < nap->n_cnt; i++) {
|
|
if ((uap = taddr2uaddr(ncp, nbp)) !=
|
|
(char *)NULL) {
|
|
dprintf("%s ", uap);
|
|
}
|
|
free (uap);
|
|
nbp++;
|
|
}
|
|
dprintf("\n");
|
|
|
|
nbp = nap->n_addrs;
|
|
for (i = 0; i < nap->n_cnt; i++) {
|
|
add(ncp, nbp);
|
|
nbp++;
|
|
}
|
|
netdir_free((void *)nap, ND_ADDRLIST);
|
|
}
|
|
}
|
|
}
|
|
endnetconfig(handle);
|
|
}
|
|
|
|
void
|
|
add(ncp, nbp)
|
|
struct netconfig *ncp;
|
|
struct netbuf *nbp;
|
|
{
|
|
int fd;
|
|
struct t_bind bind;
|
|
struct t_bind *bound;
|
|
|
|
if (Ninputs >= NINLOGS)
|
|
return;
|
|
fd = t_open(ncp->nc_device, O_RDWR, NULL);
|
|
if (fd < 0)
|
|
return;
|
|
memcpy(&Ncf[Ninputs],ncp,sizeof(struct netconfig));
|
|
bound = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
|
|
bind.addr = *nbp;
|
|
bind.qlen = 0;
|
|
if (t_bind(fd, &bind, bound) < 0) {
|
|
t_close(fd);
|
|
t_free((char *)bound, T_BIND);
|
|
return;
|
|
}
|
|
if ((bind.addr.len != bound->addr.len) ||
|
|
!same(bind.addr.buf, bound->addr.buf, bind.addr.len)) {
|
|
t_close(fd);
|
|
t_free((char *)bound, T_BIND);
|
|
return;
|
|
}
|
|
Udp[Ninputs] = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ADDR);
|
|
if (Udp[Ninputs] == NULL) {
|
|
t_close(fd);
|
|
t_free((char *)bound, T_BIND);
|
|
return;
|
|
}
|
|
Errp[Ninputs] = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ADDR);
|
|
if (Errp[Ninputs] == NULL) {
|
|
t_close(fd);
|
|
t_free((char *)Udp[Ninputs], T_UNITDATA);
|
|
t_free((char *)bound, T_BIND);
|
|
return;
|
|
}
|
|
Pfd[Ninputs].fd = fd;
|
|
Pfd[Ninputs].events = POLLIN;
|
|
Myaddrs[Ninputs++] = &bound->addr;
|
|
}
|
|
|
|
int
|
|
logforward(f, ebuf)
|
|
register struct filed *f;
|
|
char *ebuf;
|
|
{
|
|
struct nd_hostserv hs;
|
|
struct netbuf *nbp;
|
|
struct netconfig *ncp;
|
|
struct nd_addrlist *nap;
|
|
void *handle;
|
|
char *hp;
|
|
|
|
hp = f->f_un.f_forw.f_hname;
|
|
hs.h_host = hp;
|
|
hs.h_serv = "syslog";
|
|
|
|
if ((handle = setnetconfig()) == NULL) {
|
|
(void) strcpy(ebuf,
|
|
"unable to rewind the netconfig database");
|
|
errno = 0;
|
|
return(-1);
|
|
}
|
|
nap = (struct nd_addrlist *)NULL;
|
|
while ((ncp = getnetconfig(handle)) != NULL) {
|
|
if (ncp->nc_semantics == NC_TPI_CLTS) {
|
|
if (netdir_getbyname(ncp, &hs, &nap) == 0) {
|
|
if (!nap)
|
|
continue;
|
|
nbp = nap->n_addrs;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (nap == (struct nd_addrlist *)NULL) {
|
|
endnetconfig(handle);
|
|
(void) sprintf(ebuf, "unknown host %s", hp);
|
|
errno = 0;
|
|
return (-1);
|
|
}
|
|
if (ismyaddr(nbp)) {
|
|
netdir_free((void *)nap, ND_ADDRLIST);
|
|
endnetconfig(handle);
|
|
(void) sprintf(ebuf, "host %s is this host - logging loop",
|
|
hp);
|
|
errno = 0;
|
|
return (-1);
|
|
}
|
|
f->f_un.f_forw.f_addr.buf = malloc(nbp->len);
|
|
if (f->f_un.f_forw.f_addr.buf == NULL) {
|
|
netdir_free((void *)nap, ND_ADDRLIST);
|
|
endnetconfig(handle);
|
|
(void) strcpy(ebuf, "malloc");
|
|
return (-1);
|
|
}
|
|
bcopy(nbp->buf, f->f_un.f_forw.f_addr.buf, nbp->len);
|
|
f->f_un.f_forw.f_addr.len = nbp->len;
|
|
f->f_file = t_open(ncp->nc_device, O_RDWR, NULL);
|
|
if (f->f_file < 0) {
|
|
netdir_free((void *)nap, ND_ADDRLIST);
|
|
endnetconfig(handle);
|
|
(void) strcpy(ebuf, "t_open");
|
|
return (-1);
|
|
}
|
|
netdir_free((void *)nap, ND_ADDRLIST);
|
|
endnetconfig(handle);
|
|
if (t_bind(f->f_file, NULL, NULL) < 0) {
|
|
(void) strcpy(ebuf, "t_bind");
|
|
t_close(f->f_file);
|
|
return(-1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
amiloghost()
|
|
{
|
|
struct nd_hostserv hs;
|
|
struct netconfig *ncp;
|
|
struct nd_addrlist *nap;
|
|
struct netbuf *nbp;
|
|
int i;
|
|
void *handle;
|
|
char *uap;
|
|
struct t_bind bind;
|
|
struct t_bind *bound;
|
|
int fd;
|
|
|
|
/*
|
|
* we need to know if we are running on the loghost machine. This is
|
|
* checked by binding to the address associated with the "loghost" host
|
|
* and "syslogd" service over the connectionless transport
|
|
*/
|
|
|
|
hs.h_host = "loghost";
|
|
hs.h_serv = "syslog";
|
|
|
|
if ((handle = setnetconfig())== NULL)
|
|
return(0);
|
|
while ((ncp = getnetconfig(handle)) != NULL) {
|
|
if (ncp->nc_semantics == NC_TPI_CLTS) {
|
|
if (netdir_getbyname(ncp, &hs, &nap) == 0) {
|
|
if (!nap)
|
|
continue;
|
|
nbp = nap->n_addrs;
|
|
for (i = 0; i < nap->n_cnt; i++) {
|
|
if ((uap = taddr2uaddr(ncp, nbp))
|
|
!= (char *)NULL) {
|
|
dprintf("amiloghost() testing %s\n", uap);
|
|
}
|
|
free(uap);
|
|
|
|
fd = t_open(ncp->nc_device, O_RDWR,
|
|
NULL);
|
|
if (fd < 0)
|
|
return(0);
|
|
bound = (struct t_bind *)t_alloc(fd,
|
|
T_BIND, T_ADDR);
|
|
bind.addr = *nbp;
|
|
bind.qlen = 0;
|
|
if (t_bind(fd, &bind, bound) == 0) {
|
|
t_close(fd);
|
|
t_free((char *)bound, T_BIND);
|
|
netdir_free((void *)nap,
|
|
ND_ADDRLIST);
|
|
return(1);
|
|
} else {
|
|
t_close(fd);
|
|
t_free((char *)bound, T_BIND);
|
|
}
|
|
nbp++;
|
|
}
|
|
netdir_free((void *)nap, ND_ADDRLIST);
|
|
}
|
|
}
|
|
}
|
|
endnetconfig(handle);
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
same(a, b, n)
|
|
register char *a;
|
|
register char *b;
|
|
register int n;
|
|
{
|
|
if (n <= 0)
|
|
return(0);
|
|
while (n-- > 0)
|
|
if (*a++ != *b++)
|
|
return(0);
|
|
return(1);
|
|
}
|