syslogd.c revision 81977
150276Speter/*
250276Speter * Copyright (c) 1983, 1988, 1993, 1994
3166124Srafan *	The Regents of the University of California.  All rights reserved.
450276Speter *
550276Speter * Redistribution and use in source and binary forms, with or without
650276Speter * modification, are permitted provided that the following conditions
750276Speter * are met:
850276Speter * 1. Redistributions of source code must retain the above copyright
950276Speter *    notice, this list of conditions and the following disclaimer.
1050276Speter * 2. Redistributions in binary form must reproduce the above copyright
1150276Speter *    notice, this list of conditions and the following disclaimer in the
1250276Speter *    documentation and/or other materials provided with the distribution.
1350276Speter * 3. All advertising materials mentioning features or use of this software
1450276Speter *    must display the following acknowledgement:
1550276Speter *	This product includes software developed by the University of
1650276Speter *	California, Berkeley and its contributors.
1750276Speter * 4. Neither the name of the University nor the names of its contributors
1850276Speter *    may be used to endorse or promote products derived from this software
1950276Speter *    without specific prior written permission.
2050276Speter *
2150276Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2250276Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2350276Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2450276Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2550276Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2650276Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2750276Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2850276Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2950276Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30166124Srafan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3150276Speter * SUCH DAMAGE.
3250276Speter */
3350276Speter
3450276Speter#ifndef lint
3550276Speterstatic const char copyright[] =
3650276Speter"@(#) Copyright (c) 1983, 1988, 1993, 1994\n\
3750276Speter	The Regents of the University of California.  All rights reserved.\n";
3850276Speter#endif /* not lint */
3950276Speter
4050276Speter#ifndef lint
4150276Speter#if 0
4250276Speterstatic char sccsid[] = "@(#)syslogd.c	8.3 (Berkeley) 4/4/94";
4350276Speter#endif
4450276Speterstatic const char rcsid[] =
4550276Speter  "$FreeBSD: head/usr.sbin/syslogd/syslogd.c 81977 2001-08-20 13:24:39Z brian $";
4650276Speter#endif /* not lint */
4797049Speter
4850276Speter/*
4950276Speter *  syslogd -- log system messages
5050276Speter *
5150276Speter * This program implements a system log. It takes a series of lines.
5250276Speter * Each line may have a priority, signified as "<n>" as
5350276Speter * the first characters of the line.  If this is
54166124Srafan * not present, a default priority is used.
5550276Speter *
5650276Speter * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
5750276Speter * cause it to reread its configuration file.
5850276Speter *
59166124Srafan * Defined Constants:
6050276Speter *
6150276Speter * MAXLINE -- the maximimum line length that can be handled.
6250276Speter * DEFUPRI -- the default priority for user messages
6350276Speter * DEFSPRI -- the default priority for kernel messages
6450276Speter *
6550276Speter * Author: Eric Allman
66166124Srafan * extensive changes by Ralph Campbell
6750276Speter * more extensive changes by Eric Allman (again)
6850276Speter * Extension to log by program name as well as facility and priority
69166124Srafan *   by Peter da Silva.
70166124Srafan * -u and -v by Harlan Stenn.
71166124Srafan * Priority comparison code by Harlan Stenn.
72166124Srafan */
7350276Speter
74166124Srafan#define	MAXLINE		1024		/* maximum line length */
7550276Speter#define	MAXSVLINE	120		/* maximum saved line length */
7697049Speter#define DEFUPRI		(LOG_USER|LOG_NOTICE)
7750276Speter#define DEFSPRI		(LOG_KERN|LOG_CRIT)
7850276Speter#define TIMERINTVL	30		/* interval for checking flush, mark */
7950276Speter#define TTYMSGTIME	1		/* timed out passed to ttymsg */
8050276Speter
8150276Speter#include <sys/param.h>
8250276Speter#include <sys/ioctl.h>
8350276Speter#include <sys/stat.h>
8450276Speter#include <sys/wait.h>
8550276Speter#include <sys/socket.h>
8650276Speter#include <sys/queue.h>
8750276Speter#include <sys/uio.h>
8850276Speter#include <sys/un.h>
8950276Speter#include <sys/time.h>
9050276Speter#include <sys/resource.h>
9150276Speter#include <sys/syslimits.h>
9250276Speter#include <paths.h>
93
94#include <netinet/in.h>
95#include <netdb.h>
96#include <arpa/inet.h>
97
98#include <ctype.h>
99#include <err.h>
100#include <errno.h>
101#include <fcntl.h>
102#include <setjmp.h>
103#include <signal.h>
104#include <stdio.h>
105#include <stdlib.h>
106#include <string.h>
107#include <sysexits.h>
108#include <unistd.h>
109#include <utmp.h>
110#include "pathnames.h"
111
112#define SYSLOG_NAMES
113#include <sys/syslog.h>
114
115#ifdef NI_WITHSCOPEID
116static const int withscopeid = NI_WITHSCOPEID;
117#else
118static const int withscopeid = 0;
119#endif
120
121const char	*ConfFile = _PATH_LOGCONF;
122const char	*PidFile = _PATH_LOGPID;
123const char	ctty[] = _PATH_CONSOLE;
124
125#define	dprintf		if (Debug) printf
126
127#define MAXUNAMES	20	/* maximum number of user names */
128
129#define MAXFUNIX       20
130
131int nfunix = 1;
132char *funixn[MAXFUNIX] = { _PATH_LOG };
133int funix[MAXFUNIX];
134
135/*
136 * Flags to logmsg().
137 */
138
139#define IGN_CONS	0x001	/* don't print on console */
140#define SYNC_FILE	0x002	/* do fsync on file after printing */
141#define ADDDATE		0x004	/* add a date to the message */
142#define MARK		0x008	/* this message is a mark */
143#define ISKERNEL	0x010	/* kernel generated message */
144
145/*
146 * This structure represents the files that will have log
147 * copies printed.
148 */
149
150struct filed {
151	struct	filed *f_next;		/* next in linked list */
152	short	f_type;			/* entry type, see below */
153	short	f_file;			/* file descriptor */
154	time_t	f_time;			/* time this was last written */
155	char	*f_host;		/* host from which to recd. */
156	u_char	f_pmask[LOG_NFACILITIES+1];	/* priority mask */
157	u_char	f_pcmp[LOG_NFACILITIES+1];	/* compare priority */
158#define PRI_LT	0x1
159#define PRI_EQ	0x2
160#define PRI_GT	0x4
161	char	*f_program;		/* program this applies to */
162	union {
163		char	f_uname[MAXUNAMES][UT_NAMESIZE+1];
164		struct {
165			char	f_hname[MAXHOSTNAMELEN];
166			struct addrinfo *f_addr;
167
168		} f_forw;		/* forwarding address */
169		char	f_fname[MAXPATHLEN];
170		struct {
171			char	f_pname[MAXPATHLEN];
172			pid_t	f_pid;
173		} f_pipe;
174	} f_un;
175	char	f_prevline[MAXSVLINE];		/* last message logged */
176	char	f_lasttime[16];			/* time of last occurrence */
177	char	f_prevhost[MAXHOSTNAMELEN];	/* host from which recd. */
178	int	f_prevpri;			/* pri of f_prevline */
179	int	f_prevlen;			/* length of f_prevline */
180	int	f_prevcount;			/* repetition cnt of prevline */
181	int	f_repeatcount;			/* number of "repeated" msgs */
182};
183
184/*
185 * Queue of about-to-be dead processes we should watch out for.
186 */
187
188TAILQ_HEAD(stailhead, deadq_entry) deadq_head;
189struct stailhead *deadq_headp;
190
191struct deadq_entry {
192	pid_t				dq_pid;
193	int				dq_timeout;
194	TAILQ_ENTRY(deadq_entry)	dq_entries;
195};
196
197/*
198 * The timeout to apply to processes waiting on the dead queue.  Unit
199 * of measure is `mark intervals', i.e. 20 minutes by default.
200 * Processes on the dead queue will be terminated after that time.
201 */
202
203#define DQ_TIMO_INIT	2
204
205typedef struct deadq_entry *dq_t;
206
207
208/*
209 * Struct to hold records of network addresses that are allowed to log
210 * to us.
211 */
212struct allowedpeer {
213	int isnumeric;
214	u_short port;
215	union {
216		struct {
217			struct sockaddr_storage addr;
218			struct sockaddr_storage mask;
219		} numeric;
220		char *name;
221	} u;
222#define a_addr u.numeric.addr
223#define a_mask u.numeric.mask
224#define a_name u.name
225};
226
227
228/*
229 * Intervals at which we flush out "message repeated" messages,
230 * in seconds after previous message is logged.  After each flush,
231 * we move to the next interval until we reach the largest.
232 */
233int	repeatinterval[] = { 30, 120, 600 };	/* # of secs before flush */
234#define	MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
235#define	REPEATTIME(f)	((f)->f_time + repeatinterval[(f)->f_repeatcount])
236#define	BACKOFF(f)	{ if (++(f)->f_repeatcount > MAXREPEAT) \
237				 (f)->f_repeatcount = MAXREPEAT; \
238			}
239
240/* values for f_type */
241#define F_UNUSED	0		/* unused entry */
242#define F_FILE		1		/* regular file */
243#define F_TTY		2		/* terminal */
244#define F_CONSOLE	3		/* console terminal */
245#define F_FORW		4		/* remote machine */
246#define F_USERS		5		/* list of users */
247#define F_WALL		6		/* everyone logged on */
248#define F_PIPE		7		/* pipe to program */
249
250char	*TypeNames[8] = {
251	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
252	"FORW",		"USERS",	"WALL",		"PIPE"
253};
254
255struct	filed *Files;
256struct	filed consfile;
257
258int	Debug;			/* debug flag */
259int	resolve = 1;		/* resolve hostname */
260char	LocalHostName[MAXHOSTNAMELEN];	/* our hostname */
261char	*LocalDomain;		/* our local domain name */
262int	*finet = NULL;		/* Internet datagram socket */
263int	fklog = -1;		/* /dev/klog */
264int	Initialized = 0;	/* set when we have initialized ourselves */
265int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
266int	MarkSeq = 0;		/* mark sequence number */
267int	SecureMode = 0;		/* when true, receive only unix domain socks */
268#ifdef INET6
269int	family = PF_UNSPEC;	/* protocol family (IPv4, IPv6 or both) */
270#else
271int	family = PF_INET;	/* protocol family (IPv4 only) */
272#endif
273int	send_to_all = 0;	/* send message to all IPv4/IPv6 addresses */
274
275char	bootfile[MAXLINE+1];	/* booted kernel file */
276
277struct allowedpeer *AllowedPeers;
278int	NumAllowed = 0;		/* # of AllowedPeer entries */
279
280int	UniquePriority = 0;	/* Only log specified priority? */
281int	LogFacPri = 0;		/* Put facility and priority in log message: */
282				/* 0=no, 1=numeric, 2=names */
283int	KeepKernFac = 0;	/* Keep remotely logged kernel facility */
284
285int	allowaddr __P((char *));
286void	cfline __P((char *, struct filed *, char *, char *));
287char   *cvthname __P((struct sockaddr *));
288void	deadq_enter __P((pid_t, const char *));
289int	deadq_remove __P((pid_t));
290int	decode __P((const char *, CODE *));
291void	die __P((int));
292void	domark __P((int));
293void	fprintlog __P((struct filed *, int, char *));
294int*	socksetup __P((int));
295void	init __P((int));
296void	logerror __P((const char *));
297void	logmsg __P((int, char *, char *, int));
298void	log_deadchild __P((pid_t, int, const char *));
299void	printline __P((char *, char *));
300void	printsys __P((char *));
301int	p_open __P((char *, pid_t *));
302void	readklog __P((void));
303void	reapchild __P((int));
304char   *ttymsg __P((struct iovec *, int, char *, int));
305static void	usage __P((void));
306int	validate __P((struct sockaddr *, const char *));
307static void	unmapped __P((struct sockaddr *));
308void	wallmsg __P((struct filed *, struct iovec *));
309int	waitdaemon __P((int, int, int));
310void	timedout __P((int));
311
312int
313main(argc, argv)
314	int argc;
315	char *argv[];
316{
317	int ch, i, l;
318	struct sockaddr_un sunx, fromunix;
319	struct sockaddr_storage frominet;
320	FILE *fp;
321	char *p, *hname, line[MAXLINE + 1];
322	struct timeval tv, *tvp;
323	struct sigaction sact;
324	sigset_t mask;
325	pid_t ppid = 1;
326	socklen_t len;
327
328	while ((ch = getopt(argc, argv, "46Aa:df:kl:m:np:P:suv")) != -1)
329		switch (ch) {
330		case '4':
331			family = PF_INET;
332			break;
333#ifdef INET6
334		case '6':
335			family = PF_INET6;
336			break;
337#endif
338		case 'A':
339			send_to_all++;
340			break;
341		case 'a':		/* allow specific network addresses only */
342			if (allowaddr(optarg) == -1)
343				usage();
344			break;
345		case 'd':		/* debug */
346			Debug++;
347			break;
348		case 'f':		/* configuration file */
349			ConfFile = optarg;
350			break;
351		case 'k':		/* keep remote kern fac */
352			KeepKernFac = 1;
353			break;
354		case 'l':
355			if (nfunix < MAXFUNIX)
356				funixn[nfunix++] = optarg;
357			else
358				warnx("out of descriptors, ignoring %s",
359					optarg);
360			break;
361		case 'm':		/* mark interval */
362			MarkInterval = atoi(optarg) * 60;
363			break;
364		case 'n':
365			resolve = 0;
366			break;
367		case 'p':		/* path */
368			funixn[0] = optarg;
369			break;
370		case 'P':		/* path for alt. PID */
371			PidFile = optarg;
372			break;
373		case 's':		/* no network mode */
374			SecureMode++;
375			break;
376		case 'u':		/* only log specified priority */
377		        UniquePriority++;
378			break;
379		case 'v':		/* log facility and priority */
380		  	LogFacPri++;
381			break;
382		case '?':
383		default:
384			usage();
385		}
386	if ((argc -= optind) != 0)
387		usage();
388
389	if (!Debug) {
390		ppid = waitdaemon(0, 0, 30);
391		if (ppid < 0)
392			err(1, "could not become daemon");
393	} else
394		setlinebuf(stdout);
395
396	if (NumAllowed)
397		endservent();
398
399	consfile.f_type = F_CONSOLE;
400	(void)strcpy(consfile.f_un.f_fname, ctty + sizeof _PATH_DEV - 1);
401	(void)gethostname(LocalHostName, sizeof(LocalHostName));
402	if ((p = strchr(LocalHostName, '.')) != NULL) {
403		*p++ = '\0';
404		LocalDomain = p;
405	} else
406		LocalDomain = "";
407	(void)strcpy(bootfile, getbootfile());
408	(void)signal(SIGTERM, die);
409	(void)signal(SIGINT, Debug ? die : SIG_IGN);
410	(void)signal(SIGQUIT, Debug ? die : SIG_IGN);
411	/*
412	 * We don't want the SIGCHLD and SIGHUP handlers to interfere
413	 * with each other; they are likely candidates for being called
414	 * simultaneously (SIGHUP closes pipe descriptor, process dies,
415	 * SIGCHLD happens).
416	 */
417	sigemptyset(&mask);
418	sigaddset(&mask, SIGHUP);
419	sact.sa_handler = reapchild;
420	sact.sa_mask = mask;
421	sact.sa_flags = SA_RESTART;
422	(void)sigaction(SIGCHLD, &sact, NULL);
423	(void)signal(SIGALRM, domark);
424	(void)signal(SIGPIPE, SIG_IGN);	/* We'll catch EPIPE instead. */
425	(void)alarm(TIMERINTVL);
426
427	TAILQ_INIT(&deadq_head);
428
429#ifndef SUN_LEN
430#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
431#endif
432	for (i = 0; i < nfunix; i++) {
433		memset(&sunx, 0, sizeof(sunx));
434		sunx.sun_family = AF_UNIX;
435		(void)strncpy(sunx.sun_path, funixn[i], sizeof(sunx.sun_path));
436		funix[i] = socket(AF_UNIX, SOCK_DGRAM, 0);
437		if (funix[i] < 0 ||
438		    bind(funix[i], (struct sockaddr *)&sunx,
439			 SUN_LEN(&sunx)) < 0 ||
440		    chmod(funixn[i], 0666) < 0) {
441			(void) snprintf(line, sizeof line,
442					"cannot create %s", funixn[i]);
443			logerror(line);
444			dprintf("cannot create %s (%d)\n", funixn[i], errno);
445			if (i == 0)
446				die(0);
447		}
448	}
449	if (SecureMode <= 1)
450		finet = socksetup(family);
451
452	if (finet) {
453		if (SecureMode) {
454			for (i = 0; i < *finet; i++) {
455				if (shutdown(finet[i+1], SHUT_RD) < 0) {
456					logerror("shutdown");
457					if (!Debug)
458						die(0);
459				}
460			}
461		} else
462			dprintf("listening on inet and/or inet6 socket\n");
463		dprintf("sending on inet and/or inet6 socket\n");
464	}
465
466	if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
467		if (fcntl(fklog, F_SETFL, O_NONBLOCK) < 0)
468			fklog = -1;
469	if (fklog < 0)
470		dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
471
472	/* tuck my process id away */
473	fp = fopen(PidFile, "w");
474	if (fp != NULL) {
475		fprintf(fp, "%d\n", getpid());
476		(void) fclose(fp);
477	}
478
479	dprintf("off & running....\n");
480
481	init(0);
482	/* prevent SIGHUP and SIGCHLD handlers from running in parallel */
483	sigemptyset(&mask);
484	sigaddset(&mask, SIGCHLD);
485	sact.sa_handler = init;
486	sact.sa_mask = mask;
487	sact.sa_flags = SA_RESTART;
488	(void)sigaction(SIGHUP, &sact, NULL);
489
490	tvp = &tv;
491	tv.tv_sec = tv.tv_usec = 0;
492
493	for (;;) {
494		fd_set readfds;
495		int nfds = 0;
496
497		FD_ZERO(&readfds);
498		if (fklog != -1) {
499			FD_SET(fklog, &readfds);
500			if (fklog > nfds)
501				nfds = fklog;
502		}
503		if (finet && !SecureMode) {
504			for (i = 0; i < *finet; i++) {
505				FD_SET(finet[i+1], &readfds);
506				if (finet[i+1] > nfds)
507					nfds = finet[i+1];
508			}
509		}
510		for (i = 0; i < nfunix; i++) {
511			if (funix[i] != -1) {
512				FD_SET(funix[i], &readfds);
513				if (funix[i] > nfds)
514					nfds = funix[i];
515			}
516		}
517
518		/*dprintf("readfds = %#x\n", readfds);*/
519		nfds = select(nfds+1, &readfds, (fd_set *)NULL,
520			      (fd_set *)NULL, tvp);
521		if (nfds == 0) {
522			if (tvp) {
523				tvp = NULL;
524				if (ppid != 1)
525					kill(ppid, SIGALRM);
526			}
527			continue;
528		}
529		if (nfds < 0) {
530			if (errno != EINTR)
531				logerror("select");
532			continue;
533		}
534		/*dprintf("got a message (%d, %#x)\n", nfds, readfds);*/
535		if (fklog != -1 && FD_ISSET(fklog, &readfds))
536			readklog();
537		if (finet && !SecureMode) {
538			for (i = 0; i < *finet; i++) {
539				if (FD_ISSET(finet[i+1], &readfds)) {
540					len = sizeof(frominet);
541					l = recvfrom(finet[i+1], line, MAXLINE,
542					     0, (struct sockaddr *)&frominet,
543					     &len);
544					if (l > 0) {
545						line[l] = '\0';
546						hname = cvthname((struct sockaddr *)&frominet);
547						unmapped((struct sockaddr *)&frominet);
548						if (validate((struct sockaddr *)&frominet, hname))
549							printline(hname, line);
550					} else if (l < 0 && errno != EINTR)
551						logerror("recvfrom inet");
552				}
553			}
554		}
555		for (i = 0; i < nfunix; i++) {
556			if (funix[i] != -1 && FD_ISSET(funix[i], &readfds)) {
557				len = sizeof(fromunix);
558				l = recvfrom(funix[i], line, MAXLINE, 0,
559				    (struct sockaddr *)&fromunix, &len);
560				if (l > 0) {
561					line[l] = '\0';
562					printline(LocalHostName, line);
563				} else if (l < 0 && errno != EINTR)
564					logerror("recvfrom unix");
565			}
566		}
567	}
568}
569
570static void
571unmapped(sa)
572	struct sockaddr *sa;
573{
574	struct sockaddr_in6 *sin6;
575	struct sockaddr_in sin;
576
577	if (sa->sa_family != AF_INET6)
578		return;
579	if (sa->sa_len != sizeof(struct sockaddr_in6) ||
580	    sizeof(sin) > sa->sa_len)
581		return;
582	sin6 = (struct sockaddr_in6 *)sa;
583	if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
584		return;
585
586	memset(&sin, 0, sizeof(sin));
587	sin.sin_family = AF_INET;
588	sin.sin_len = sizeof(struct sockaddr_in);
589	memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
590	       sizeof(sin.sin_addr));
591	sin.sin_port = sin6->sin6_port;
592
593	memcpy(sa, &sin, sin.sin_len);
594}
595
596static void
597usage()
598{
599
600	fprintf(stderr, "%s\n%s\n%s\n",
601		"usage: syslogd [-46Adnsuv] [-a allowed_peer] [-f config_file]",
602		"               [-m mark_interval] [-l log_socket]",
603		"               [-p log_socket] [-P pid_file]");
604	exit(1);
605}
606
607/*
608 * Take a raw input line, decode the message, and print the message
609 * on the appropriate log files.
610 */
611void
612printline(hname, msg)
613	char *hname;
614	char *msg;
615{
616	int c, pri;
617	char *p, *q, line[MAXLINE + 1];
618
619	/* test for special codes */
620	pri = DEFUPRI;
621	p = msg;
622	if (*p == '<') {
623		pri = 0;
624		while (isdigit(*++p))
625			pri = 10 * pri + (*p - '0');
626		if (*p == '>')
627			++p;
628	}
629	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
630		pri = DEFUPRI;
631
632	/* don't allow users to log kernel messages */
633	if (LOG_FAC(pri) == LOG_KERN && !KeepKernFac)
634		pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
635
636	q = line;
637
638	while ((c = (unsigned char)*p++) != '\0' &&
639	    q < &line[sizeof(line) - 4]) {
640		if ((c & 0x80) && c < 0xA0) {
641			c &= 0x7F;
642			*q++ = 'M';
643			*q++ = '-';
644		}
645		if (isascii(c) && iscntrl(c)) {
646			if (c == '\n')
647				*q++ = ' ';
648			else if (c == '\t')
649				*q++ = '\t';
650			else {
651				*q++ = '^';
652				*q++ = c ^ 0100;
653			}
654		} else
655			*q++ = c;
656	}
657	*q = '\0';
658
659	logmsg(pri, line, hname, 0);
660}
661
662/*
663 * Read /dev/klog while data are available, split into lines.
664 */
665void
666readklog()
667{
668	char *p, *q, line[MAXLINE + 1];
669	int len, i;
670
671	len = 0;
672	for (;;) {
673		i = read(fklog, line + len, MAXLINE - 1 - len);
674		if (i > 0)
675			line[i + len] = '\0';
676		else if (i < 0 && errno != EINTR && errno != EAGAIN) {
677			logerror("klog");
678			fklog = -1;
679			break;
680		} else
681			break;
682
683		for (p = line; (q = strchr(p, '\n')) != NULL; p = q + 1) {
684			*q = '\0';
685			printsys(p);
686		}
687		len = strlen(p);
688		if (len >= MAXLINE - 1) {
689			printsys(p);
690			len = 0;
691		}
692		if (len > 0)
693			memmove(line, p, len + 1);
694	}
695	if (len > 0)
696		printsys(line);
697}
698
699/*
700 * Take a raw input line from /dev/klog, format similar to syslog().
701 */
702void
703printsys(p)
704	char *p;
705{
706	int pri, flags;
707
708	flags = ISKERNEL | SYNC_FILE | ADDDATE;	/* fsync after write */
709	pri = DEFSPRI;
710	if (*p == '<') {
711		pri = 0;
712		while (isdigit(*++p))
713			pri = 10 * pri + (*p - '0');
714		if (*p == '>')
715			++p;
716		if ((pri & LOG_FACMASK) == LOG_CONSOLE)
717			flags |= IGN_CONS;
718	} else {
719		/* kernel printf's come out on console */
720		flags |= IGN_CONS;
721	}
722	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
723		pri = DEFSPRI;
724	logmsg(pri, p, LocalHostName, flags);
725}
726
727time_t	now;
728
729/*
730 * Log a message to the appropriate log files, users, etc. based on
731 * the priority.
732 */
733void
734logmsg(pri, msg, from, flags)
735	int pri;
736	char *msg, *from;
737	int flags;
738{
739	struct filed *f;
740	int i, fac, msglen, omask, prilev;
741	char *timestamp;
742 	char prog[NAME_MAX+1];
743	char buf[MAXLINE+1];
744
745	dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
746	    pri, flags, from, msg);
747
748	omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
749
750	/*
751	 * Check to see if msg looks non-standard.
752	 */
753	msglen = strlen(msg);
754	if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
755	    msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
756		flags |= ADDDATE;
757
758	(void)time(&now);
759	if (flags & ADDDATE)
760		timestamp = ctime(&now) + 4;
761	else {
762		timestamp = msg;
763		msg += 16;
764		msglen -= 16;
765	}
766
767	/* skip leading blanks */
768	while (isspace(*msg)) {
769		msg++;
770		msglen--;
771	}
772
773	/* extract facility and priority level */
774	if (flags & MARK)
775		fac = LOG_NFACILITIES;
776	else
777		fac = LOG_FAC(pri);
778	prilev = LOG_PRI(pri);
779
780	/* extract program name */
781	for (i = 0; i < NAME_MAX; i++) {
782		if (!isalnum(msg[i]))
783			break;
784		prog[i] = msg[i];
785	}
786	prog[i] = 0;
787
788	/* add kernel prefix for kernel messages */
789	if (flags & ISKERNEL) {
790		snprintf(buf, sizeof(buf), "%s: %s", bootfile, msg);
791		msg = buf;
792		msglen = strlen(buf);
793	}
794
795	/* log the message to the particular outputs */
796	if (!Initialized) {
797		f = &consfile;
798		f->f_file = open(ctty, O_WRONLY, 0);
799
800		if (f->f_file >= 0) {
801			fprintlog(f, flags, msg);
802			(void)close(f->f_file);
803		}
804		(void)sigsetmask(omask);
805		return;
806	}
807	for (f = Files; f; f = f->f_next) {
808		/* skip messages that are incorrect priority */
809		if (!(((f->f_pcmp[fac] & PRI_EQ) && (f->f_pmask[fac] == prilev))
810		     ||((f->f_pcmp[fac] & PRI_LT) && (f->f_pmask[fac] < prilev))
811		     ||((f->f_pcmp[fac] & PRI_GT) && (f->f_pmask[fac] > prilev))
812		     )
813		    || f->f_pmask[fac] == INTERNAL_NOPRI)
814			continue;
815		/* skip messages with the incorrect hostname */
816		if (f->f_host)
817			switch (f->f_host[0]) {
818			case '+':
819				if (strcmp(from, f->f_host + 1) != 0)
820					continue;
821				break;
822			case '-':
823				if (strcmp(from, f->f_host + 1) == 0)
824					continue;
825				break;
826			}
827
828		/* skip messages with the incorrect program name */
829		if (f->f_program)
830			if (strcmp(prog, f->f_program) != 0)
831				continue;
832
833		if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
834			continue;
835
836		/* don't output marks to recently written files */
837		if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
838			continue;
839
840		/*
841		 * suppress duplicate lines to this file
842		 */
843		if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
844		    !strcmp(msg, f->f_prevline) &&
845		    !strcasecmp(from, f->f_prevhost)) {
846			(void)strncpy(f->f_lasttime, timestamp, 15);
847			f->f_prevcount++;
848			dprintf("msg repeated %d times, %ld sec of %d\n",
849			    f->f_prevcount, (long)(now - f->f_time),
850			    repeatinterval[f->f_repeatcount]);
851			/*
852			 * If domark would have logged this by now,
853			 * flush it now (so we don't hold isolated messages),
854			 * but back off so we'll flush less often
855			 * in the future.
856			 */
857			if (now > REPEATTIME(f)) {
858				fprintlog(f, flags, (char *)NULL);
859				BACKOFF(f);
860			}
861		} else {
862			/* new line, save it */
863			if (f->f_prevcount)
864				fprintlog(f, 0, (char *)NULL);
865			f->f_repeatcount = 0;
866			f->f_prevpri = pri;
867			(void)strncpy(f->f_lasttime, timestamp, 15);
868			(void)strncpy(f->f_prevhost, from,
869					sizeof(f->f_prevhost)-1);
870			f->f_prevhost[sizeof(f->f_prevhost)-1] = '\0';
871			if (msglen < MAXSVLINE) {
872				f->f_prevlen = msglen;
873				(void)strcpy(f->f_prevline, msg);
874				fprintlog(f, flags, (char *)NULL);
875			} else {
876				f->f_prevline[0] = 0;
877				f->f_prevlen = 0;
878				fprintlog(f, flags, msg);
879			}
880		}
881	}
882	(void)sigsetmask(omask);
883}
884
885void
886fprintlog(f, flags, msg)
887	struct filed *f;
888	int flags;
889	char *msg;
890{
891	struct iovec iov[7];
892	struct iovec *v;
893	struct addrinfo *r;
894	int i, l, lsent = 0;
895	char line[MAXLINE + 1], repbuf[80], greetings[200];
896	char *msgret;
897
898	v = iov;
899	if (f->f_type == F_WALL) {
900		v->iov_base = greetings;
901		v->iov_len = snprintf(greetings, sizeof greetings,
902		    "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
903		    f->f_prevhost, ctime(&now));
904		if (v->iov_len > 0)
905			v++;
906		v->iov_base = "";
907		v->iov_len = 0;
908		v++;
909	} else {
910		v->iov_base = f->f_lasttime;
911		v->iov_len = 15;
912		v++;
913		v->iov_base = " ";
914		v->iov_len = 1;
915		v++;
916	}
917
918	if (LogFacPri) {
919	  	static char fp_buf[30];	/* Hollow laugh */
920		int fac = f->f_prevpri & LOG_FACMASK;
921		int pri = LOG_PRI(f->f_prevpri);
922		const char *f_s = NULL;
923		char f_n[5];	/* Hollow laugh */
924		const char *p_s = NULL;
925		char p_n[5];	/* Hollow laugh */
926
927		if (LogFacPri > 1) {
928		  CODE *c;
929
930		  for (c = facilitynames; c->c_name; c++) {
931		    if (c->c_val == fac) {
932		      f_s = c->c_name;
933		      break;
934		    }
935		  }
936		  for (c = prioritynames; c->c_name; c++) {
937		    if (c->c_val == pri) {
938		      p_s = c->c_name;
939		      break;
940		    }
941		  }
942		}
943		if (!f_s) {
944		  snprintf(f_n, sizeof f_n, "%d", LOG_FAC(fac));
945		  f_s = f_n;
946		}
947		if (!p_s) {
948		  snprintf(p_n, sizeof p_n, "%d", pri);
949		  p_s = p_n;
950		}
951		snprintf(fp_buf, sizeof fp_buf, "<%s.%s> ", f_s, p_s);
952		v->iov_base = fp_buf;
953		v->iov_len = strlen(fp_buf);
954	} else {
955	        v->iov_base="";
956		v->iov_len = 0;
957	}
958	v++;
959
960	v->iov_base = f->f_prevhost;
961	v->iov_len = strlen(v->iov_base);
962	v++;
963	v->iov_base = " ";
964	v->iov_len = 1;
965	v++;
966
967	if (msg) {
968		v->iov_base = msg;
969		v->iov_len = strlen(msg);
970	} else if (f->f_prevcount > 1) {
971		v->iov_base = repbuf;
972		v->iov_len = sprintf(repbuf, "last message repeated %d times",
973		    f->f_prevcount);
974	} else {
975		v->iov_base = f->f_prevline;
976		v->iov_len = f->f_prevlen;
977	}
978	v++;
979
980	dprintf("Logging to %s", TypeNames[f->f_type]);
981	f->f_time = now;
982
983	switch (f->f_type) {
984	case F_UNUSED:
985		dprintf("\n");
986		break;
987
988	case F_FORW:
989		dprintf(" %s\n", f->f_un.f_forw.f_hname);
990		/* check for local vs remote messages */
991		if (strcasecmp(f->f_prevhost, LocalHostName))
992			l = snprintf(line, sizeof line - 1,
993			    "<%d>%.15s Forwarded from %s: %s",
994			    f->f_prevpri, iov[0].iov_base, f->f_prevhost,
995			    iov[5].iov_base);
996		else
997			l = snprintf(line, sizeof line - 1, "<%d>%.15s %s",
998			     f->f_prevpri, iov[0].iov_base, iov[5].iov_base);
999		if (l < 0)
1000			l = 0;
1001		else if (l > MAXLINE)
1002			l = MAXLINE;
1003
1004		if (finet) {
1005			for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
1006				for (i = 0; i < *finet; i++) {
1007#if 0
1008					/*
1009					 * should we check AF first, or just
1010					 * trial and error? FWD
1011					 */
1012					if (r->ai_family ==
1013					    address_family_of(finet[i+1]))
1014#endif
1015					lsent = sendto(finet[i+1], line, l, 0,
1016					    r->ai_addr, r->ai_addrlen);
1017					if (lsent == l)
1018						break;
1019				}
1020				if (lsent == l && !send_to_all)
1021					break;
1022			}
1023			if (lsent != l) {
1024				int e = errno;
1025				(void)close(f->f_file);
1026				errno = e;
1027				f->f_type = F_UNUSED;
1028				logerror("sendto");
1029			}
1030		}
1031		break;
1032
1033	case F_FILE:
1034		dprintf(" %s\n", f->f_un.f_fname);
1035		v->iov_base = "\n";
1036		v->iov_len = 1;
1037		if (writev(f->f_file, iov, 7) < 0) {
1038			int e = errno;
1039			(void)close(f->f_file);
1040			f->f_type = F_UNUSED;
1041			errno = e;
1042			logerror(f->f_un.f_fname);
1043		} else if (flags & SYNC_FILE)
1044			(void)fsync(f->f_file);
1045		break;
1046
1047	case F_PIPE:
1048		dprintf(" %s\n", f->f_un.f_pipe.f_pname);
1049		v->iov_base = "\n";
1050		v->iov_len = 1;
1051		if (f->f_un.f_pipe.f_pid == 0) {
1052			if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
1053						&f->f_un.f_pipe.f_pid)) < 0) {
1054				f->f_type = F_UNUSED;
1055				logerror(f->f_un.f_pipe.f_pname);
1056				break;
1057			}
1058		}
1059		if (writev(f->f_file, iov, 7) < 0) {
1060			int e = errno;
1061			(void)close(f->f_file);
1062			if (f->f_un.f_pipe.f_pid > 0)
1063				deadq_enter(f->f_un.f_pipe.f_pid,
1064					    f->f_un.f_pipe.f_pname);
1065			f->f_un.f_pipe.f_pid = 0;
1066			errno = e;
1067			logerror(f->f_un.f_pipe.f_pname);
1068		}
1069		break;
1070
1071	case F_CONSOLE:
1072		if (flags & IGN_CONS) {
1073			dprintf(" (ignored)\n");
1074			break;
1075		}
1076		/* FALLTHROUGH */
1077
1078	case F_TTY:
1079		dprintf(" %s%s\n", _PATH_DEV, f->f_un.f_fname);
1080		v->iov_base = "\r\n";
1081		v->iov_len = 2;
1082
1083		errno = 0;	/* ttymsg() only sometimes returns an errno */
1084		if ((msgret = ttymsg(iov, 7, f->f_un.f_fname, 10))) {
1085			f->f_type = F_UNUSED;
1086			logerror(msgret);
1087		}
1088		break;
1089
1090	case F_USERS:
1091	case F_WALL:
1092		dprintf("\n");
1093		v->iov_base = "\r\n";
1094		v->iov_len = 2;
1095		wallmsg(f, iov);
1096		break;
1097	}
1098	f->f_prevcount = 0;
1099}
1100
1101/*
1102 *  WALLMSG -- Write a message to the world at large
1103 *
1104 *	Write the specified message to either the entire
1105 *	world, or a list of approved users.
1106 */
1107void
1108wallmsg(f, iov)
1109	struct filed *f;
1110	struct iovec *iov;
1111{
1112	static int reenter;			/* avoid calling ourselves */
1113	FILE *uf;
1114	struct utmp ut;
1115	int i;
1116	char *p;
1117	char line[sizeof(ut.ut_line) + 1];
1118
1119	if (reenter++)
1120		return;
1121	if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
1122		logerror(_PATH_UTMP);
1123		reenter = 0;
1124		return;
1125	}
1126	/* NOSTRICT */
1127	while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) {
1128		if (ut.ut_name[0] == '\0')
1129			continue;
1130		strncpy(line, ut.ut_line, sizeof(ut.ut_line));
1131		line[sizeof(ut.ut_line)] = '\0';
1132		if (f->f_type == F_WALL) {
1133			if ((p = ttymsg(iov, 7, line, TTYMSGTIME)) != NULL) {
1134				errno = 0;	/* already in msg */
1135				logerror(p);
1136			}
1137			continue;
1138		}
1139		/* should we send the message to this user? */
1140		for (i = 0; i < MAXUNAMES; i++) {
1141			if (!f->f_un.f_uname[i][0])
1142				break;
1143			if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
1144			    UT_NAMESIZE)) {
1145				if ((p = ttymsg(iov, 7, line, TTYMSGTIME))
1146								!= NULL) {
1147					errno = 0;	/* already in msg */
1148					logerror(p);
1149				}
1150				break;
1151			}
1152		}
1153	}
1154	(void)fclose(uf);
1155	reenter = 0;
1156}
1157
1158void
1159reapchild(signo)
1160	int signo;
1161{
1162	int status;
1163	pid_t pid;
1164	struct filed *f;
1165
1166	while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) {
1167		if (!Initialized)
1168			/* Don't tell while we are initting. */
1169			continue;
1170
1171		/* First, look if it's a process from the dead queue. */
1172		if (deadq_remove(pid))
1173			goto oncemore;
1174
1175		/* Now, look in list of active processes. */
1176		for (f = Files; f; f = f->f_next)
1177			if (f->f_type == F_PIPE &&
1178			    f->f_un.f_pipe.f_pid == pid) {
1179				(void)close(f->f_file);
1180				f->f_un.f_pipe.f_pid = 0;
1181				log_deadchild(pid, status,
1182					      f->f_un.f_pipe.f_pname);
1183				break;
1184			}
1185	  oncemore:
1186		continue;
1187	}
1188}
1189
1190/*
1191 * Return a printable representation of a host address.
1192 */
1193char *
1194cvthname(f)
1195	struct sockaddr *f;
1196{
1197	int error;
1198	sigset_t omask, nmask;
1199	char *p;
1200	static char hname[NI_MAXHOST], ip[NI_MAXHOST];
1201
1202	error = getnameinfo((struct sockaddr *)f,
1203			    ((struct sockaddr *)f)->sa_len,
1204			    ip, sizeof ip, NULL, 0,
1205			    NI_NUMERICHOST | withscopeid);
1206	dprintf("cvthname(%s)\n", ip);
1207
1208	if (error) {
1209		dprintf("Malformed from address %s\n", gai_strerror(error));
1210		return ("???");
1211	}
1212	if (!resolve)
1213		return (ip);
1214
1215	sigemptyset(&nmask);
1216	sigaddset(&nmask, SIGHUP);
1217	sigprocmask(SIG_BLOCK, &nmask, &omask);
1218	error = getnameinfo((struct sockaddr *)f,
1219			    ((struct sockaddr *)f)->sa_len,
1220			    hname, sizeof hname, NULL, 0,
1221			    NI_NAMEREQD | withscopeid);
1222	sigprocmask(SIG_SETMASK, &omask, NULL);
1223	if (error) {
1224		dprintf("Host name for your address (%s) unknown\n", ip);
1225		return (ip);
1226	}
1227	if ((p = strchr(hname, '.')) && strcasecmp(p + 1, LocalDomain) == 0)
1228		*p = '\0';
1229	return (hname);
1230}
1231
1232void
1233domark(signo)
1234	int signo;
1235{
1236	struct filed *f;
1237	dq_t q;
1238
1239	now = time((time_t *)NULL);
1240	MarkSeq += TIMERINTVL;
1241	if (MarkSeq >= MarkInterval) {
1242		logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
1243		MarkSeq = 0;
1244	}
1245
1246	for (f = Files; f; f = f->f_next) {
1247		if (f->f_prevcount && now >= REPEATTIME(f)) {
1248			dprintf("flush %s: repeated %d times, %d sec.\n",
1249			    TypeNames[f->f_type], f->f_prevcount,
1250			    repeatinterval[f->f_repeatcount]);
1251			fprintlog(f, 0, (char *)NULL);
1252			BACKOFF(f);
1253		}
1254	}
1255
1256	/* Walk the dead queue, and see if we should signal somebody. */
1257	for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries))
1258		switch (q->dq_timeout) {
1259		case 0:
1260			/* Already signalled once, try harder now. */
1261			if (kill(q->dq_pid, SIGKILL) != 0)
1262				(void)deadq_remove(q->dq_pid);
1263			break;
1264
1265		case 1:
1266			/*
1267			 * Timed out on dead queue, send terminate
1268			 * signal.  Note that we leave the removal
1269			 * from the dead queue to reapchild(), which
1270			 * will also log the event (unless the process
1271			 * didn't even really exist, in case we simply
1272			 * drop it from the dead queue).
1273			 */
1274			if (kill(q->dq_pid, SIGTERM) != 0)
1275				(void)deadq_remove(q->dq_pid);
1276			/* FALLTHROUGH */
1277
1278		default:
1279			q->dq_timeout--;
1280		}
1281
1282	(void)alarm(TIMERINTVL);
1283}
1284
1285/*
1286 * Print syslogd errors some place.
1287 */
1288void
1289logerror(type)
1290	const char *type;
1291{
1292	char buf[512];
1293
1294	if (errno)
1295		(void)snprintf(buf,
1296		    sizeof buf, "syslogd: %s: %s", type, strerror(errno));
1297	else
1298		(void)snprintf(buf, sizeof buf, "syslogd: %s", type);
1299	errno = 0;
1300	dprintf("%s\n", buf);
1301	logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
1302}
1303
1304void
1305die(signo)
1306	int signo;
1307{
1308	struct filed *f;
1309	int was_initialized;
1310	char buf[100];
1311	int i;
1312
1313	was_initialized = Initialized;
1314	Initialized = 0;	/* Don't log SIGCHLDs. */
1315	for (f = Files; f != NULL; f = f->f_next) {
1316		/* flush any pending output */
1317		if (f->f_prevcount)
1318			fprintlog(f, 0, (char *)NULL);
1319		if (f->f_type == F_PIPE)
1320			(void)close(f->f_file);
1321	}
1322	Initialized = was_initialized;
1323	if (signo) {
1324		dprintf("syslogd: exiting on signal %d\n", signo);
1325		(void)sprintf(buf, "exiting on signal %d", signo);
1326		errno = 0;
1327		logerror(buf);
1328	}
1329	for (i = 0; i < nfunix; i++)
1330		if (funixn[i] && funix[i] != -1)
1331			(void)unlink(funixn[i]);
1332	exit(1);
1333}
1334
1335/*
1336 *  INIT -- Initialize syslogd from configuration table
1337 */
1338void
1339init(signo)
1340	int signo;
1341{
1342	int i;
1343	FILE *cf;
1344	struct filed *f, *next, **nextp;
1345	char *p;
1346	char cline[LINE_MAX];
1347 	char prog[NAME_MAX+1];
1348	char host[MAXHOSTNAMELEN];
1349
1350	dprintf("init\n");
1351
1352	/*
1353	 *  Close all open log files.
1354	 */
1355	Initialized = 0;
1356	for (f = Files; f != NULL; f = next) {
1357		/* flush any pending output */
1358		if (f->f_prevcount)
1359			fprintlog(f, 0, (char *)NULL);
1360
1361		switch (f->f_type) {
1362		case F_FILE:
1363		case F_FORW:
1364		case F_CONSOLE:
1365		case F_TTY:
1366			(void)close(f->f_file);
1367			break;
1368		case F_PIPE:
1369			(void)close(f->f_file);
1370			if (f->f_un.f_pipe.f_pid > 0)
1371				deadq_enter(f->f_un.f_pipe.f_pid,
1372					    f->f_un.f_pipe.f_pname);
1373			f->f_un.f_pipe.f_pid = 0;
1374			break;
1375		}
1376		next = f->f_next;
1377		if (f->f_program) free(f->f_program);
1378		if (f->f_host) free(f->f_host);
1379		free((char *)f);
1380	}
1381	Files = NULL;
1382	nextp = &Files;
1383
1384	/* open the configuration file */
1385	if ((cf = fopen(ConfFile, "r")) == NULL) {
1386		dprintf("cannot open %s\n", ConfFile);
1387		*nextp = (struct filed *)calloc(1, sizeof(*f));
1388		cfline("*.ERR\t/dev/console", *nextp, "*", "*");
1389		(*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
1390		cfline("*.PANIC\t*", (*nextp)->f_next, "*", "*");
1391		Initialized = 1;
1392		return;
1393	}
1394
1395	/*
1396	 *  Foreach line in the conf table, open that file.
1397	 */
1398	f = NULL;
1399	strcpy(host, "*");
1400	strcpy(prog, "*");
1401	while (fgets(cline, sizeof(cline), cf) != NULL) {
1402		/*
1403		 * check for end-of-section, comments, strip off trailing
1404		 * spaces and newline character. #!prog is treated specially:
1405		 * following lines apply only to that program.
1406		 */
1407		for (p = cline; isspace(*p); ++p)
1408			continue;
1409		if (*p == 0)
1410			continue;
1411		if (*p == '#') {
1412			p++;
1413			if (*p != '!' && *p != '+' && *p != '-')
1414				continue;
1415		}
1416		if (*p == '+' || *p == '-') {
1417			host[0] = *p++;
1418			while (isspace(*p)) p++;
1419			if ((!*p) || (*p == '*')) {
1420				strcpy(host, "*");
1421				continue;
1422			}
1423			if (*p == '@')
1424				p = LocalHostName;
1425			for (i = 1; i < MAXHOSTNAMELEN - 1; i++) {
1426				if (!isalnum(*p) && *p != '.' && *p != '-')
1427					break;
1428				host[i] = *p++;
1429			}
1430			host[i] = '\0';
1431			continue;
1432		}
1433		if (*p == '!') {
1434			p++;
1435			while (isspace(*p)) p++;
1436			if ((!*p) || (*p == '*')) {
1437				strcpy(prog, "*");
1438				continue;
1439			}
1440			for (i = 0; i < NAME_MAX; i++) {
1441				if (!isalnum(p[i]))
1442					break;
1443				prog[i] = p[i];
1444			}
1445			prog[i] = 0;
1446			continue;
1447		}
1448		for (p = strchr(cline, '\0'); isspace(*--p);)
1449			continue;
1450		*++p = '\0';
1451		f = (struct filed *)calloc(1, sizeof(*f));
1452		*nextp = f;
1453		nextp = &f->f_next;
1454		cfline(cline, f, prog, host);
1455	}
1456
1457	/* close the configuration file */
1458	(void)fclose(cf);
1459
1460	Initialized = 1;
1461
1462	if (Debug) {
1463		for (f = Files; f; f = f->f_next) {
1464			for (i = 0; i <= LOG_NFACILITIES; i++)
1465				if (f->f_pmask[i] == INTERNAL_NOPRI)
1466					printf("X ");
1467				else
1468					printf("%d ", f->f_pmask[i]);
1469			printf("%s: ", TypeNames[f->f_type]);
1470			switch (f->f_type) {
1471			case F_FILE:
1472				printf("%s", f->f_un.f_fname);
1473				break;
1474
1475			case F_CONSOLE:
1476			case F_TTY:
1477				printf("%s%s", _PATH_DEV, f->f_un.f_fname);
1478				break;
1479
1480			case F_FORW:
1481				printf("%s", f->f_un.f_forw.f_hname);
1482				break;
1483
1484			case F_PIPE:
1485				printf("%s", f->f_un.f_pipe.f_pname);
1486				break;
1487
1488			case F_USERS:
1489				for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
1490					printf("%s, ", f->f_un.f_uname[i]);
1491				break;
1492			}
1493			if (f->f_program)
1494				printf(" (%s)", f->f_program);
1495			printf("\n");
1496		}
1497	}
1498
1499	logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
1500	dprintf("syslogd: restarted\n");
1501}
1502
1503/*
1504 * Crack a configuration file line
1505 */
1506void
1507cfline(line, f, prog, host)
1508	char *line;
1509	struct filed *f;
1510	char *prog;
1511	char *host;
1512{
1513	struct addrinfo hints, *res;
1514	int error, i, pri;
1515	char *bp, *p, *q;
1516	char buf[MAXLINE], ebuf[100];
1517
1518	dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line, prog, host);
1519
1520	errno = 0;	/* keep strerror() stuff out of logerror messages */
1521
1522	/* clear out file entry */
1523	memset(f, 0, sizeof(*f));
1524	for (i = 0; i <= LOG_NFACILITIES; i++)
1525		f->f_pmask[i] = INTERNAL_NOPRI;
1526
1527	/* save hostname if any */
1528	if (host && *host == '*')
1529		host = NULL;
1530	if (host)
1531		f->f_host = strdup(host);
1532
1533	/* save program name if any */
1534	if (prog && *prog == '*')
1535		prog = NULL;
1536	if (prog)
1537		f->f_program = strdup(prog);
1538
1539	/* scan through the list of selectors */
1540	for (p = line; *p && *p != '\t' && *p != ' ';) {
1541		int pri_done;
1542		int pri_cmp;
1543
1544		/* find the end of this facility name list */
1545		for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.'; )
1546			continue;
1547
1548		/* get the priority comparison */
1549		pri_cmp = 0;
1550		pri_done = 0;
1551		while (!pri_done) {
1552			switch (*q) {
1553			case '<':
1554				pri_cmp |= PRI_LT;
1555				q++;
1556				break;
1557			case '=':
1558				pri_cmp |= PRI_EQ;
1559				q++;
1560				break;
1561			case '>':
1562				pri_cmp |= PRI_GT;
1563				q++;
1564				break;
1565			default:
1566				pri_done++;
1567				break;
1568			}
1569		}
1570		if (!pri_cmp)
1571			pri_cmp = (UniquePriority)
1572				  ? (PRI_EQ)
1573				  : (PRI_EQ | PRI_GT)
1574				  ;
1575
1576		/* collect priority name */
1577		for (bp = buf; *q && !strchr("\t,; ", *q); )
1578			*bp++ = *q++;
1579		*bp = '\0';
1580
1581		/* skip cruft */
1582		while (strchr(",;", *q))
1583			q++;
1584
1585		/* decode priority name */
1586		if (*buf == '*')
1587			pri = LOG_PRIMASK + 1;
1588		else {
1589			pri = decode(buf, prioritynames);
1590			if (pri < 0) {
1591				(void)snprintf(ebuf, sizeof ebuf,
1592				    "unknown priority name \"%s\"", buf);
1593				logerror(ebuf);
1594				return;
1595			}
1596		}
1597
1598		/* scan facilities */
1599		while (*p && !strchr("\t.; ", *p)) {
1600			for (bp = buf; *p && !strchr("\t,;. ", *p); )
1601				*bp++ = *p++;
1602			*bp = '\0';
1603
1604			if (*buf == '*')
1605				for (i = 0; i < LOG_NFACILITIES; i++) {
1606					f->f_pmask[i] = pri;
1607					f->f_pcmp[i] = pri_cmp;
1608				}
1609			else {
1610				i = decode(buf, facilitynames);
1611				if (i < 0) {
1612					(void)snprintf(ebuf, sizeof ebuf,
1613					    "unknown facility name \"%s\"",
1614					    buf);
1615					logerror(ebuf);
1616					return;
1617				}
1618				f->f_pmask[i >> 3] = pri;
1619				f->f_pcmp[i >> 3] = pri_cmp;
1620			}
1621			while (*p == ',' || *p == ' ')
1622				p++;
1623		}
1624
1625		p = q;
1626	}
1627
1628	/* skip to action part */
1629	while (*p == '\t' || *p == ' ')
1630		p++;
1631
1632	switch (*p)
1633	{
1634	case '@':
1635		(void)strncpy(f->f_un.f_forw.f_hname, ++p,
1636			sizeof(f->f_un.f_forw.f_hname)-1);
1637		f->f_un.f_forw.f_hname[sizeof(f->f_un.f_forw.f_hname)-1] = '\0';
1638		memset(&hints, 0, sizeof(hints));
1639		hints.ai_family = family;
1640		hints.ai_socktype = SOCK_DGRAM;
1641		error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints,
1642				    &res);
1643		if (error) {
1644			logerror(gai_strerror(error));
1645			break;
1646		}
1647		f->f_un.f_forw.f_addr = res;
1648		f->f_type = F_FORW;
1649		break;
1650
1651	case '/':
1652		if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
1653			f->f_type = F_UNUSED;
1654			logerror(p);
1655			break;
1656		}
1657		if (isatty(f->f_file)) {
1658			if (strcmp(p, ctty) == 0)
1659				f->f_type = F_CONSOLE;
1660			else
1661				f->f_type = F_TTY;
1662			(void)strcpy(f->f_un.f_fname, p + sizeof _PATH_DEV - 1);
1663		} else {
1664			(void)strcpy(f->f_un.f_fname, p);
1665			f->f_type = F_FILE;
1666		}
1667		break;
1668
1669	case '|':
1670		f->f_un.f_pipe.f_pid = 0;
1671		(void)strcpy(f->f_un.f_pipe.f_pname, p + 1);
1672		f->f_type = F_PIPE;
1673		break;
1674
1675	case '*':
1676		f->f_type = F_WALL;
1677		break;
1678
1679	default:
1680		for (i = 0; i < MAXUNAMES && *p; i++) {
1681			for (q = p; *q && *q != ','; )
1682				q++;
1683			(void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
1684			if ((q - p) > UT_NAMESIZE)
1685				f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
1686			else
1687				f->f_un.f_uname[i][q - p] = '\0';
1688			while (*q == ',' || *q == ' ')
1689				q++;
1690			p = q;
1691		}
1692		f->f_type = F_USERS;
1693		break;
1694	}
1695}
1696
1697
1698/*
1699 *  Decode a symbolic name to a numeric value
1700 */
1701int
1702decode(name, codetab)
1703	const char *name;
1704	CODE *codetab;
1705{
1706	CODE *c;
1707	char *p, buf[40];
1708
1709	if (isdigit(*name))
1710		return (atoi(name));
1711
1712	for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
1713		if (isupper(*name))
1714			*p = tolower(*name);
1715		else
1716			*p = *name;
1717	}
1718	*p = '\0';
1719	for (c = codetab; c->c_name; c++)
1720		if (!strcmp(buf, c->c_name))
1721			return (c->c_val);
1722
1723	return (-1);
1724}
1725
1726/*
1727 * fork off and become a daemon, but wait for the child to come online
1728 * before returing to the parent, or we get disk thrashing at boot etc.
1729 * Set a timer so we don't hang forever if it wedges.
1730 */
1731int
1732waitdaemon(nochdir, noclose, maxwait)
1733	int nochdir, noclose, maxwait;
1734{
1735	int fd;
1736	int status;
1737	pid_t pid, childpid;
1738
1739	switch (childpid = fork()) {
1740	case -1:
1741		return (-1);
1742	case 0:
1743		break;
1744	default:
1745		signal(SIGALRM, timedout);
1746		alarm(maxwait);
1747		while ((pid = wait3(&status, 0, NULL)) != -1) {
1748			if (WIFEXITED(status))
1749				errx(1, "child pid %d exited with return code %d",
1750					pid, WEXITSTATUS(status));
1751			if (WIFSIGNALED(status))
1752				errx(1, "child pid %d exited on signal %d%s",
1753					pid, WTERMSIG(status),
1754					WCOREDUMP(status) ? " (core dumped)" :
1755					"");
1756			if (pid == childpid)	/* it's gone... */
1757				break;
1758		}
1759		exit(0);
1760	}
1761
1762	if (setsid() == -1)
1763		return (-1);
1764
1765	if (!nochdir)
1766		(void)chdir("/");
1767
1768	if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
1769		(void)dup2(fd, STDIN_FILENO);
1770		(void)dup2(fd, STDOUT_FILENO);
1771		(void)dup2(fd, STDERR_FILENO);
1772		if (fd > 2)
1773			(void)close (fd);
1774	}
1775	return (getppid());
1776}
1777
1778/*
1779 * We get a SIGALRM from the child when it's running and finished doing it's
1780 * fsync()'s or O_SYNC writes for all the boot messages.
1781 *
1782 * We also get a signal from the kernel if the timer expires, so check to
1783 * see what happened.
1784 */
1785void
1786timedout(sig)
1787	int sig __unused;
1788{
1789	int left;
1790	left = alarm(0);
1791	signal(SIGALRM, SIG_DFL);
1792	if (left == 0)
1793		errx(1, "timed out waiting for child");
1794	else
1795		exit(0);
1796}
1797
1798/*
1799 * Add `s' to the list of allowable peer addresses to accept messages
1800 * from.
1801 *
1802 * `s' is a string in the form:
1803 *
1804 *    [*]domainname[:{servicename|portnumber|*}]
1805 *
1806 * or
1807 *
1808 *    netaddr/maskbits[:{servicename|portnumber|*}]
1809 *
1810 * Returns -1 on error, 0 if the argument was valid.
1811 */
1812int
1813allowaddr(s)
1814	char *s;
1815{
1816	char *cp1, *cp2;
1817	struct allowedpeer ap;
1818	struct servent *se;
1819	int masklen = -1, i;
1820	struct addrinfo hints, *res;
1821	struct in_addr *addrp, *maskp;
1822	u_int32_t *addr6p, *mask6p;
1823	char ip[NI_MAXHOST];
1824
1825#ifdef INET6
1826	if (*s != '[' || (cp1 = strchr(s + 1, ']')) == NULL)
1827#endif
1828		cp1 = s;
1829	if ((cp1 = strrchr(cp1, ':'))) {
1830		/* service/port provided */
1831		*cp1++ = '\0';
1832		if (strlen(cp1) == 1 && *cp1 == '*')
1833			/* any port allowed */
1834			ap.port = 0;
1835		else if ((se = getservbyname(cp1, "udp")))
1836			ap.port = ntohs(se->s_port);
1837		else {
1838			ap.port = strtol(cp1, &cp2, 0);
1839			if (*cp2 != '\0')
1840				return -1; /* port not numeric */
1841		}
1842	} else {
1843		if ((se = getservbyname("syslog", "udp")))
1844			ap.port = ntohs(se->s_port);
1845		else
1846			/* sanity, should not happen */
1847			ap.port = 514;
1848	}
1849
1850	if ((cp1 = strchr(s, '/')) != NULL &&
1851	    strspn(cp1 + 1, "0123456789") == strlen(cp1 + 1)) {
1852		*cp1 = '\0';
1853		if ((masklen = atoi(cp1 + 1)) < 0)
1854			return -1;
1855	}
1856#ifdef INET6
1857	if (*s == '[') {
1858		cp2 = s + strlen(s) - 1;
1859		if (*cp2 == ']') {
1860			++s;
1861			*cp2 = '\0';
1862		} else
1863			cp2 = NULL;
1864	} else
1865		cp2 = NULL;
1866#endif
1867	memset(&hints, 0, sizeof(hints));
1868	hints.ai_family = PF_UNSPEC;
1869	hints.ai_socktype = SOCK_DGRAM;
1870	hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
1871	if (getaddrinfo(s, NULL, &hints, &res) == 0) {
1872		ap.isnumeric = 1;
1873		memcpy(&ap.a_addr, res->ai_addr, res->ai_addrlen);
1874		memset(&ap.a_mask, 0, sizeof(ap.a_mask));
1875		ap.a_mask.ss_family = res->ai_family;
1876		if (res->ai_family == AF_INET) {
1877			ap.a_mask.ss_len = sizeof(struct sockaddr_in);
1878			maskp = &((struct sockaddr_in *)&ap.a_mask)->sin_addr;
1879			addrp = &((struct sockaddr_in *)&ap.a_addr)->sin_addr;
1880			if (masklen < 0) {
1881				/* use default netmask */
1882				if (IN_CLASSA(ntohl(addrp->s_addr)))
1883					maskp->s_addr = htonl(IN_CLASSA_NET);
1884				else if (IN_CLASSB(ntohl(addrp->s_addr)))
1885					maskp->s_addr = htonl(IN_CLASSB_NET);
1886				else
1887					maskp->s_addr = htonl(IN_CLASSC_NET);
1888			} else if (masklen <= 32) {
1889				/* convert masklen to netmask */
1890				maskp->s_addr = htonl(~((1 << (32 - masklen)) - 1));
1891			} else {
1892				freeaddrinfo(res);
1893				return -1;
1894			}
1895			/* Lose any host bits in the network number. */
1896			addrp->s_addr &= maskp->s_addr;
1897		}
1898#ifdef INET6
1899		else if (res->ai_family == AF_INET6 && masklen <= 128) {
1900			ap.a_mask.ss_len = sizeof(struct sockaddr_in6);
1901			if (masklen < 0)
1902				masklen = 128;
1903			mask6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_mask)->sin6_addr;
1904			/* convert masklen to netmask */
1905			while (masklen > 0) {
1906				if (masklen < 32) {
1907					*mask6p = htonl(~(0xffffffff >> masklen));
1908					break;
1909				}
1910				*mask6p++ = 0xffffffff;
1911				masklen -= 32;
1912			}
1913			/* Lose any host bits in the network number. */
1914			mask6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_mask)->sin6_addr;
1915			addr6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_addr)->sin6_addr;
1916			for (i = 0; i < 4; i++)
1917				addr6p[i] &= mask6p[i];
1918		}
1919#endif
1920		else {
1921			freeaddrinfo(res);
1922			return -1;
1923		}
1924		freeaddrinfo(res);
1925	} else {
1926		/* arg `s' is domain name */
1927		ap.isnumeric = 0;
1928		ap.a_name = s;
1929		if (cp1)
1930			*cp1 = '/';
1931#ifdef INET6
1932		if (cp2) {
1933			*cp2 = ']';
1934			--s;
1935		}
1936#endif
1937	}
1938
1939	if (Debug) {
1940		printf("allowaddr: rule %d: ", NumAllowed);
1941		if (ap.isnumeric) {
1942			printf("numeric, ");
1943			getnameinfo((struct sockaddr *)&ap.a_addr,
1944				    ((struct sockaddr *)&ap.a_addr)->sa_len,
1945				    ip, sizeof ip, NULL, 0,
1946				    NI_NUMERICHOST | withscopeid);
1947			printf("addr = %s, ", ip);
1948			getnameinfo((struct sockaddr *)&ap.a_mask,
1949				    ((struct sockaddr *)&ap.a_mask)->sa_len,
1950				    ip, sizeof ip, NULL, 0,
1951				    NI_NUMERICHOST | withscopeid);
1952			printf("mask = %s; ", ip);
1953		} else
1954			printf("domainname = %s; ", ap.a_name);
1955		printf("port = %d\n", ap.port);
1956	}
1957
1958	if ((AllowedPeers = realloc(AllowedPeers,
1959				    ++NumAllowed * sizeof(struct allowedpeer)))
1960	    == NULL) {
1961		fprintf(stderr, "Out of memory!\n");
1962		exit(EX_OSERR);
1963	}
1964	memcpy(&AllowedPeers[NumAllowed - 1], &ap, sizeof(struct allowedpeer));
1965	return 0;
1966}
1967
1968/*
1969 * Validate that the remote peer has permission to log to us.
1970 */
1971int
1972validate(sa, hname)
1973	struct sockaddr *sa;
1974	const char *hname;
1975{
1976	int i, j, reject;
1977	size_t l1, l2;
1978	char *cp, name[NI_MAXHOST], ip[NI_MAXHOST], port[NI_MAXSERV];
1979	struct allowedpeer *ap;
1980	struct sockaddr_in *sin, *a4p = NULL, *m4p = NULL;
1981	struct sockaddr_in6 *sin6, *a6p = NULL, *m6p = NULL;
1982	struct addrinfo hints, *res;
1983	u_short sport;
1984
1985	if (NumAllowed == 0)
1986		/* traditional behaviour, allow everything */
1987		return 1;
1988
1989	strlcpy(name, hname, sizeof name);
1990	memset(&hints, 0, sizeof(hints));
1991	hints.ai_family = PF_UNSPEC;
1992	hints.ai_socktype = SOCK_DGRAM;
1993	hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
1994	if (getaddrinfo(name, NULL, &hints, &res) == 0)
1995		freeaddrinfo(res);
1996	else if (strchr(name, '.') == NULL) {
1997		strlcat(name, ".", sizeof name);
1998		strlcat(name, LocalDomain, sizeof name);
1999	}
2000	if (getnameinfo(sa, sa->sa_len, ip, sizeof ip, port, sizeof port,
2001			NI_NUMERICHOST | withscopeid | NI_NUMERICSERV) != 0)
2002		return 0;	/* for safety, should not occur */
2003	dprintf("validate: dgram from IP %s, port %s, name %s;\n",
2004		ip, port, name);
2005	sport = atoi(port);
2006
2007	/* now, walk down the list */
2008	for (i = 0, ap = AllowedPeers; i < NumAllowed; i++, ap++) {
2009		if (ap->port != 0 && ap->port != sport) {
2010			dprintf("rejected in rule %d due to port mismatch.\n", i);
2011			continue;
2012		}
2013
2014		if (ap->isnumeric) {
2015			if (ap->a_addr.ss_family != sa->sa_family) {
2016				dprintf("rejected in rule %d due to address family mismatch.\n", i);
2017				continue;
2018			}
2019			if (ap->a_addr.ss_family == AF_INET) {
2020				sin = (struct sockaddr_in *)sa;
2021				a4p = (struct sockaddr_in *)&ap->a_addr;
2022				m4p = (struct sockaddr_in *)&ap->a_mask;
2023				if ((sin->sin_addr.s_addr & m4p->sin_addr.s_addr)
2024				    != a4p->sin_addr.s_addr) {
2025					dprintf("rejected in rule %d due to IP mismatch.\n", i);
2026					continue;
2027				}
2028			}
2029#ifdef INET6
2030			else if (ap->a_addr.ss_family == AF_INET6) {
2031				sin6 = (struct sockaddr_in6 *)sa;
2032				a6p = (struct sockaddr_in6 *)&ap->a_addr;
2033				m6p = (struct sockaddr_in6 *)&ap->a_mask;
2034#ifdef NI_WITHSCOPEID
2035				if (a6p->sin6_scope_id != 0 &&
2036				    sin6->sin6_scope_id != a6p->sin6_scope_id) {
2037					dprintf("rejected in rule %d due to scope mismatch.\n", i);
2038					continue;
2039				}
2040#endif
2041				reject = 0;
2042				for (j = 0; j < 16; j += 4) {
2043					if ((*(u_int32_t *)&sin6->sin6_addr.s6_addr[j] & *(u_int32_t *)&m6p->sin6_addr.s6_addr[j])
2044					    != *(u_int32_t *)&a6p->sin6_addr.s6_addr[j]) {
2045						++reject;
2046						break;
2047					}
2048				}
2049				if (reject) {
2050					dprintf("rejected in rule %d due to IP mismatch.\n", i);
2051					continue;
2052				}
2053			}
2054#endif
2055			else
2056				continue;
2057		} else {
2058			cp = ap->a_name;
2059			l1 = strlen(name);
2060			if (*cp == '*') {
2061				/* allow wildmatch */
2062				cp++;
2063				l2 = strlen(cp);
2064				if (l2 > l1 || memcmp(cp, &name[l1 - l2], l2) != 0) {
2065					dprintf("rejected in rule %d due to name mismatch.\n", i);
2066					continue;
2067				}
2068			} else {
2069				/* exact match */
2070				l2 = strlen(cp);
2071				if (l2 != l1 || memcmp(cp, name, l1) != 0) {
2072					dprintf("rejected in rule %d due to name mismatch.\n", i);
2073					continue;
2074				}
2075			}
2076		}
2077		dprintf("accepted in rule %d.\n", i);
2078		return 1;	/* hooray! */
2079	}
2080	return 0;
2081}
2082
2083/*
2084 * Fairly similar to popen(3), but returns an open descriptor, as
2085 * opposed to a FILE *.
2086 */
2087int
2088p_open(prog, pid)
2089	char *prog;
2090	pid_t *pid;
2091{
2092	int pfd[2], nulldesc, i;
2093	sigset_t omask, mask;
2094	char *argv[4]; /* sh -c cmd NULL */
2095	char errmsg[200];
2096
2097	if (pipe(pfd) == -1)
2098		return -1;
2099	if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1)
2100		/* we are royally screwed anyway */
2101		return -1;
2102
2103	sigemptyset(&mask);
2104	sigaddset(&mask, SIGALRM);
2105	sigaddset(&mask, SIGHUP);
2106	sigprocmask(SIG_BLOCK, &mask, &omask);
2107	switch ((*pid = fork())) {
2108	case -1:
2109		sigprocmask(SIG_SETMASK, &omask, 0);
2110		close(nulldesc);
2111		return -1;
2112
2113	case 0:
2114		argv[0] = "sh";
2115		argv[1] = "-c";
2116		argv[2] = prog;
2117		argv[3] = NULL;
2118
2119		alarm(0);
2120		(void)setsid();	/* Avoid catching SIGHUPs. */
2121
2122		/*
2123		 * Throw away pending signals, and reset signal
2124		 * behaviour to standard values.
2125		 */
2126		signal(SIGALRM, SIG_IGN);
2127		signal(SIGHUP, SIG_IGN);
2128		sigprocmask(SIG_SETMASK, &omask, 0);
2129		signal(SIGPIPE, SIG_DFL);
2130		signal(SIGQUIT, SIG_DFL);
2131		signal(SIGALRM, SIG_DFL);
2132		signal(SIGHUP, SIG_DFL);
2133
2134		dup2(pfd[0], STDIN_FILENO);
2135		dup2(nulldesc, STDOUT_FILENO);
2136		dup2(nulldesc, STDERR_FILENO);
2137		for (i = getdtablesize(); i > 2; i--)
2138			(void) close(i);
2139
2140		(void) execvp(_PATH_BSHELL, argv);
2141		_exit(255);
2142	}
2143
2144	sigprocmask(SIG_SETMASK, &omask, 0);
2145	close(nulldesc);
2146	close(pfd[0]);
2147	/*
2148	 * Avoid blocking on a hung pipe.  With O_NONBLOCK, we are
2149	 * supposed to get an EWOULDBLOCK on writev(2), which is
2150	 * caught by the logic above anyway, which will in turn close
2151	 * the pipe, and fork a new logging subprocess if necessary.
2152	 * The stale subprocess will be killed some time later unless
2153	 * it terminated itself due to closing its input pipe (so we
2154	 * get rid of really dead puppies).
2155	 */
2156	if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
2157		/* This is bad. */
2158		(void)snprintf(errmsg, sizeof errmsg,
2159			       "Warning: cannot change pipe to PID %d to "
2160			       "non-blocking behaviour.",
2161			       (int)*pid);
2162		logerror(errmsg);
2163	}
2164	return pfd[1];
2165}
2166
2167void
2168deadq_enter(pid, name)
2169	pid_t pid;
2170	const char *name;
2171{
2172	dq_t p;
2173	int status;
2174
2175	/*
2176	 * Be paranoid, if we can't signal the process, don't enter it
2177	 * into the dead queue (perhaps it's already dead).  If possible,
2178	 * we try to fetch and log the child's status.
2179	 */
2180	if (kill(pid, 0) != 0) {
2181		if (waitpid(pid, &status, WNOHANG) > 0)
2182			log_deadchild(pid, status, name);
2183		return;
2184	}
2185
2186	p = malloc(sizeof(struct deadq_entry));
2187	if (p == 0) {
2188		errno = 0;
2189		logerror("panic: out of virtual memory!");
2190		exit(1);
2191	}
2192
2193	p->dq_pid = pid;
2194	p->dq_timeout = DQ_TIMO_INIT;
2195	TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries);
2196}
2197
2198int
2199deadq_remove(pid)
2200	pid_t pid;
2201{
2202	dq_t q;
2203
2204	for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries))
2205		if (q->dq_pid == pid) {
2206			TAILQ_REMOVE(&deadq_head, q, dq_entries);
2207				free(q);
2208				return 1;
2209		}
2210
2211	return 0;
2212}
2213
2214void
2215log_deadchild(pid, status, name)
2216	pid_t pid;
2217	int status;
2218	const char *name;
2219{
2220	int code;
2221	char buf[256];
2222	const char *reason;
2223
2224	errno = 0; /* Keep strerror() stuff out of logerror messages. */
2225	if (WIFSIGNALED(status)) {
2226		reason = "due to signal";
2227		code = WTERMSIG(status);
2228	} else {
2229		reason = "with status";
2230		code = WEXITSTATUS(status);
2231		if (code == 0)
2232			return;
2233	}
2234	(void)snprintf(buf, sizeof buf,
2235		       "Logging subprocess %d (%s) exited %s %d.",
2236		       pid, name, reason, code);
2237	logerror(buf);
2238}
2239
2240int *
2241socksetup(af)
2242	int af;
2243{
2244	struct addrinfo hints, *res, *r;
2245	int error, maxs, *s, *socks;
2246
2247	memset(&hints, 0, sizeof(hints));
2248	hints.ai_flags = AI_PASSIVE;
2249	hints.ai_family = af;
2250	hints.ai_socktype = SOCK_DGRAM;
2251	error = getaddrinfo(NULL, "syslog", &hints, &res);
2252	if (error) {
2253		logerror(gai_strerror(error));
2254		errno = 0;
2255		die(0);
2256	}
2257
2258	/* Count max number of sockets we may open */
2259	for (maxs = 0, r = res; r; r = r->ai_next, maxs++);
2260	socks = malloc((maxs+1) * sizeof(int));
2261	if (!socks) {
2262		logerror("couldn't allocate memory for sockets");
2263		die(0);
2264	}
2265
2266	*socks = 0;   /* num of sockets counter at start of array */
2267	s = socks + 1;
2268	for (r = res; r; r = r->ai_next) {
2269		*s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
2270		if (*s < 0) {
2271			logerror("socket");
2272			continue;
2273		}
2274#ifdef IPV6_BINDV6ONLY
2275		if (r->ai_family == AF_INET6) {
2276			int on = 1;
2277			if (setsockopt(*s, IPPROTO_IPV6, IPV6_BINDV6ONLY,
2278				       (char *)&on, sizeof (on)) < 0) {
2279				logerror("setsockopt");
2280				close(*s);
2281				continue;
2282			}
2283		}
2284#endif
2285		if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
2286			close(*s);
2287			logerror("bind");
2288			continue;
2289		}
2290
2291		(*socks)++;
2292		s++;
2293	}
2294
2295	if (*socks == 0) {
2296		free(socks);
2297		if (Debug)
2298			return(NULL);
2299		else
2300			die(0);
2301	}
2302	if (res)
2303		freeaddrinfo(res);
2304
2305	return(socks);
2306}
2307