syslogd.c revision 37450
1/*
2 * Copyright (c) 1983, 1988, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1983, 1988, 1993, 1994\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)syslogd.c	8.3 (Berkeley) 4/4/94";
43#endif
44static const char rcsid[] =
45	"$Id: syslogd.c,v 1.37 1998/07/02 19:35:40 guido Exp $";
46#endif /* not lint */
47
48/*
49 *  syslogd -- log system messages
50 *
51 * This program implements a system log. It takes a series of lines.
52 * Each line may have a priority, signified as "<n>" as
53 * the first characters of the line.  If this is
54 * not present, a default priority is used.
55 *
56 * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
57 * cause it to reread its configuration file.
58 *
59 * Defined Constants:
60 *
61 * MAXLINE -- the maximimum line length that can be handled.
62 * DEFUPRI -- the default priority for user messages
63 * DEFSPRI -- the default priority for kernel messages
64 *
65 * Author: Eric Allman
66 * extensive changes by Ralph Campbell
67 * more extensive changes by Eric Allman (again)
68 * Extension to log by program name as well as facility and priority
69 *   by Peter da Silva.
70 */
71
72#define	MAXLINE		1024		/* maximum line length */
73#define	MAXSVLINE	120		/* maximum saved line length */
74#define DEFUPRI		(LOG_USER|LOG_NOTICE)
75#define DEFSPRI		(LOG_KERN|LOG_CRIT)
76#define TIMERINTVL	30		/* interval for checking flush, mark */
77#define TTYMSGTIME	1		/* timed out passed to ttymsg */
78
79#include <sys/param.h>
80#include <sys/ioctl.h>
81#include <sys/stat.h>
82#include <sys/wait.h>
83#include <sys/socket.h>
84#include <sys/queue.h>
85#include <sys/uio.h>
86#include <sys/un.h>
87#include <sys/time.h>
88#include <sys/resource.h>
89#include <sys/syslimits.h>
90#include <paths.h>
91
92#include <netinet/in.h>
93#include <netdb.h>
94#include <arpa/inet.h>
95
96#include <ctype.h>
97#include <err.h>
98#include <errno.h>
99#include <fcntl.h>
100#include <regex.h>
101#include <setjmp.h>
102#include <signal.h>
103#include <stdio.h>
104#include <stdlib.h>
105#include <string.h>
106#include <sysexits.h>
107#include <unistd.h>
108#include <utmp.h>
109#include "pathnames.h"
110
111#define SYSLOG_NAMES
112#include <sys/syslog.h>
113
114const char	*ConfFile = _PATH_LOGCONF;
115const char	*PidFile = _PATH_LOGPID;
116const char	ctty[] = _PATH_CONSOLE;
117
118#define	dprintf		if (Debug) printf
119
120#define MAXUNAMES	20	/* maximum number of user names */
121
122#define MAXFUNIX       20
123
124int nfunix = 1;
125char *funixn[MAXFUNIX] = { _PATH_LOG };
126int funix[MAXFUNIX];
127
128/*
129 * Flags to logmsg().
130 */
131
132#define IGN_CONS	0x001	/* don't print on console */
133#define SYNC_FILE	0x002	/* do fsync on file after printing */
134#define ADDDATE		0x004	/* add a date to the message */
135#define MARK		0x008	/* this message is a mark */
136#define ISKERNEL	0x010	/* kernel generated message */
137
138/*
139 * This structure represents the files that will have log
140 * copies printed.
141 */
142
143struct filed {
144	struct	filed *f_next;		/* next in linked list */
145	short	f_type;			/* entry type, see below */
146	short	f_file;			/* file descriptor */
147	time_t	f_time;			/* time this was last written */
148	u_char	f_pmask[LOG_NFACILITIES+1];	/* priority mask */
149	char	*f_program;		/* program this applies to */
150	union {
151		char	f_uname[MAXUNAMES][UT_NAMESIZE+1];
152		struct {
153			char	f_hname[MAXHOSTNAMELEN+1];
154			struct sockaddr_in	f_addr;
155		} f_forw;		/* forwarding address */
156		char	f_fname[MAXPATHLEN];
157		struct {
158			char	f_pname[MAXPATHLEN];
159			pid_t	f_pid;
160		} f_pipe;
161	} f_un;
162	char	f_prevline[MAXSVLINE];		/* last message logged */
163	char	f_lasttime[16];			/* time of last occurrence */
164	char	f_prevhost[MAXHOSTNAMELEN+1];	/* host from which recd. */
165	int	f_prevpri;			/* pri of f_prevline */
166	int	f_prevlen;			/* length of f_prevline */
167	int	f_prevcount;			/* repetition cnt of prevline */
168	int	f_repeatcount;			/* number of "repeated" msgs */
169};
170
171/*
172 * Queue of about-to-be dead processes we should watch out for.
173 */
174
175TAILQ_HEAD(stailhead, deadq_entry) deadq_head;
176struct stailhead *deadq_headp;
177
178struct deadq_entry {
179	pid_t				dq_pid;
180	int				dq_timeout;
181	TAILQ_ENTRY(deadq_entry)	dq_entries;
182};
183
184/*
185 * The timeout to apply to processes waiting on the dead queue.  Unit
186 * of measure is `mark intervals', i.e. 20 minutes by default.
187 * Processes on the dead queue will be terminated after that time.
188 */
189
190#define DQ_TIMO_INIT	2
191
192typedef struct deadq_entry *dq_t;
193
194
195/*
196 * Struct to hold records of network addresses that are allowed to log
197 * to us.
198 */
199struct allowedpeer {
200	int isnumeric;
201	u_short port;
202	union {
203		struct {
204			struct in_addr addr;
205			struct in_addr mask;
206		} numeric;
207		char *name;
208	} u;
209#define a_addr u.numeric.addr
210#define a_mask u.numeric.mask
211#define a_name u.name
212};
213
214
215/*
216 * Intervals at which we flush out "message repeated" messages,
217 * in seconds after previous message is logged.  After each flush,
218 * we move to the next interval until we reach the largest.
219 */
220int	repeatinterval[] = { 30, 120, 600 };	/* # of secs before flush */
221#define	MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
222#define	REPEATTIME(f)	((f)->f_time + repeatinterval[(f)->f_repeatcount])
223#define	BACKOFF(f)	{ if (++(f)->f_repeatcount > MAXREPEAT) \
224				 (f)->f_repeatcount = MAXREPEAT; \
225			}
226
227/* values for f_type */
228#define F_UNUSED	0		/* unused entry */
229#define F_FILE		1		/* regular file */
230#define F_TTY		2		/* terminal */
231#define F_CONSOLE	3		/* console terminal */
232#define F_FORW		4		/* remote machine */
233#define F_USERS		5		/* list of users */
234#define F_WALL		6		/* everyone logged on */
235#define F_PIPE		7		/* pipe to program */
236
237char	*TypeNames[8] = {
238	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
239	"FORW",		"USERS",	"WALL",		"PIPE"
240};
241
242struct	filed *Files;
243struct	filed consfile;
244
245int	Debug;			/* debug flag */
246char	LocalHostName[MAXHOSTNAMELEN+1];	/* our hostname */
247char	*LocalDomain;		/* our local domain name */
248int	finet;			/* Internet datagram socket */
249int	LogPort;		/* port number for INET connections */
250int	Initialized = 0;	/* set when we have initialized ourselves */
251int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
252int	MarkSeq = 0;		/* mark sequence number */
253int	SecureMode = 0;		/* when true, receive only unix domain socks */
254u_int	Vogons = 0;		/* packets arriving in SecureMode */
255
256char	bootfile[MAXLINE+1];	/* booted kernel file */
257
258struct allowedpeer *AllowedPeers;
259int	NumAllowed = 0;		/* # of AllowedPeer entries */
260
261int	allowaddr __P((char *));
262void	cfline __P((char *, struct filed *, char *));
263char   *cvthname __P((struct sockaddr_in *));
264void	deadq_enter __P((pid_t));
265int	decode __P((const char *, CODE *));
266void	die __P((int));
267void	domark __P((int));
268void	fprintlog __P((struct filed *, int, char *));
269void	init __P((int));
270void	logerror __P((const char *));
271void	logmsg __P((int, char *, char *, int));
272void	printline __P((char *, char *));
273void	printsys __P((char *));
274int	p_open __P((char *, pid_t *));
275void	reapchild __P((int));
276char   *ttymsg __P((struct iovec *, int, char *, int));
277static void	usage __P((void));
278int	validate __P((struct sockaddr_in *, const char *));
279void	wallmsg __P((struct filed *, struct iovec *));
280int	waitdaemon __P((int, int, int));
281void	timedout __P((int));
282
283int
284main(argc, argv)
285	int argc;
286	char *argv[];
287{
288	int ch, i, l, fklog, len;
289	struct sockaddr_un sunx, fromunix;
290	struct sockaddr_in sin, frominet;
291	FILE *fp;
292	char *p, *hname, line[MAXLINE + 1];
293	struct timeval tv, *tvp;
294	pid_t ppid;
295
296	while ((ch = getopt(argc, argv, "a:dl:sf:m:p:")) != -1)
297		switch(ch) {
298		case 'd':		/* debug */
299			Debug++;
300			break;
301		case 'a':		/* allow specific network addresses only */
302			if (allowaddr(optarg) == -1)
303				usage();
304			break;
305		case 'f':		/* configuration file */
306			ConfFile = optarg;
307			break;
308		case 'm':		/* mark interval */
309			MarkInterval = atoi(optarg) * 60;
310			break;
311		case 'p':		/* path */
312			funixn[0] = optarg;
313			break;
314		case 's':		/* no network mode */
315			SecureMode++;
316			break;
317		case 'l':
318			if (nfunix < MAXFUNIX)
319				funixn[nfunix++] = optarg;
320			else
321				fprintf(stderr,
322				   "syslogd: out of descriptors, ignoring %s\n",
323					optarg);
324			break;
325		case '?':
326		default:
327			usage();
328		}
329	if ((argc -= optind) != 0)
330		usage();
331
332	if (!Debug) {
333		ppid = waitdaemon(0, 0, 30);
334		if (ppid < 0)
335			err(1, "could not become daemon");
336	} else
337		setlinebuf(stdout);
338
339	if (NumAllowed)
340		endservent();
341
342	consfile.f_type = F_CONSOLE;
343	(void)strcpy(consfile.f_un.f_fname, ctty + sizeof _PATH_DEV - 1);
344	(void)gethostname(LocalHostName, sizeof(LocalHostName));
345	if ((p = strchr(LocalHostName, '.')) != NULL) {
346		*p++ = '\0';
347		LocalDomain = p;
348	} else
349		LocalDomain = "";
350	(void)strcpy(bootfile, getbootfile());
351	(void)signal(SIGTERM, die);
352	(void)signal(SIGINT, Debug ? die : SIG_IGN);
353	(void)signal(SIGQUIT, Debug ? die : SIG_IGN);
354	(void)signal(SIGCHLD, reapchild);
355	(void)signal(SIGALRM, domark);
356	(void)signal(SIGPIPE, SIG_IGN);	/* We'll catch EPIPE instead. */
357	(void)alarm(TIMERINTVL);
358
359	TAILQ_INIT(&deadq_head);
360
361#ifndef SUN_LEN
362#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
363#endif
364	for (i = 0; i < nfunix; i++) {
365		memset(&sunx, 0, sizeof(sunx));
366		sunx.sun_family = AF_UNIX;
367		(void)strncpy(sunx.sun_path, funixn[i], sizeof(sunx.sun_path));
368		funix[i] = socket(AF_UNIX, SOCK_DGRAM, 0);
369		if (funix[i] < 0 ||
370		    bind(funix[i], (struct sockaddr *)&sunx,
371			 SUN_LEN(&sunx)) < 0 ||
372		    chmod(funixn[i], 0666) < 0) {
373			(void) snprintf(line, sizeof line,
374					"cannot create %s", funixn[i]);
375			logerror(line);
376			dprintf("cannot create %s (%d)\n", funixn[i], errno);
377			if (i == 0)
378				die(0);
379		}
380	}
381	finet = socket(AF_INET, SOCK_DGRAM, 0);
382	if (finet >= 0) {
383		struct servent *sp;
384
385		sp = getservbyname("syslog", "udp");
386		if (sp == NULL) {
387			errno = 0;
388			logerror("syslog/udp: unknown service");
389			die(0);
390		}
391		memset(&sin, 0, sizeof(sin));
392		sin.sin_family = AF_INET;
393		sin.sin_port = LogPort = sp->s_port;
394
395		if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
396			logerror("bind");
397			if (!Debug)
398				die(0);
399		}
400	}
401
402	if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0)
403		dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
404
405	/* tuck my process id away */
406	fp = fopen(PidFile, "w");
407	if (fp != NULL) {
408		fprintf(fp, "%d\n", getpid());
409		(void) fclose(fp);
410	}
411
412	dprintf("off & running....\n");
413
414	init(0);
415	(void)signal(SIGHUP, init);
416
417	tvp = &tv;
418	tv.tv_sec = tv.tv_usec = 0;
419
420	for (;;) {
421		fd_set readfds;
422		int nfds = 0;
423
424		FD_ZERO(&readfds);
425		if (fklog != -1) {
426			FD_SET(fklog, &readfds);
427			if (fklog > nfds)
428				nfds = fklog;
429		}
430		if (finet != -1) {
431			FD_SET(finet, &readfds);
432			if (finet > nfds)
433				nfds = finet;
434		}
435		for (i = 0; i < nfunix; i++) {
436			if (funix[i] != -1) {
437				FD_SET(funix[i], &readfds);
438				if (funix[i] > nfds)
439					nfds = funix[i];
440			}
441		}
442
443		/*dprintf("readfds = %#x\n", readfds);*/
444		nfds = select(nfds+1, &readfds, (fd_set *)NULL,
445			      (fd_set *)NULL, tvp);
446		if (nfds == 0) {
447			if (tvp) {
448				tvp = NULL;
449				if (ppid != 1)
450					kill(ppid, SIGALRM);
451			}
452			continue;
453		}
454		if (nfds < 0) {
455			if (errno != EINTR)
456				logerror("select");
457			continue;
458		}
459		/*dprintf("got a message (%d, %#x)\n", nfds, readfds);*/
460		if (fklog != -1 && FD_ISSET(fklog, &readfds)) {
461			i = read(fklog, line, MAXLINE - 1);
462			if (i > 0) {
463				line[i] = '\0';
464				printsys(line);
465			} else if (i < 0 && errno != EINTR) {
466				logerror("klog");
467				fklog = -1;
468			}
469		}
470		if (finet != -1 && FD_ISSET(finet, &readfds)) {
471			len = sizeof(frominet);
472			l = recvfrom(finet, line, MAXLINE, 0,
473			    (struct sockaddr *)&frominet, &len);
474			if (SecureMode) {
475				Vogons++;
476				if (!(Vogons & (Vogons - 1))) {
477					(void)snprintf(line, sizeof line,
478"syslogd: discarded %d unwanted packets in secure mode", Vogons);
479					logmsg(LOG_SYSLOG|LOG_AUTH, line,
480					    LocalHostName, ADDDATE);
481				}
482			} else if (l > 0) {
483				line[l] = '\0';
484				hname = cvthname(&frominet);
485				if (validate(&frominet, hname))
486					printline(hname, line);
487			} else if (l < 0 && errno != EINTR)
488				logerror("recvfrom inet");
489		}
490		for (i = 0; i < nfunix; i++) {
491			if (funix[i] != -1 && FD_ISSET(funix[i], &readfds)) {
492				len = sizeof(fromunix);
493				l = recvfrom(funix[i], line, MAXLINE, 0,
494				    (struct sockaddr *)&fromunix, &len);
495				if (l > 0) {
496					line[l] = '\0';
497					printline(LocalHostName, line);
498				} else if (l < 0 && errno != EINTR)
499					logerror("recvfrom unix");
500			}
501		}
502	}
503}
504
505static void
506usage()
507{
508
509	fprintf(stderr, "%s\n%s\n%s\n",
510		"usage: syslogd [-ds] [-a allowed_peer] [-f config_file]",
511		"               [-m mark_interval] [-p log_socket]",
512		"               [-l log_socket]");
513	exit(1);
514}
515
516/*
517 * Take a raw input line, decode the message, and print the message
518 * on the appropriate log files.
519 */
520void
521printline(hname, msg)
522	char *hname;
523	char *msg;
524{
525	int c, pri;
526	char *p, *q, line[MAXLINE + 1];
527
528	/* test for special codes */
529	pri = DEFUPRI;
530	p = msg;
531	if (*p == '<') {
532		pri = 0;
533		while (isdigit(*++p))
534			pri = 10 * pri + (*p - '0');
535		if (*p == '>')
536			++p;
537	}
538	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
539		pri = DEFUPRI;
540
541	/* don't allow users to log kernel messages */
542	if (LOG_FAC(pri) == LOG_KERN)
543		pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
544
545	q = line;
546
547	while ((c = *p++ & 0177) != '\0' &&
548	    q < &line[sizeof(line) - 1])
549		if (iscntrl(c))
550			if (c == '\n')
551				*q++ = ' ';
552			else if (c == '\t')
553				*q++ = '\t';
554			else {
555				*q++ = '^';
556				*q++ = c ^ 0100;
557			}
558		else
559			*q++ = c;
560	*q = '\0';
561
562	logmsg(pri, line, hname, 0);
563}
564
565/*
566 * Take a raw input line from /dev/klog, split and format similar to syslog().
567 */
568void
569printsys(msg)
570	char *msg;
571{
572	int c, pri, flags;
573	char *p, *q;
574
575	for (p = msg; *p != '\0'; ) {
576		flags = ISKERNEL | SYNC_FILE | ADDDATE;	/* fsync after write */
577		pri = DEFSPRI;
578		if (*p == '<') {
579			pri = 0;
580			while (isdigit(*++p))
581				pri = 10 * pri + (*p - '0');
582			if (*p == '>')
583				++p;
584		} else {
585			/* kernel printf's come out on console */
586			flags |= IGN_CONS;
587		}
588		if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
589			pri = DEFSPRI;
590		for (q = p; *q != '\0' && *q != '\n'; q++);
591		if (*q != '\0')
592			*q++ = '\0';
593		logmsg(pri, p, LocalHostName, flags);
594		p = q;
595	}
596}
597
598time_t	now;
599
600/*
601 * Log a message to the appropriate log files, users, etc. based on
602 * the priority.
603 */
604void
605logmsg(pri, msg, from, flags)
606	int pri;
607	char *msg, *from;
608	int flags;
609{
610	struct filed *f;
611	int i, fac, msglen, omask, prilev;
612	char *timestamp;
613 	char prog[NAME_MAX+1];
614	char buf[MAXLINE+1];
615
616	dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
617	    pri, flags, from, msg);
618
619	omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
620
621	/*
622	 * Check to see if msg looks non-standard.
623	 */
624	msglen = strlen(msg);
625	if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
626	    msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
627		flags |= ADDDATE;
628
629	(void)time(&now);
630	if (flags & ADDDATE)
631		timestamp = ctime(&now) + 4;
632	else {
633		timestamp = msg;
634		msg += 16;
635		msglen -= 16;
636	}
637
638	/* skip leading blanks */
639	while(isspace(*msg)) {
640		msg++;
641		msglen--;
642	}
643
644	/* extract facility and priority level */
645	if (flags & MARK)
646		fac = LOG_NFACILITIES;
647	else
648		fac = LOG_FAC(pri);
649	prilev = LOG_PRI(pri);
650
651	/* extract program name */
652	for(i = 0; i < NAME_MAX; i++) {
653		if(!isalnum(msg[i]))
654			break;
655		prog[i] = msg[i];
656	}
657	prog[i] = 0;
658
659	/* add kernel prefix for kernel messages */
660	if (flags & ISKERNEL) {
661		snprintf(buf, sizeof(buf), "%s: %s", bootfile, msg);
662		msg = buf;
663		msglen = strlen(buf);
664	}
665
666	/* log the message to the particular outputs */
667	if (!Initialized) {
668		f = &consfile;
669		f->f_file = open(ctty, O_WRONLY, 0);
670
671		if (f->f_file >= 0) {
672			fprintlog(f, flags, msg);
673			(void)close(f->f_file);
674		}
675		(void)sigsetmask(omask);
676		return;
677	}
678	for (f = Files; f; f = f->f_next) {
679		/* skip messages that are incorrect priority */
680		if (f->f_pmask[fac] < prilev ||
681		    f->f_pmask[fac] == INTERNAL_NOPRI)
682			continue;
683		/* skip messages with the incorrect program name */
684		if(f->f_program)
685			if(strcmp(prog, f->f_program) != 0)
686				continue;
687
688		if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
689			continue;
690
691		/* don't output marks to recently written files */
692		if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
693			continue;
694
695		/*
696		 * suppress duplicate lines to this file
697		 */
698		if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
699		    !strcmp(msg, f->f_prevline) &&
700		    !strcmp(from, f->f_prevhost)) {
701			(void)strncpy(f->f_lasttime, timestamp, 15);
702			f->f_prevcount++;
703			dprintf("msg repeated %d times, %ld sec of %d\n",
704			    f->f_prevcount, (long)(now - f->f_time),
705			    repeatinterval[f->f_repeatcount]);
706			/*
707			 * If domark would have logged this by now,
708			 * flush it now (so we don't hold isolated messages),
709			 * but back off so we'll flush less often
710			 * in the future.
711			 */
712			if (now > REPEATTIME(f)) {
713				fprintlog(f, flags, (char *)NULL);
714				BACKOFF(f);
715			}
716		} else {
717			/* new line, save it */
718			if (f->f_prevcount)
719				fprintlog(f, 0, (char *)NULL);
720			f->f_repeatcount = 0;
721			f->f_prevpri = pri;
722			(void)strncpy(f->f_lasttime, timestamp, 15);
723			(void)strncpy(f->f_prevhost, from,
724					sizeof(f->f_prevhost));
725			if (msglen < MAXSVLINE) {
726				f->f_prevlen = msglen;
727				(void)strcpy(f->f_prevline, msg);
728				fprintlog(f, flags, (char *)NULL);
729			} else {
730				f->f_prevline[0] = 0;
731				f->f_prevlen = 0;
732				fprintlog(f, flags, msg);
733			}
734		}
735	}
736	(void)sigsetmask(omask);
737}
738
739void
740fprintlog(f, flags, msg)
741	struct filed *f;
742	int flags;
743	char *msg;
744{
745	struct iovec iov[6];
746	struct iovec *v;
747	int l;
748	char line[MAXLINE + 1], repbuf[80], greetings[200];
749	char *msgret;
750
751	v = iov;
752	if (f->f_type == F_WALL) {
753		v->iov_base = greetings;
754		v->iov_len = snprintf(greetings, sizeof greetings,
755		    "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
756		    f->f_prevhost, ctime(&now));
757		v++;
758		v->iov_base = "";
759		v->iov_len = 0;
760		v++;
761	} else {
762		v->iov_base = f->f_lasttime;
763		v->iov_len = 15;
764		v++;
765		v->iov_base = " ";
766		v->iov_len = 1;
767		v++;
768	}
769	v->iov_base = f->f_prevhost;
770	v->iov_len = strlen(v->iov_base);
771	v++;
772	v->iov_base = " ";
773	v->iov_len = 1;
774	v++;
775
776	if (msg) {
777		v->iov_base = msg;
778		v->iov_len = strlen(msg);
779	} else if (f->f_prevcount > 1) {
780		v->iov_base = repbuf;
781		v->iov_len = sprintf(repbuf, "last message repeated %d times",
782		    f->f_prevcount);
783	} else {
784		v->iov_base = f->f_prevline;
785		v->iov_len = f->f_prevlen;
786	}
787	v++;
788
789	dprintf("Logging to %s", TypeNames[f->f_type]);
790	f->f_time = now;
791
792	switch (f->f_type) {
793	case F_UNUSED:
794		dprintf("\n");
795		break;
796
797	case F_FORW:
798		dprintf(" %s\n", f->f_un.f_forw.f_hname);
799		/* check for local vs remote messages */
800		if (strcmp(f->f_prevhost, LocalHostName))
801			l = snprintf(line, sizeof line - 1,
802			    "<%d>%.15s Forwarded from %s: %s",
803			    f->f_prevpri, iov[0].iov_base, f->f_prevhost,
804			    iov[4].iov_base);
805		else
806			l = snprintf(line, sizeof line - 1, "<%d>%.15s %s",
807			     f->f_prevpri, iov[0].iov_base, iov[4].iov_base);
808		if (l > MAXLINE)
809			l = MAXLINE;
810		if ((finet >= 0) &&
811		     (sendto(finet, line, l, 0,
812			     (struct sockaddr *)&f->f_un.f_forw.f_addr,
813			     sizeof(f->f_un.f_forw.f_addr)) != l)) {
814			int e = errno;
815			(void)close(f->f_file);
816			f->f_type = F_UNUSED;
817			errno = e;
818			logerror("sendto");
819		}
820		break;
821
822	case F_FILE:
823		dprintf(" %s\n", f->f_un.f_fname);
824		v->iov_base = "\n";
825		v->iov_len = 1;
826		if (writev(f->f_file, iov, 6) < 0) {
827			int e = errno;
828			(void)close(f->f_file);
829			f->f_type = F_UNUSED;
830			errno = e;
831			logerror(f->f_un.f_fname);
832		} else if (flags & SYNC_FILE)
833			(void)fsync(f->f_file);
834		break;
835
836	case F_PIPE:
837		dprintf(" %s\n", f->f_un.f_pipe.f_pname);
838		v->iov_base = "\n";
839		v->iov_len = 1;
840		if (f->f_un.f_pipe.f_pid == 0) {
841			if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
842						&f->f_un.f_pipe.f_pid)) < 0) {
843				f->f_type = F_UNUSED;
844				logerror(f->f_un.f_pipe.f_pname);
845				break;
846			}
847		}
848		if (writev(f->f_file, iov, 6) < 0) {
849			int e = errno;
850			(void)close(f->f_file);
851			if (f->f_un.f_pipe.f_pid > 0)
852				deadq_enter(f->f_un.f_pipe.f_pid);
853			f->f_un.f_pipe.f_pid = 0;
854			errno = e;
855			logerror(f->f_un.f_pipe.f_pname);
856		}
857		break;
858
859	case F_CONSOLE:
860		if (flags & IGN_CONS) {
861			dprintf(" (ignored)\n");
862			break;
863		}
864		/* FALLTHROUGH */
865
866	case F_TTY:
867		dprintf(" %s%s\n", _PATH_DEV, f->f_un.f_fname);
868		v->iov_base = "\r\n";
869		v->iov_len = 2;
870
871		errno = 0;	/* ttymsg() only sometimes returns an errno */
872		if ((msgret = ttymsg(iov, 6, f->f_un.f_fname, 10))) {
873			f->f_type = F_UNUSED;
874			logerror(msgret);
875		}
876		break;
877
878	case F_USERS:
879	case F_WALL:
880		dprintf("\n");
881		v->iov_base = "\r\n";
882		v->iov_len = 2;
883		wallmsg(f, iov);
884		break;
885	}
886	f->f_prevcount = 0;
887}
888
889/*
890 *  WALLMSG -- Write a message to the world at large
891 *
892 *	Write the specified message to either the entire
893 *	world, or a list of approved users.
894 */
895void
896wallmsg(f, iov)
897	struct filed *f;
898	struct iovec *iov;
899{
900	static int reenter;			/* avoid calling ourselves */
901	FILE *uf;
902	struct utmp ut;
903	int i;
904	char *p;
905	char line[sizeof(ut.ut_line) + 1];
906
907	if (reenter++)
908		return;
909	if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
910		logerror(_PATH_UTMP);
911		reenter = 0;
912		return;
913	}
914	/* NOSTRICT */
915	while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) {
916		if (ut.ut_name[0] == '\0')
917			continue;
918		strncpy(line, ut.ut_line, sizeof(ut.ut_line));
919		line[sizeof(ut.ut_line)] = '\0';
920		if (f->f_type == F_WALL) {
921			if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) != NULL) {
922				errno = 0;	/* already in msg */
923				logerror(p);
924			}
925			continue;
926		}
927		/* should we send the message to this user? */
928		for (i = 0; i < MAXUNAMES; i++) {
929			if (!f->f_un.f_uname[i][0])
930				break;
931			if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
932			    UT_NAMESIZE)) {
933				if ((p = ttymsg(iov, 6, line, TTYMSGTIME))
934								!= NULL) {
935					errno = 0;	/* already in msg */
936					logerror(p);
937				}
938				break;
939			}
940		}
941	}
942	(void)fclose(uf);
943	reenter = 0;
944}
945
946void
947reapchild(signo)
948	int signo;
949{
950	int status, code;
951	pid_t pid;
952	struct filed *f;
953	char buf[256];
954	const char *reason;
955	dq_t q;
956
957	while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) {
958		if (!Initialized)
959			/* Don't tell while we are initting. */
960			continue;
961
962		/* First, look if it's a process from the dead queue. */
963		for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries))
964			if (q->dq_pid == pid) {
965				TAILQ_REMOVE(&deadq_head, q, dq_entries);
966				free(q);
967				goto oncemore;
968			}
969
970		/* Now, look in list of active processes. */
971		for (f = Files; f; f = f->f_next)
972			if (f->f_type == F_PIPE &&
973			    f->f_un.f_pipe.f_pid == pid) {
974				(void)close(f->f_file);
975
976				errno = 0; /* Keep strerror() stuff out of logerror messages. */
977				f->f_un.f_pipe.f_pid = 0;
978				if (WIFSIGNALED(status)) {
979					reason = "due to signal";
980					code = WTERMSIG(status);
981				} else {
982					reason = "with status";
983					code = WEXITSTATUS(status);
984					if (code == 0)
985						goto oncemore; /* Exited OK. */
986				}
987				(void)snprintf(buf, sizeof buf,
988				"Logging subprocess %d (%s) exited %s %d.",
989					       pid, f->f_un.f_pipe.f_pname,
990					       reason, code);
991				logerror(buf);
992				break;
993			}
994	  oncemore:
995	}
996}
997
998/*
999 * Return a printable representation of a host address.
1000 */
1001char *
1002cvthname(f)
1003	struct sockaddr_in *f;
1004{
1005	struct hostent *hp;
1006	char *p;
1007
1008	dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
1009
1010	if (f->sin_family != AF_INET) {
1011		dprintf("Malformed from address\n");
1012		return ("???");
1013	}
1014	hp = gethostbyaddr((char *)&f->sin_addr,
1015	    sizeof(struct in_addr), f->sin_family);
1016	if (hp == 0) {
1017		dprintf("Host name for your address (%s) unknown\n",
1018			inet_ntoa(f->sin_addr));
1019		return (inet_ntoa(f->sin_addr));
1020	}
1021	if ((p = strchr(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
1022		*p = '\0';
1023	return (hp->h_name);
1024}
1025
1026void
1027domark(signo)
1028	int signo;
1029{
1030	struct filed *f;
1031	dq_t q;
1032
1033	now = time((time_t *)NULL);
1034	MarkSeq += TIMERINTVL;
1035	if (MarkSeq >= MarkInterval) {
1036		logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
1037		MarkSeq = 0;
1038	}
1039
1040	for (f = Files; f; f = f->f_next) {
1041		if (f->f_prevcount && now >= REPEATTIME(f)) {
1042			dprintf("flush %s: repeated %d times, %d sec.\n",
1043			    TypeNames[f->f_type], f->f_prevcount,
1044			    repeatinterval[f->f_repeatcount]);
1045			fprintlog(f, 0, (char *)NULL);
1046			BACKOFF(f);
1047		}
1048	}
1049
1050	/* Walk the dead queue, and see if we should signal somebody. */
1051	for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries))
1052		switch (q->dq_timeout) {
1053		case 0:
1054			/* Already signalled once, try harder now. */
1055			kill(q->dq_pid, SIGKILL);
1056			break;
1057
1058		case 1:
1059			/*
1060			 * Timed out on dead queue, send terminate
1061			 * signal.  Note that we leave the removal
1062			 * from the dead queue to reapchild(), which
1063			 * will also log the event.
1064			 */
1065			kill(q->dq_pid, SIGTERM);
1066			/* FALLTROUGH */
1067
1068		default:
1069			q->dq_timeout--;
1070		}
1071
1072	(void)alarm(TIMERINTVL);
1073}
1074
1075/*
1076 * Print syslogd errors some place.
1077 */
1078void
1079logerror(type)
1080	const char *type;
1081{
1082	char buf[512];
1083
1084	if (errno)
1085		(void)snprintf(buf,
1086		    sizeof buf, "syslogd: %s: %s", type, strerror(errno));
1087	else
1088		(void)snprintf(buf, sizeof buf, "syslogd: %s", type);
1089	errno = 0;
1090	dprintf("%s\n", buf);
1091	logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
1092}
1093
1094void
1095die(signo)
1096	int signo;
1097{
1098	struct filed *f;
1099	int was_initialized;
1100	char buf[100];
1101	int i;
1102
1103	was_initialized = Initialized;
1104	Initialized = 0;	/* Don't log SIGCHLDs. */
1105	for (f = Files; f != NULL; f = f->f_next) {
1106		/* flush any pending output */
1107		if (f->f_prevcount)
1108			fprintlog(f, 0, (char *)NULL);
1109		if (f->f_type == F_PIPE)
1110			(void)close(f->f_file);
1111	}
1112	Initialized = was_initialized;
1113	if (signo) {
1114		dprintf("syslogd: exiting on signal %d\n", signo);
1115		(void)sprintf(buf, "exiting on signal %d", signo);
1116		errno = 0;
1117		logerror(buf);
1118	}
1119	for (i = 0; i < nfunix; i++)
1120		if (funixn[i] && funix[i] != -1)
1121			(void)unlink(funixn[i]);
1122	exit(1);
1123}
1124
1125/*
1126 *  INIT -- Initialize syslogd from configuration table
1127 */
1128void
1129init(signo)
1130	int signo;
1131{
1132	int i;
1133	FILE *cf;
1134	struct filed *f, *next, **nextp;
1135	char *p;
1136	char cline[LINE_MAX];
1137 	char prog[NAME_MAX+1];
1138
1139	dprintf("init\n");
1140
1141	/*
1142	 *  Close all open log files.
1143	 */
1144	Initialized = 0;
1145	for (f = Files; f != NULL; f = next) {
1146		/* flush any pending output */
1147		if (f->f_prevcount)
1148			fprintlog(f, 0, (char *)NULL);
1149
1150		switch (f->f_type) {
1151		case F_FILE:
1152		case F_FORW:
1153		case F_CONSOLE:
1154		case F_TTY:
1155			(void)close(f->f_file);
1156			break;
1157		case F_PIPE:
1158			(void)close(f->f_file);
1159			if (f->f_un.f_pipe.f_pid > 0)
1160				deadq_enter(f->f_un.f_pipe.f_pid);
1161			f->f_un.f_pipe.f_pid = 0;
1162			break;
1163		}
1164		next = f->f_next;
1165		if(f->f_program) free(f->f_program);
1166		free((char *)f);
1167	}
1168	Files = NULL;
1169	nextp = &Files;
1170
1171	/* open the configuration file */
1172	if ((cf = fopen(ConfFile, "r")) == NULL) {
1173		dprintf("cannot open %s\n", ConfFile);
1174		*nextp = (struct filed *)calloc(1, sizeof(*f));
1175		cfline("*.ERR\t/dev/console", *nextp, "*");
1176		(*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
1177		cfline("*.PANIC\t*", (*nextp)->f_next, "*");
1178		Initialized = 1;
1179		return;
1180	}
1181
1182	/*
1183	 *  Foreach line in the conf table, open that file.
1184	 */
1185	f = NULL;
1186	strcpy(prog, "*");
1187	while (fgets(cline, sizeof(cline), cf) != NULL) {
1188		/*
1189		 * check for end-of-section, comments, strip off trailing
1190		 * spaces and newline character. #!prog is treated specially:
1191		 * following lines apply only to that program.
1192		 */
1193		for (p = cline; isspace(*p); ++p)
1194			continue;
1195		if (*p == 0)
1196			continue;
1197		if(*p == '#') {
1198			p++;
1199			if(*p!='!')
1200				continue;
1201		}
1202		if(*p=='!') {
1203			p++;
1204			while(isspace(*p)) p++;
1205			if(!*p) {
1206				strcpy(prog, "*");
1207				continue;
1208			}
1209			for(i = 0; i < NAME_MAX; i++) {
1210				if(!isalnum(p[i]))
1211					break;
1212				prog[i] = p[i];
1213			}
1214			prog[i] = 0;
1215			continue;
1216		}
1217		for (p = strchr(cline, '\0'); isspace(*--p);)
1218			continue;
1219		*++p = '\0';
1220		f = (struct filed *)calloc(1, sizeof(*f));
1221		*nextp = f;
1222		nextp = &f->f_next;
1223		cfline(cline, f, prog);
1224	}
1225
1226	/* close the configuration file */
1227	(void)fclose(cf);
1228
1229	Initialized = 1;
1230
1231	if (Debug) {
1232		for (f = Files; f; f = f->f_next) {
1233			for (i = 0; i <= LOG_NFACILITIES; i++)
1234				if (f->f_pmask[i] == INTERNAL_NOPRI)
1235					printf("X ");
1236				else
1237					printf("%d ", f->f_pmask[i]);
1238			printf("%s: ", TypeNames[f->f_type]);
1239			switch (f->f_type) {
1240			case F_FILE:
1241				printf("%s", f->f_un.f_fname);
1242				break;
1243
1244			case F_CONSOLE:
1245			case F_TTY:
1246				printf("%s%s", _PATH_DEV, f->f_un.f_fname);
1247				break;
1248
1249			case F_FORW:
1250				printf("%s", f->f_un.f_forw.f_hname);
1251				break;
1252
1253			case F_PIPE:
1254				printf("%s", f->f_un.f_pipe.f_pname);
1255				break;
1256
1257			case F_USERS:
1258				for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
1259					printf("%s, ", f->f_un.f_uname[i]);
1260				break;
1261			}
1262			if(f->f_program) {
1263				printf(" (%s)", f->f_program);
1264			}
1265			printf("\n");
1266		}
1267	}
1268
1269	logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
1270	dprintf("syslogd: restarted\n");
1271}
1272
1273/*
1274 * Crack a configuration file line
1275 */
1276void
1277cfline(line, f, prog)
1278	char *line;
1279	struct filed *f;
1280	char *prog;
1281{
1282	struct hostent *hp;
1283	int i, pri;
1284	char *bp, *p, *q;
1285	char buf[MAXLINE], ebuf[100];
1286
1287	dprintf("cfline(\"%s\", f, \"%s\")\n", line, prog);
1288
1289	errno = 0;	/* keep strerror() stuff out of logerror messages */
1290
1291	/* clear out file entry */
1292	memset(f, 0, sizeof(*f));
1293	for (i = 0; i <= LOG_NFACILITIES; i++)
1294		f->f_pmask[i] = INTERNAL_NOPRI;
1295
1296	/* save program name if any */
1297	if(prog && *prog=='*') prog = NULL;
1298	if(prog) {
1299		f->f_program = calloc(1, strlen(prog)+1);
1300		if(f->f_program) {
1301			strcpy(f->f_program, prog);
1302		}
1303	}
1304
1305	/* scan through the list of selectors */
1306	for (p = line; *p && *p != '\t';) {
1307
1308		/* find the end of this facility name list */
1309		for (q = p; *q && *q != '\t' && *q++ != '.'; )
1310			continue;
1311
1312		/* collect priority name */
1313		for (bp = buf; *q && !strchr("\t,;", *q); )
1314			*bp++ = *q++;
1315		*bp = '\0';
1316
1317		/* skip cruft */
1318		while (strchr(", ;", *q))
1319			q++;
1320
1321		/* decode priority name */
1322		if (*buf == '*')
1323			pri = LOG_PRIMASK + 1;
1324		else {
1325			pri = decode(buf, prioritynames);
1326			if (pri < 0) {
1327				(void)snprintf(ebuf, sizeof ebuf,
1328				    "unknown priority name \"%s\"", buf);
1329				logerror(ebuf);
1330				return;
1331			}
1332		}
1333
1334		/* scan facilities */
1335		while (*p && !strchr("\t.;", *p)) {
1336			for (bp = buf; *p && !strchr("\t,;.", *p); )
1337				*bp++ = *p++;
1338			*bp = '\0';
1339			if (*buf == '*')
1340				for (i = 0; i < LOG_NFACILITIES; i++)
1341					f->f_pmask[i] = pri;
1342			else {
1343				i = decode(buf, facilitynames);
1344				if (i < 0) {
1345					(void)snprintf(ebuf, sizeof ebuf,
1346					    "unknown facility name \"%s\"",
1347					    buf);
1348					logerror(ebuf);
1349					return;
1350				}
1351				f->f_pmask[i >> 3] = pri;
1352			}
1353			while (*p == ',' || *p == ' ')
1354				p++;
1355		}
1356
1357		p = q;
1358	}
1359
1360	/* skip to action part */
1361	while (*p == '\t')
1362		p++;
1363
1364	switch (*p)
1365	{
1366	case '@':
1367		(void)strcpy(f->f_un.f_forw.f_hname, ++p);
1368		hp = gethostbyname(p);
1369		if (hp == NULL) {
1370			extern int h_errno;
1371
1372			logerror(hstrerror(h_errno));
1373			break;
1374		}
1375		memset(&f->f_un.f_forw.f_addr, 0,
1376			 sizeof(f->f_un.f_forw.f_addr));
1377		f->f_un.f_forw.f_addr.sin_family = AF_INET;
1378		f->f_un.f_forw.f_addr.sin_port = LogPort;
1379		memmove(&f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length);
1380		f->f_type = F_FORW;
1381		break;
1382
1383	case '/':
1384		if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
1385			f->f_type = F_UNUSED;
1386			logerror(p);
1387			break;
1388		}
1389		if (isatty(f->f_file)) {
1390			if (strcmp(p, ctty) == 0)
1391				f->f_type = F_CONSOLE;
1392			else
1393				f->f_type = F_TTY;
1394			(void)strcpy(f->f_un.f_fname, p + sizeof _PATH_DEV - 1);
1395		} else {
1396			(void)strcpy(f->f_un.f_fname, p);
1397			f->f_type = F_FILE;
1398		}
1399		break;
1400
1401	case '|':
1402		f->f_un.f_pipe.f_pid = 0;
1403		(void)strcpy(f->f_un.f_pipe.f_pname, p + 1);
1404		f->f_type = F_PIPE;
1405		break;
1406
1407	case '*':
1408		f->f_type = F_WALL;
1409		break;
1410
1411	default:
1412		for (i = 0; i < MAXUNAMES && *p; i++) {
1413			for (q = p; *q && *q != ','; )
1414				q++;
1415			(void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
1416			if ((q - p) > UT_NAMESIZE)
1417				f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
1418			else
1419				f->f_un.f_uname[i][q - p] = '\0';
1420			while (*q == ',' || *q == ' ')
1421				q++;
1422			p = q;
1423		}
1424		f->f_type = F_USERS;
1425		break;
1426	}
1427}
1428
1429
1430/*
1431 *  Decode a symbolic name to a numeric value
1432 */
1433int
1434decode(name, codetab)
1435	const char *name;
1436	CODE *codetab;
1437{
1438	CODE *c;
1439	char *p, buf[40];
1440
1441	if (isdigit(*name))
1442		return (atoi(name));
1443
1444	for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
1445		if (isupper(*name))
1446			*p = tolower(*name);
1447		else
1448			*p = *name;
1449	}
1450	*p = '\0';
1451	for (c = codetab; c->c_name; c++)
1452		if (!strcmp(buf, c->c_name))
1453			return (c->c_val);
1454
1455	return (-1);
1456}
1457
1458/*
1459 * fork off and become a daemon, but wait for the child to come online
1460 * before returing to the parent, or we get disk thrashing at boot etc.
1461 * Set a timer so we don't hang forever if it wedges.
1462 */
1463int
1464waitdaemon(nochdir, noclose, maxwait)
1465	int nochdir, noclose, maxwait;
1466{
1467	int fd;
1468	int status;
1469	pid_t pid, childpid;
1470
1471	switch (childpid = fork()) {
1472	case -1:
1473		return (-1);
1474	case 0:
1475		break;
1476	default:
1477		signal(SIGALRM, timedout);
1478		alarm(maxwait);
1479		while ((pid = wait3(&status, 0, NULL)) != -1) {
1480			if (WIFEXITED(status))
1481				errx(1, "child pid %d exited with return code %d",
1482					pid, WEXITSTATUS(status));
1483			if (WIFSIGNALED(status))
1484				errx(1, "child pid %d exited on signal %d%s",
1485					pid, WTERMSIG(status),
1486					WCOREDUMP(status) ? " (core dumped)" :
1487					"");
1488			if (pid == childpid)	/* it's gone... */
1489				break;
1490		}
1491		exit(0);
1492	}
1493
1494	if (setsid() == -1)
1495		return (-1);
1496
1497	if (!nochdir)
1498		(void)chdir("/");
1499
1500	if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
1501		(void)dup2(fd, STDIN_FILENO);
1502		(void)dup2(fd, STDOUT_FILENO);
1503		(void)dup2(fd, STDERR_FILENO);
1504		if (fd > 2)
1505			(void)close (fd);
1506	}
1507	return (getppid());
1508}
1509
1510/*
1511 * We get a SIGALRM from the child when it's running and finished doing it's
1512 * fsync()'s or O_SYNC writes for all the boot messages.
1513 *
1514 * We also get a signal from the kernel if the timer expires, so check to
1515 * see what happened.
1516 */
1517void
1518timedout(sig)
1519	int sig __unused;
1520{
1521	int left;
1522	left = alarm(0);
1523	signal(SIGALRM, SIG_DFL);
1524	if (left == 0)
1525		errx(1, "timed out waiting for child");
1526	else
1527		exit(0);
1528}
1529
1530/*
1531 * Add `s' to the list of allowable peer addresses to accept messages
1532 * from.
1533 *
1534 * `s' is a string in the form:
1535 *
1536 *    [*]domainname[:{servicename|portnumber|*}]
1537 *
1538 * or
1539 *
1540 *    netaddr/maskbits[:{servicename|portnumber|*}]
1541 *
1542 * Returns -1 on error, 0 if the argument was valid.
1543 */
1544int
1545allowaddr(s)
1546	char *s;
1547{
1548	char *cp1, *cp2;
1549	struct allowedpeer ap;
1550	struct servent *se;
1551	regex_t re;
1552	int i;
1553
1554	if ((cp1 = strrchr(s, ':'))) {
1555		/* service/port provided */
1556		*cp1++ = '\0';
1557		if (strlen(cp1) == 1 && *cp1 == '*')
1558			/* any port allowed */
1559			ap.port = htons(0);
1560		else if ((se = getservbyname(cp1, "udp")))
1561			ap.port = se->s_port;
1562		else {
1563			ap.port = htons((int)strtol(cp1, &cp2, 0));
1564			if (*cp2 != '\0')
1565				return -1; /* port not numeric */
1566		}
1567	} else {
1568		if ((se = getservbyname("syslog", "udp")))
1569			ap.port = se->s_port;
1570		else
1571			/* sanity, should not happen */
1572			ap.port = htons(514);
1573	}
1574
1575	/* the regexp's are ugly, but the cleanest way */
1576
1577	if (regcomp(&re, "^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+(/[0-9]+)?$",
1578		    REG_EXTENDED))
1579		/* if RE compilation fails, that's an internal error */
1580		abort();
1581	if (regexec(&re, s, 0, 0, 0) == 0) {
1582		/* arg `s' is numeric */
1583		ap.isnumeric = 1;
1584		if ((cp1 = strchr(s, '/')) != NULL) {
1585			*cp1++ = '\0';
1586			i = atoi(cp1);
1587			if (i < 0 || i > 32)
1588				return -1;
1589			/* convert masklen to netmask */
1590			ap.a_mask.s_addr = htonl(~((1 << (32 - i)) - 1));
1591		}
1592		if (ascii2addr(AF_INET, s, &ap.a_addr) == -1)
1593			return -1;
1594		if (cp1 == NULL) {
1595			/* use default netmask */
1596			if (IN_CLASSA(ntohl(ap.a_addr.s_addr)))
1597				ap.a_mask.s_addr = htonl(IN_CLASSA_NET);
1598			else if (IN_CLASSB(ntohl(ap.a_addr.s_addr)))
1599				ap.a_mask.s_addr = htonl(IN_CLASSB_NET);
1600			else
1601				ap.a_mask.s_addr = htonl(IN_CLASSC_NET);
1602		}
1603	} else {
1604		/* arg `s' is domain name */
1605		ap.isnumeric = 0;
1606		ap.a_name = s;
1607	}
1608	regfree(&re);
1609
1610	if (Debug) {
1611		printf("allowaddr: rule %d: ", NumAllowed);
1612		if (ap.isnumeric) {
1613			printf("numeric, ");
1614			printf("addr = %s, ",
1615			       addr2ascii(AF_INET, &ap.a_addr, sizeof(struct in_addr), 0));
1616			printf("mask = %s; ",
1617			       addr2ascii(AF_INET, &ap.a_mask, sizeof(struct in_addr), 0));
1618		} else
1619			printf("domainname = %s; ", ap.a_name);
1620		printf("port = %d\n", ntohs(ap.port));
1621	}
1622
1623	if ((AllowedPeers = realloc(AllowedPeers,
1624				    ++NumAllowed * sizeof(struct allowedpeer)))
1625	    == NULL) {
1626		fprintf(stderr, "Out of memory!\n");
1627		exit(EX_OSERR);
1628	}
1629	memcpy(&AllowedPeers[NumAllowed - 1], &ap, sizeof(struct allowedpeer));
1630	return 0;
1631}
1632
1633/*
1634 * Validate that the remote peer has permission to log to us.
1635 */
1636int
1637validate(sin, hname)
1638	struct sockaddr_in *sin;
1639	const char *hname;
1640{
1641	int i;
1642	size_t l1, l2;
1643	char *cp, name[MAXHOSTNAMELEN];
1644	struct allowedpeer *ap;
1645
1646	if (NumAllowed == 0)
1647		/* traditional behaviour, allow everything */
1648		return 1;
1649
1650	strncpy(name, hname, sizeof name);
1651	if (strchr(name, '.') == NULL) {
1652		strncat(name, ".", sizeof name - strlen(name) - 1);
1653		strncat(name, LocalDomain, sizeof name - strlen(name) - 1);
1654	}
1655	dprintf("validate: dgram from IP %s, port %d, name %s;\n",
1656		addr2ascii(AF_INET, &sin->sin_addr, sizeof(struct in_addr), 0),
1657		ntohs(sin->sin_port), name);
1658
1659	/* now, walk down the list */
1660	for (i = 0, ap = AllowedPeers; i < NumAllowed; i++, ap++) {
1661		if (ntohs(ap->port) != 0 && ap->port != sin->sin_port) {
1662			dprintf("rejected in rule %d due to port mismatch.\n", i);
1663			continue;
1664		}
1665
1666		if (ap->isnumeric) {
1667			if ((sin->sin_addr.s_addr & ap->a_mask.s_addr)
1668			    != ap->a_addr.s_addr) {
1669				dprintf("rejected in rule %d due to IP mismatch.\n", i);
1670				continue;
1671			}
1672		} else {
1673			cp = ap->a_name;
1674			l1 = strlen(name);
1675			if (*cp == '*') {
1676				/* allow wildmatch */
1677				cp++;
1678				l2 = strlen(cp);
1679				if (l2 > l1 || memcmp(cp, &name[l1 - l2], l2) != 0) {
1680					dprintf("rejected in rule %d due to name mismatch.\n", i);
1681					continue;
1682				}
1683			} else {
1684				/* exact match */
1685				l2 = strlen(cp);
1686				if (l2 != l1 || memcmp(cp, name, l1) != 0) {
1687					dprintf("rejected in rule %d due to name mismatch.\n", i);
1688					continue;
1689				}
1690			}
1691		}
1692		dprintf("accepted in rule %d.\n", i);
1693		return 1;	/* hooray! */
1694	}
1695	return 0;
1696}
1697
1698/*
1699 * Fairly similar to popen(3), but returns an open descriptor, as
1700 * opposed to a FILE *.
1701 */
1702int
1703p_open(prog, pid)
1704	char *prog;
1705	pid_t *pid;
1706{
1707	int pfd[2], nulldesc, i;
1708	sigset_t omask, mask;
1709	char *argv[4]; /* sh -c cmd NULL */
1710	char errmsg[200];
1711
1712	if (pipe(pfd) == -1)
1713		return -1;
1714	if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1)
1715		/* we are royally screwed anyway */
1716		return -1;
1717
1718	sigemptyset(&mask);
1719	sigaddset(&mask, SIGALRM);
1720	sigaddset(&mask, SIGHUP);
1721	sigprocmask(SIG_BLOCK, &mask, &omask);
1722	switch ((*pid = fork())) {
1723	case -1:
1724		sigprocmask(SIG_SETMASK, &omask, 0);
1725		close(nulldesc);
1726		return -1;
1727
1728	case 0:
1729		argv[0] = "sh";
1730		argv[1] = "-c";
1731		argv[2] = prog;
1732		argv[3] = NULL;
1733
1734		alarm(0);
1735		(void)setsid();	/* Avoid catching SIGHUPs. */
1736
1737		/*
1738		 * Throw away pending signals, and reset signal
1739		 * behaviour to standard values.
1740		 */
1741		signal(SIGALRM, SIG_IGN);
1742		signal(SIGHUP, SIG_IGN);
1743		sigprocmask(SIG_SETMASK, &omask, 0);
1744		signal(SIGPIPE, SIG_DFL);
1745		signal(SIGQUIT, SIG_DFL);
1746		signal(SIGALRM, SIG_DFL);
1747		signal(SIGHUP, SIG_DFL);
1748
1749		dup2(pfd[0], STDIN_FILENO);
1750		dup2(nulldesc, STDOUT_FILENO);
1751		dup2(nulldesc, STDERR_FILENO);
1752		for (i = getdtablesize(); i > 2; i--)
1753			(void) close(i);
1754
1755		(void) execvp(_PATH_BSHELL, argv);
1756		_exit(255);
1757	}
1758
1759	sigprocmask(SIG_SETMASK, &omask, 0);
1760	close(nulldesc);
1761	close(pfd[0]);
1762	/*
1763	 * Avoid blocking on a hung pipe.  With O_NONBLOCK, we are
1764	 * supposed to get an EWOULDBLOCK on writev(2), which is
1765	 * caught by the logic above anyway, which will in turn close
1766	 * the pipe, and fork a new logging subprocess if necessary.
1767	 * The stale subprocess will be killed some time later unless
1768	 * it terminated itself due to closing its input pipe (so we
1769	 * get rid of really dead puppies).
1770	 */
1771	if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
1772		/* This is bad. */
1773		(void)snprintf(errmsg, sizeof errmsg,
1774			       "Warning: cannot change pipe to PID %d to "
1775			       "non-blocking behaviour.",
1776			       (int)*pid);
1777		logerror(errmsg);
1778	}
1779	return pfd[1];
1780}
1781
1782void
1783deadq_enter(pid)
1784	pid_t pid;
1785{
1786	dq_t p;
1787
1788	p = malloc(sizeof(struct deadq_entry));
1789	if (p == 0) {
1790		errno = 0;
1791		logerror("panic: out of virtual memory!");
1792		exit(1);
1793	}
1794
1795	p->dq_pid = pid;
1796	p->dq_timeout = DQ_TIMO_INIT;
1797	TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries);
1798}
1799