syslogd.c revision 76431
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  "$FreeBSD: head/usr.sbin/syslogd/syslogd.c 76431 2001-05-10 15:48:33Z dwmalone $";
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 * -u and -v by Harlan Stenn.
71 * Priority comparison code by Harlan Stenn.
72 */
73
74#define	MAXLINE		1024		/* maximum line length */
75#define	MAXSVLINE	120		/* maximum saved line length */
76#define DEFUPRI		(LOG_USER|LOG_NOTICE)
77#define DEFSPRI		(LOG_KERN|LOG_CRIT)
78#define TIMERINTVL	30		/* interval for checking flush, mark */
79#define TTYMSGTIME	1		/* timed out passed to ttymsg */
80
81#include <sys/param.h>
82#include <sys/ioctl.h>
83#include <sys/stat.h>
84#include <sys/wait.h>
85#include <sys/socket.h>
86#include <sys/queue.h>
87#include <sys/uio.h>
88#include <sys/un.h>
89#include <sys/time.h>
90#include <sys/resource.h>
91#include <sys/syslimits.h>
92#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		v++;
905		v->iov_base = "";
906		v->iov_len = 0;
907		v++;
908	} else {
909		v->iov_base = f->f_lasttime;
910		v->iov_len = 15;
911		v++;
912		v->iov_base = " ";
913		v->iov_len = 1;
914		v++;
915	}
916
917	if (LogFacPri) {
918	  	static char fp_buf[30];	/* Hollow laugh */
919		int fac = f->f_prevpri & LOG_FACMASK;
920		int pri = LOG_PRI(f->f_prevpri);
921		char *f_s = 0;
922		char f_n[5];	/* Hollow laugh */
923		char *p_s = 0;
924		char p_n[5];	/* Hollow laugh */
925
926		if (LogFacPri > 1) {
927		  CODE *c;
928
929		  for (c = facilitynames; c->c_name; c++) {
930		    if (c->c_val == fac) {
931		      f_s = c->c_name;
932		      break;
933		    }
934		  }
935		  for (c = prioritynames; c->c_name; c++) {
936		    if (c->c_val == pri) {
937		      p_s = c->c_name;
938		      break;
939		    }
940		  }
941		}
942		if (!f_s) {
943		  snprintf(f_n, sizeof f_n, "%d", LOG_FAC(fac));
944		  f_s = f_n;
945		}
946		if (!p_s) {
947		  snprintf(p_n, sizeof p_n, "%d", pri);
948		  p_s = p_n;
949		}
950		snprintf(fp_buf, sizeof fp_buf, "<%s.%s> ", f_s, p_s);
951		v->iov_base = fp_buf;
952		v->iov_len = strlen(fp_buf);
953	} else {
954	        v->iov_base="";
955		v->iov_len = 0;
956	}
957	v++;
958
959	v->iov_base = f->f_prevhost;
960	v->iov_len = strlen(v->iov_base);
961	v++;
962	v->iov_base = " ";
963	v->iov_len = 1;
964	v++;
965
966	if (msg) {
967		v->iov_base = msg;
968		v->iov_len = strlen(msg);
969	} else if (f->f_prevcount > 1) {
970		v->iov_base = repbuf;
971		v->iov_len = sprintf(repbuf, "last message repeated %d times",
972		    f->f_prevcount);
973	} else {
974		v->iov_base = f->f_prevline;
975		v->iov_len = f->f_prevlen;
976	}
977	v++;
978
979	dprintf("Logging to %s", TypeNames[f->f_type]);
980	f->f_time = now;
981
982	switch (f->f_type) {
983	case F_UNUSED:
984		dprintf("\n");
985		break;
986
987	case F_FORW:
988		dprintf(" %s\n", f->f_un.f_forw.f_hname);
989		/* check for local vs remote messages */
990		if (strcasecmp(f->f_prevhost, LocalHostName))
991			l = snprintf(line, sizeof line - 1,
992			    "<%d>%.15s Forwarded from %s: %s",
993			    f->f_prevpri, iov[0].iov_base, f->f_prevhost,
994			    iov[5].iov_base);
995		else
996			l = snprintf(line, sizeof line - 1, "<%d>%.15s %s",
997			     f->f_prevpri, iov[0].iov_base, iov[5].iov_base);
998		if (l > MAXLINE)
999			l = MAXLINE;
1000
1001		if (finet) {
1002			for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
1003				for (i = 0; i < *finet; i++) {
1004#if 0
1005					/*
1006					 * should we check AF first, or just
1007					 * trial and error? FWD
1008					 */
1009					if (r->ai_family ==
1010					    address_family_of(finet[i+1]))
1011#endif
1012					lsent = sendto(finet[i+1], line, l, 0,
1013					    r->ai_addr, r->ai_addrlen);
1014					if (lsent == l)
1015						break;
1016				}
1017				if (lsent == l && !send_to_all)
1018					break;
1019			}
1020			if (lsent != l) {
1021				int e = errno;
1022				(void)close(f->f_file);
1023				errno = e;
1024				f->f_type = F_UNUSED;
1025				logerror("sendto");
1026			}
1027		}
1028		break;
1029
1030	case F_FILE:
1031		dprintf(" %s\n", f->f_un.f_fname);
1032		v->iov_base = "\n";
1033		v->iov_len = 1;
1034		if (writev(f->f_file, iov, 7) < 0) {
1035			int e = errno;
1036			(void)close(f->f_file);
1037			f->f_type = F_UNUSED;
1038			errno = e;
1039			logerror(f->f_un.f_fname);
1040		} else if (flags & SYNC_FILE)
1041			(void)fsync(f->f_file);
1042		break;
1043
1044	case F_PIPE:
1045		dprintf(" %s\n", f->f_un.f_pipe.f_pname);
1046		v->iov_base = "\n";
1047		v->iov_len = 1;
1048		if (f->f_un.f_pipe.f_pid == 0) {
1049			if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
1050						&f->f_un.f_pipe.f_pid)) < 0) {
1051				f->f_type = F_UNUSED;
1052				logerror(f->f_un.f_pipe.f_pname);
1053				break;
1054			}
1055		}
1056		if (writev(f->f_file, iov, 7) < 0) {
1057			int e = errno;
1058			(void)close(f->f_file);
1059			if (f->f_un.f_pipe.f_pid > 0)
1060				deadq_enter(f->f_un.f_pipe.f_pid,
1061					    f->f_un.f_pipe.f_pname);
1062			f->f_un.f_pipe.f_pid = 0;
1063			errno = e;
1064			logerror(f->f_un.f_pipe.f_pname);
1065		}
1066		break;
1067
1068	case F_CONSOLE:
1069		if (flags & IGN_CONS) {
1070			dprintf(" (ignored)\n");
1071			break;
1072		}
1073		/* FALLTHROUGH */
1074
1075	case F_TTY:
1076		dprintf(" %s%s\n", _PATH_DEV, f->f_un.f_fname);
1077		v->iov_base = "\r\n";
1078		v->iov_len = 2;
1079
1080		errno = 0;	/* ttymsg() only sometimes returns an errno */
1081		if ((msgret = ttymsg(iov, 7, f->f_un.f_fname, 10))) {
1082			f->f_type = F_UNUSED;
1083			logerror(msgret);
1084		}
1085		break;
1086
1087	case F_USERS:
1088	case F_WALL:
1089		dprintf("\n");
1090		v->iov_base = "\r\n";
1091		v->iov_len = 2;
1092		wallmsg(f, iov);
1093		break;
1094	}
1095	f->f_prevcount = 0;
1096}
1097
1098/*
1099 *  WALLMSG -- Write a message to the world at large
1100 *
1101 *	Write the specified message to either the entire
1102 *	world, or a list of approved users.
1103 */
1104void
1105wallmsg(f, iov)
1106	struct filed *f;
1107	struct iovec *iov;
1108{
1109	static int reenter;			/* avoid calling ourselves */
1110	FILE *uf;
1111	struct utmp ut;
1112	int i;
1113	char *p;
1114	char line[sizeof(ut.ut_line) + 1];
1115
1116	if (reenter++)
1117		return;
1118	if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
1119		logerror(_PATH_UTMP);
1120		reenter = 0;
1121		return;
1122	}
1123	/* NOSTRICT */
1124	while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) {
1125		if (ut.ut_name[0] == '\0')
1126			continue;
1127		strncpy(line, ut.ut_line, sizeof(ut.ut_line));
1128		line[sizeof(ut.ut_line)] = '\0';
1129		if (f->f_type == F_WALL) {
1130			if ((p = ttymsg(iov, 7, line, TTYMSGTIME)) != NULL) {
1131				errno = 0;	/* already in msg */
1132				logerror(p);
1133			}
1134			continue;
1135		}
1136		/* should we send the message to this user? */
1137		for (i = 0; i < MAXUNAMES; i++) {
1138			if (!f->f_un.f_uname[i][0])
1139				break;
1140			if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
1141			    UT_NAMESIZE)) {
1142				if ((p = ttymsg(iov, 7, line, TTYMSGTIME))
1143								!= NULL) {
1144					errno = 0;	/* already in msg */
1145					logerror(p);
1146				}
1147				break;
1148			}
1149		}
1150	}
1151	(void)fclose(uf);
1152	reenter = 0;
1153}
1154
1155void
1156reapchild(signo)
1157	int signo;
1158{
1159	int status;
1160	pid_t pid;
1161	struct filed *f;
1162
1163	while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) {
1164		if (!Initialized)
1165			/* Don't tell while we are initting. */
1166			continue;
1167
1168		/* First, look if it's a process from the dead queue. */
1169		if (deadq_remove(pid))
1170			goto oncemore;
1171
1172		/* Now, look in list of active processes. */
1173		for (f = Files; f; f = f->f_next)
1174			if (f->f_type == F_PIPE &&
1175			    f->f_un.f_pipe.f_pid == pid) {
1176				(void)close(f->f_file);
1177				f->f_un.f_pipe.f_pid = 0;
1178				log_deadchild(pid, status,
1179					      f->f_un.f_pipe.f_pname);
1180				break;
1181			}
1182	  oncemore:
1183		continue;
1184	}
1185}
1186
1187/*
1188 * Return a printable representation of a host address.
1189 */
1190char *
1191cvthname(f)
1192	struct sockaddr *f;
1193{
1194	int error;
1195	sigset_t omask, nmask;
1196	char *p;
1197	static char hname[NI_MAXHOST], ip[NI_MAXHOST];
1198
1199	error = getnameinfo((struct sockaddr *)f,
1200			    ((struct sockaddr *)f)->sa_len,
1201			    ip, sizeof ip, NULL, 0,
1202			    NI_NUMERICHOST | withscopeid);
1203	dprintf("cvthname(%s)\n", ip);
1204
1205	if (error) {
1206		dprintf("Malformed from address %s\n", gai_strerror(error));
1207		return ("???");
1208	}
1209	if (!resolve)
1210		return (ip);
1211
1212	sigemptyset(&nmask);
1213	sigaddset(&nmask, SIGHUP);
1214	sigprocmask(SIG_BLOCK, &nmask, &omask);
1215	error = getnameinfo((struct sockaddr *)f,
1216			    ((struct sockaddr *)f)->sa_len,
1217			    hname, sizeof hname, NULL, 0,
1218			    NI_NAMEREQD | withscopeid);
1219	sigprocmask(SIG_SETMASK, &omask, NULL);
1220	if (error) {
1221		dprintf("Host name for your address (%s) unknown\n", ip);
1222		return (ip);
1223	}
1224	if ((p = strchr(hname, '.')) && strcasecmp(p + 1, LocalDomain) == 0)
1225		*p = '\0';
1226	return (hname);
1227}
1228
1229void
1230domark(signo)
1231	int signo;
1232{
1233	struct filed *f;
1234	dq_t q;
1235
1236	now = time((time_t *)NULL);
1237	MarkSeq += TIMERINTVL;
1238	if (MarkSeq >= MarkInterval) {
1239		logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
1240		MarkSeq = 0;
1241	}
1242
1243	for (f = Files; f; f = f->f_next) {
1244		if (f->f_prevcount && now >= REPEATTIME(f)) {
1245			dprintf("flush %s: repeated %d times, %d sec.\n",
1246			    TypeNames[f->f_type], f->f_prevcount,
1247			    repeatinterval[f->f_repeatcount]);
1248			fprintlog(f, 0, (char *)NULL);
1249			BACKOFF(f);
1250		}
1251	}
1252
1253	/* Walk the dead queue, and see if we should signal somebody. */
1254	for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries))
1255		switch (q->dq_timeout) {
1256		case 0:
1257			/* Already signalled once, try harder now. */
1258			if (kill(q->dq_pid, SIGKILL) != 0)
1259				(void)deadq_remove(q->dq_pid);
1260			break;
1261
1262		case 1:
1263			/*
1264			 * Timed out on dead queue, send terminate
1265			 * signal.  Note that we leave the removal
1266			 * from the dead queue to reapchild(), which
1267			 * will also log the event (unless the process
1268			 * didn't even really exist, in case we simply
1269			 * drop it from the dead queue).
1270			 */
1271			if (kill(q->dq_pid, SIGTERM) != 0)
1272				(void)deadq_remove(q->dq_pid);
1273			/* FALLTHROUGH */
1274
1275		default:
1276			q->dq_timeout--;
1277		}
1278
1279	(void)alarm(TIMERINTVL);
1280}
1281
1282/*
1283 * Print syslogd errors some place.
1284 */
1285void
1286logerror(type)
1287	const char *type;
1288{
1289	char buf[512];
1290
1291	if (errno)
1292		(void)snprintf(buf,
1293		    sizeof buf, "syslogd: %s: %s", type, strerror(errno));
1294	else
1295		(void)snprintf(buf, sizeof buf, "syslogd: %s", type);
1296	errno = 0;
1297	dprintf("%s\n", buf);
1298	logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
1299}
1300
1301void
1302die(signo)
1303	int signo;
1304{
1305	struct filed *f;
1306	int was_initialized;
1307	char buf[100];
1308	int i;
1309
1310	was_initialized = Initialized;
1311	Initialized = 0;	/* Don't log SIGCHLDs. */
1312	for (f = Files; f != NULL; f = f->f_next) {
1313		/* flush any pending output */
1314		if (f->f_prevcount)
1315			fprintlog(f, 0, (char *)NULL);
1316		if (f->f_type == F_PIPE)
1317			(void)close(f->f_file);
1318	}
1319	Initialized = was_initialized;
1320	if (signo) {
1321		dprintf("syslogd: exiting on signal %d\n", signo);
1322		(void)sprintf(buf, "exiting on signal %d", signo);
1323		errno = 0;
1324		logerror(buf);
1325	}
1326	for (i = 0; i < nfunix; i++)
1327		if (funixn[i] && funix[i] != -1)
1328			(void)unlink(funixn[i]);
1329	exit(1);
1330}
1331
1332/*
1333 *  INIT -- Initialize syslogd from configuration table
1334 */
1335void
1336init(signo)
1337	int signo;
1338{
1339	int i;
1340	FILE *cf;
1341	struct filed *f, *next, **nextp;
1342	char *p;
1343	char cline[LINE_MAX];
1344 	char prog[NAME_MAX+1];
1345	char host[MAXHOSTNAMELEN];
1346
1347	dprintf("init\n");
1348
1349	/*
1350	 *  Close all open log files.
1351	 */
1352	Initialized = 0;
1353	for (f = Files; f != NULL; f = next) {
1354		/* flush any pending output */
1355		if (f->f_prevcount)
1356			fprintlog(f, 0, (char *)NULL);
1357
1358		switch (f->f_type) {
1359		case F_FILE:
1360		case F_FORW:
1361		case F_CONSOLE:
1362		case F_TTY:
1363			(void)close(f->f_file);
1364			break;
1365		case F_PIPE:
1366			(void)close(f->f_file);
1367			if (f->f_un.f_pipe.f_pid > 0)
1368				deadq_enter(f->f_un.f_pipe.f_pid,
1369					    f->f_un.f_pipe.f_pname);
1370			f->f_un.f_pipe.f_pid = 0;
1371			break;
1372		}
1373		next = f->f_next;
1374		if (f->f_program) free(f->f_program);
1375		if (f->f_host) free(f->f_host);
1376		free((char *)f);
1377	}
1378	Files = NULL;
1379	nextp = &Files;
1380
1381	/* open the configuration file */
1382	if ((cf = fopen(ConfFile, "r")) == NULL) {
1383		dprintf("cannot open %s\n", ConfFile);
1384		*nextp = (struct filed *)calloc(1, sizeof(*f));
1385		cfline("*.ERR\t/dev/console", *nextp, "*", "*");
1386		(*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
1387		cfline("*.PANIC\t*", (*nextp)->f_next, "*", "*");
1388		Initialized = 1;
1389		return;
1390	}
1391
1392	/*
1393	 *  Foreach line in the conf table, open that file.
1394	 */
1395	f = NULL;
1396	strcpy(host, "*");
1397	strcpy(prog, "*");
1398	while (fgets(cline, sizeof(cline), cf) != NULL) {
1399		/*
1400		 * check for end-of-section, comments, strip off trailing
1401		 * spaces and newline character. #!prog is treated specially:
1402		 * following lines apply only to that program.
1403		 */
1404		for (p = cline; isspace(*p); ++p)
1405			continue;
1406		if (*p == 0)
1407			continue;
1408		if (*p == '#') {
1409			p++;
1410			if (*p != '!' && *p != '+' && *p != '-')
1411				continue;
1412		}
1413		if (*p == '+' || *p == '-') {
1414			host[0] = *p++;
1415			while (isspace(*p)) p++;
1416			if ((!*p) || (*p == '*')) {
1417				strcpy(host, "*");
1418				continue;
1419			}
1420			if (*p == '@')
1421				p = LocalHostName;
1422			for (i = 1; i < MAXHOSTNAMELEN - 1; i++) {
1423				if (!isalnum(*p) && *p != '.' && *p != '-')
1424					break;
1425				host[i] = *p++;
1426			}
1427			host[i] = '\0';
1428			continue;
1429		}
1430		if (*p == '!') {
1431			p++;
1432			while (isspace(*p)) p++;
1433			if ((!*p) || (*p == '*')) {
1434				strcpy(prog, "*");
1435				continue;
1436			}
1437			for (i = 0; i < NAME_MAX; i++) {
1438				if (!isalnum(p[i]))
1439					break;
1440				prog[i] = p[i];
1441			}
1442			prog[i] = 0;
1443			continue;
1444		}
1445		for (p = strchr(cline, '\0'); isspace(*--p);)
1446			continue;
1447		*++p = '\0';
1448		f = (struct filed *)calloc(1, sizeof(*f));
1449		*nextp = f;
1450		nextp = &f->f_next;
1451		cfline(cline, f, prog, host);
1452	}
1453
1454	/* close the configuration file */
1455	(void)fclose(cf);
1456
1457	Initialized = 1;
1458
1459	if (Debug) {
1460		for (f = Files; f; f = f->f_next) {
1461			for (i = 0; i <= LOG_NFACILITIES; i++)
1462				if (f->f_pmask[i] == INTERNAL_NOPRI)
1463					printf("X ");
1464				else
1465					printf("%d ", f->f_pmask[i]);
1466			printf("%s: ", TypeNames[f->f_type]);
1467			switch (f->f_type) {
1468			case F_FILE:
1469				printf("%s", f->f_un.f_fname);
1470				break;
1471
1472			case F_CONSOLE:
1473			case F_TTY:
1474				printf("%s%s", _PATH_DEV, f->f_un.f_fname);
1475				break;
1476
1477			case F_FORW:
1478				printf("%s", f->f_un.f_forw.f_hname);
1479				break;
1480
1481			case F_PIPE:
1482				printf("%s", f->f_un.f_pipe.f_pname);
1483				break;
1484
1485			case F_USERS:
1486				for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
1487					printf("%s, ", f->f_un.f_uname[i]);
1488				break;
1489			}
1490			if (f->f_program)
1491				printf(" (%s)", f->f_program);
1492			printf("\n");
1493		}
1494	}
1495
1496	logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
1497	dprintf("syslogd: restarted\n");
1498}
1499
1500/*
1501 * Crack a configuration file line
1502 */
1503void
1504cfline(line, f, prog, host)
1505	char *line;
1506	struct filed *f;
1507	char *prog;
1508	char *host;
1509{
1510	struct addrinfo hints, *res;
1511	int error, i, pri;
1512	char *bp, *p, *q;
1513	char buf[MAXLINE], ebuf[100];
1514
1515	dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line, prog, host);
1516
1517	errno = 0;	/* keep strerror() stuff out of logerror messages */
1518
1519	/* clear out file entry */
1520	memset(f, 0, sizeof(*f));
1521	for (i = 0; i <= LOG_NFACILITIES; i++)
1522		f->f_pmask[i] = INTERNAL_NOPRI;
1523
1524	/* save hostname if any */
1525	if (host && *host == '*')
1526		host = NULL;
1527	if (host)
1528		f->f_host = strdup(host);
1529
1530	/* save program name if any */
1531	if (prog && *prog == '*')
1532		prog = NULL;
1533	if (prog)
1534		f->f_program = strdup(prog);
1535
1536	/* scan through the list of selectors */
1537	for (p = line; *p && *p != '\t' && *p != ' ';) {
1538		int pri_done;
1539		int pri_cmp;
1540
1541		/* find the end of this facility name list */
1542		for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.'; )
1543			continue;
1544
1545		/* get the priority comparison */
1546		pri_cmp = 0;
1547		pri_done = 0;
1548		while (!pri_done) {
1549			switch (*q) {
1550			case '<':
1551				pri_cmp |= PRI_LT;
1552				q++;
1553				break;
1554			case '=':
1555				pri_cmp |= PRI_EQ;
1556				q++;
1557				break;
1558			case '>':
1559				pri_cmp |= PRI_GT;
1560				q++;
1561				break;
1562			default:
1563				pri_done++;
1564				break;
1565			}
1566		}
1567		if (!pri_cmp)
1568			pri_cmp = (UniquePriority)
1569				  ? (PRI_EQ)
1570				  : (PRI_EQ | PRI_GT)
1571				  ;
1572
1573		/* collect priority name */
1574		for (bp = buf; *q && !strchr("\t,; ", *q); )
1575			*bp++ = *q++;
1576		*bp = '\0';
1577
1578		/* skip cruft */
1579		while (strchr(",;", *q))
1580			q++;
1581
1582		/* decode priority name */
1583		if (*buf == '*')
1584			pri = LOG_PRIMASK + 1;
1585		else {
1586			pri = decode(buf, prioritynames);
1587			if (pri < 0) {
1588				(void)snprintf(ebuf, sizeof ebuf,
1589				    "unknown priority name \"%s\"", buf);
1590				logerror(ebuf);
1591				return;
1592			}
1593		}
1594
1595		/* scan facilities */
1596		while (*p && !strchr("\t.; ", *p)) {
1597			for (bp = buf; *p && !strchr("\t,;. ", *p); )
1598				*bp++ = *p++;
1599			*bp = '\0';
1600
1601			if (*buf == '*')
1602				for (i = 0; i < LOG_NFACILITIES; i++) {
1603					f->f_pmask[i] = pri;
1604					f->f_pcmp[i] = pri_cmp;
1605				}
1606			else {
1607				i = decode(buf, facilitynames);
1608				if (i < 0) {
1609					(void)snprintf(ebuf, sizeof ebuf,
1610					    "unknown facility name \"%s\"",
1611					    buf);
1612					logerror(ebuf);
1613					return;
1614				}
1615				f->f_pmask[i >> 3] = pri;
1616				f->f_pcmp[i >> 3] = pri_cmp;
1617			}
1618			while (*p == ',' || *p == ' ')
1619				p++;
1620		}
1621
1622		p = q;
1623	}
1624
1625	/* skip to action part */
1626	while (*p == '\t' || *p == ' ')
1627		p++;
1628
1629	switch (*p)
1630	{
1631	case '@':
1632		(void)strncpy(f->f_un.f_forw.f_hname, ++p,
1633			sizeof(f->f_un.f_forw.f_hname)-1);
1634		f->f_un.f_forw.f_hname[sizeof(f->f_un.f_forw.f_hname)-1] = '\0';
1635		memset(&hints, 0, sizeof(hints));
1636		hints.ai_family = family;
1637		hints.ai_socktype = SOCK_DGRAM;
1638		error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints,
1639				    &res);
1640		if (error) {
1641			logerror(gai_strerror(error));
1642			break;
1643		}
1644		f->f_un.f_forw.f_addr = res;
1645		f->f_type = F_FORW;
1646		break;
1647
1648	case '/':
1649		if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
1650			f->f_type = F_UNUSED;
1651			logerror(p);
1652			break;
1653		}
1654		if (isatty(f->f_file)) {
1655			if (strcmp(p, ctty) == 0)
1656				f->f_type = F_CONSOLE;
1657			else
1658				f->f_type = F_TTY;
1659			(void)strcpy(f->f_un.f_fname, p + sizeof _PATH_DEV - 1);
1660		} else {
1661			(void)strcpy(f->f_un.f_fname, p);
1662			f->f_type = F_FILE;
1663		}
1664		break;
1665
1666	case '|':
1667		f->f_un.f_pipe.f_pid = 0;
1668		(void)strcpy(f->f_un.f_pipe.f_pname, p + 1);
1669		f->f_type = F_PIPE;
1670		break;
1671
1672	case '*':
1673		f->f_type = F_WALL;
1674		break;
1675
1676	default:
1677		for (i = 0; i < MAXUNAMES && *p; i++) {
1678			for (q = p; *q && *q != ','; )
1679				q++;
1680			(void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
1681			if ((q - p) > UT_NAMESIZE)
1682				f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
1683			else
1684				f->f_un.f_uname[i][q - p] = '\0';
1685			while (*q == ',' || *q == ' ')
1686				q++;
1687			p = q;
1688		}
1689		f->f_type = F_USERS;
1690		break;
1691	}
1692}
1693
1694
1695/*
1696 *  Decode a symbolic name to a numeric value
1697 */
1698int
1699decode(name, codetab)
1700	const char *name;
1701	CODE *codetab;
1702{
1703	CODE *c;
1704	char *p, buf[40];
1705
1706	if (isdigit(*name))
1707		return (atoi(name));
1708
1709	for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
1710		if (isupper(*name))
1711			*p = tolower(*name);
1712		else
1713			*p = *name;
1714	}
1715	*p = '\0';
1716	for (c = codetab; c->c_name; c++)
1717		if (!strcmp(buf, c->c_name))
1718			return (c->c_val);
1719
1720	return (-1);
1721}
1722
1723/*
1724 * fork off and become a daemon, but wait for the child to come online
1725 * before returing to the parent, or we get disk thrashing at boot etc.
1726 * Set a timer so we don't hang forever if it wedges.
1727 */
1728int
1729waitdaemon(nochdir, noclose, maxwait)
1730	int nochdir, noclose, maxwait;
1731{
1732	int fd;
1733	int status;
1734	pid_t pid, childpid;
1735
1736	switch (childpid = fork()) {
1737	case -1:
1738		return (-1);
1739	case 0:
1740		break;
1741	default:
1742		signal(SIGALRM, timedout);
1743		alarm(maxwait);
1744		while ((pid = wait3(&status, 0, NULL)) != -1) {
1745			if (WIFEXITED(status))
1746				errx(1, "child pid %d exited with return code %d",
1747					pid, WEXITSTATUS(status));
1748			if (WIFSIGNALED(status))
1749				errx(1, "child pid %d exited on signal %d%s",
1750					pid, WTERMSIG(status),
1751					WCOREDUMP(status) ? " (core dumped)" :
1752					"");
1753			if (pid == childpid)	/* it's gone... */
1754				break;
1755		}
1756		exit(0);
1757	}
1758
1759	if (setsid() == -1)
1760		return (-1);
1761
1762	if (!nochdir)
1763		(void)chdir("/");
1764
1765	if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
1766		(void)dup2(fd, STDIN_FILENO);
1767		(void)dup2(fd, STDOUT_FILENO);
1768		(void)dup2(fd, STDERR_FILENO);
1769		if (fd > 2)
1770			(void)close (fd);
1771	}
1772	return (getppid());
1773}
1774
1775/*
1776 * We get a SIGALRM from the child when it's running and finished doing it's
1777 * fsync()'s or O_SYNC writes for all the boot messages.
1778 *
1779 * We also get a signal from the kernel if the timer expires, so check to
1780 * see what happened.
1781 */
1782void
1783timedout(sig)
1784	int sig __unused;
1785{
1786	int left;
1787	left = alarm(0);
1788	signal(SIGALRM, SIG_DFL);
1789	if (left == 0)
1790		errx(1, "timed out waiting for child");
1791	else
1792		exit(0);
1793}
1794
1795/*
1796 * Add `s' to the list of allowable peer addresses to accept messages
1797 * from.
1798 *
1799 * `s' is a string in the form:
1800 *
1801 *    [*]domainname[:{servicename|portnumber|*}]
1802 *
1803 * or
1804 *
1805 *    netaddr/maskbits[:{servicename|portnumber|*}]
1806 *
1807 * Returns -1 on error, 0 if the argument was valid.
1808 */
1809int
1810allowaddr(s)
1811	char *s;
1812{
1813	char *cp1, *cp2;
1814	struct allowedpeer ap;
1815	struct servent *se;
1816	int masklen = -1;
1817	struct addrinfo hints, *res;
1818	struct in_addr *addrp, *maskp;
1819	u_int32_t *mask6p;
1820	char ip[NI_MAXHOST];
1821
1822#ifdef INET6
1823	if (*s != '[' || (cp1 = strchr(s + 1, ']')) == NULL)
1824#endif
1825		cp1 = s;
1826	if ((cp1 = strrchr(cp1, ':'))) {
1827		/* service/port provided */
1828		*cp1++ = '\0';
1829		if (strlen(cp1) == 1 && *cp1 == '*')
1830			/* any port allowed */
1831			ap.port = 0;
1832		else if ((se = getservbyname(cp1, "udp")))
1833			ap.port = ntohs(se->s_port);
1834		else {
1835			ap.port = strtol(cp1, &cp2, 0);
1836			if (*cp2 != '\0')
1837				return -1; /* port not numeric */
1838		}
1839	} else {
1840		if ((se = getservbyname("syslog", "udp")))
1841			ap.port = ntohs(se->s_port);
1842		else
1843			/* sanity, should not happen */
1844			ap.port = 514;
1845	}
1846
1847	if ((cp1 = strchr(s, '/')) != NULL &&
1848	    strspn(cp1 + 1, "0123456789") == strlen(cp1 + 1)) {
1849		*cp1 = '\0';
1850		if ((masklen = atoi(cp1 + 1)) < 0)
1851			return -1;
1852	}
1853#ifdef INET6
1854	if (*s == '[') {
1855		cp2 = s + strlen(s) - 1;
1856		if (*cp2 == ']') {
1857			++s;
1858			*cp2 = '\0';
1859		} else
1860			cp2 = NULL;
1861	} else
1862		cp2 = NULL;
1863#endif
1864	memset(&hints, 0, sizeof(hints));
1865	hints.ai_family = PF_UNSPEC;
1866	hints.ai_socktype = SOCK_DGRAM;
1867	hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
1868	if (getaddrinfo(s, NULL, &hints, &res) == 0) {
1869		ap.isnumeric = 1;
1870		memcpy(&ap.a_addr, res->ai_addr, res->ai_addrlen);
1871		memset(&ap.a_mask, 0, sizeof(ap.a_mask));
1872		ap.a_mask.ss_family = res->ai_family;
1873		if (res->ai_family == AF_INET) {
1874			ap.a_mask.ss_len = sizeof(struct sockaddr_in);
1875			maskp = &((struct sockaddr_in *)&ap.a_mask)->sin_addr;
1876			if (masklen < 0) {
1877				/* use default netmask */
1878				addrp = &((struct sockaddr_in *)&ap.a_addr)->sin_addr;
1879				if (IN_CLASSA(ntohl(addrp->s_addr)))
1880					maskp->s_addr = htonl(IN_CLASSA_NET);
1881				else if (IN_CLASSB(ntohl(addrp->s_addr)))
1882					maskp->s_addr = htonl(IN_CLASSB_NET);
1883				else
1884					maskp->s_addr = htonl(IN_CLASSC_NET);
1885			} else if (masklen <= 32) {
1886				/* convert masklen to netmask */
1887				maskp->s_addr = htonl(~((1 << (32 - masklen)) - 1));
1888			} else {
1889				freeaddrinfo(res);
1890				return -1;
1891			}
1892		}
1893#ifdef INET6
1894		else if (res->ai_family == AF_INET6 && masklen <= 128) {
1895			ap.a_mask.ss_len = sizeof(struct sockaddr_in6);
1896			if (masklen < 0)
1897				masklen = 128;
1898			mask6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_mask)->sin6_addr;
1899			/* convert masklen to netmask */
1900			while (masklen > 0) {
1901				if (masklen < 32) {
1902					*mask6p = htonl(~(0xffffffff >> masklen));
1903					break;
1904				}
1905				*mask6p++ = 0xffffffff;
1906				masklen -= 32;
1907			}
1908		}
1909#endif
1910		else {
1911			freeaddrinfo(res);
1912			return -1;
1913		}
1914		freeaddrinfo(res);
1915	} else {
1916		/* arg `s' is domain name */
1917		ap.isnumeric = 0;
1918		ap.a_name = s;
1919		if (cp1)
1920			*cp1 = '/';
1921#ifdef INET6
1922		if (cp2) {
1923			*cp2 = ']';
1924			--s;
1925		}
1926#endif
1927	}
1928
1929	if (Debug) {
1930		printf("allowaddr: rule %d: ", NumAllowed);
1931		if (ap.isnumeric) {
1932			printf("numeric, ");
1933			getnameinfo((struct sockaddr *)&ap.a_addr,
1934				    ((struct sockaddr *)&ap.a_addr)->sa_len,
1935				    ip, sizeof ip, NULL, 0,
1936				    NI_NUMERICHOST | withscopeid);
1937			printf("addr = %s, ", ip);
1938			getnameinfo((struct sockaddr *)&ap.a_mask,
1939				    ((struct sockaddr *)&ap.a_mask)->sa_len,
1940				    ip, sizeof ip, NULL, 0,
1941				    NI_NUMERICHOST | withscopeid);
1942			printf("mask = %s; ", ip);
1943		} else
1944			printf("domainname = %s; ", ap.a_name);
1945		printf("port = %d\n", ap.port);
1946	}
1947
1948	if ((AllowedPeers = realloc(AllowedPeers,
1949				    ++NumAllowed * sizeof(struct allowedpeer)))
1950	    == NULL) {
1951		fprintf(stderr, "Out of memory!\n");
1952		exit(EX_OSERR);
1953	}
1954	memcpy(&AllowedPeers[NumAllowed - 1], &ap, sizeof(struct allowedpeer));
1955	return 0;
1956}
1957
1958/*
1959 * Validate that the remote peer has permission to log to us.
1960 */
1961int
1962validate(sa, hname)
1963	struct sockaddr *sa;
1964	const char *hname;
1965{
1966	int i, j, reject;
1967	size_t l1, l2;
1968	char *cp, name[NI_MAXHOST], ip[NI_MAXHOST], port[NI_MAXSERV];
1969	struct allowedpeer *ap;
1970	struct sockaddr_in *sin, *a4p = NULL, *m4p = NULL;
1971	struct sockaddr_in6 *sin6, *a6p = NULL, *m6p = NULL;
1972	struct addrinfo hints, *res;
1973	u_short sport;
1974
1975	if (NumAllowed == 0)
1976		/* traditional behaviour, allow everything */
1977		return 1;
1978
1979	strlcpy(name, hname, sizeof name);
1980	memset(&hints, 0, sizeof(hints));
1981	hints.ai_family = PF_UNSPEC;
1982	hints.ai_socktype = SOCK_DGRAM;
1983	hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
1984	if (getaddrinfo(name, NULL, &hints, &res) == 0)
1985		freeaddrinfo(res);
1986	else if (strchr(name, '.') == NULL) {
1987		strlcat(name, ".", sizeof name);
1988		strlcat(name, LocalDomain, sizeof name);
1989	}
1990	if (getnameinfo(sa, sa->sa_len, ip, sizeof ip, port, sizeof port,
1991			NI_NUMERICHOST | withscopeid | NI_NUMERICSERV) != 0)
1992		return 0;	/* for safety, should not occur */
1993	dprintf("validate: dgram from IP %s, port %s, name %s;\n",
1994		ip, port, name);
1995	sport = atoi(port);
1996
1997	/* now, walk down the list */
1998	for (i = 0, ap = AllowedPeers; i < NumAllowed; i++, ap++) {
1999		if (ap->port != 0 && ap->port != sport) {
2000			dprintf("rejected in rule %d due to port mismatch.\n", i);
2001			continue;
2002		}
2003
2004		if (ap->isnumeric) {
2005			if (ap->a_addr.ss_family != sa->sa_family) {
2006				dprintf("rejected in rule %d due to address family mismatch.\n", i);
2007				continue;
2008			}
2009			if (ap->a_addr.ss_family == AF_INET) {
2010				sin = (struct sockaddr_in *)sa;
2011				a4p = (struct sockaddr_in *)&ap->a_addr;
2012				m4p = (struct sockaddr_in *)&ap->a_mask;
2013				if ((sin->sin_addr.s_addr & m4p->sin_addr.s_addr)
2014				    != a4p->sin_addr.s_addr) {
2015					dprintf("rejected in rule %d due to IP mismatch.\n", i);
2016					continue;
2017				}
2018			}
2019#ifdef INET6
2020			else if (ap->a_addr.ss_family == AF_INET6) {
2021				sin6 = (struct sockaddr_in6 *)sa;
2022				a6p = (struct sockaddr_in6 *)&ap->a_addr;
2023				m6p = (struct sockaddr_in6 *)&ap->a_mask;
2024#ifdef NI_WITHSCOPEID
2025				if (a6p->sin6_scope_id != 0 &&
2026				    sin6->sin6_scope_id != a6p->sin6_scope_id) {
2027					dprintf("rejected in rule %d due to scope mismatch.\n", i);
2028					continue;
2029				}
2030#endif
2031				reject = 0;
2032				for (j = 0; j < 16; j += 4) {
2033					if ((*(u_int32_t *)&sin6->sin6_addr.s6_addr[i] & *(u_int32_t *)&m6p->sin6_addr.s6_addr[i])
2034					    != *(u_int32_t *)&a6p->sin6_addr.s6_addr[i]) {
2035						++reject;
2036						break;
2037					}
2038				}
2039				if (reject) {
2040					dprintf("rejected in rule %d due to IP mismatch.\n", i);
2041					continue;
2042				}
2043			}
2044#endif
2045			else
2046				continue;
2047		} else {
2048			cp = ap->a_name;
2049			l1 = strlen(name);
2050			if (*cp == '*') {
2051				/* allow wildmatch */
2052				cp++;
2053				l2 = strlen(cp);
2054				if (l2 > l1 || memcmp(cp, &name[l1 - l2], l2) != 0) {
2055					dprintf("rejected in rule %d due to name mismatch.\n", i);
2056					continue;
2057				}
2058			} else {
2059				/* exact match */
2060				l2 = strlen(cp);
2061				if (l2 != l1 || memcmp(cp, name, l1) != 0) {
2062					dprintf("rejected in rule %d due to name mismatch.\n", i);
2063					continue;
2064				}
2065			}
2066		}
2067		dprintf("accepted in rule %d.\n", i);
2068		return 1;	/* hooray! */
2069	}
2070	return 0;
2071}
2072
2073/*
2074 * Fairly similar to popen(3), but returns an open descriptor, as
2075 * opposed to a FILE *.
2076 */
2077int
2078p_open(prog, pid)
2079	char *prog;
2080	pid_t *pid;
2081{
2082	int pfd[2], nulldesc, i;
2083	sigset_t omask, mask;
2084	char *argv[4]; /* sh -c cmd NULL */
2085	char errmsg[200];
2086
2087	if (pipe(pfd) == -1)
2088		return -1;
2089	if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1)
2090		/* we are royally screwed anyway */
2091		return -1;
2092
2093	sigemptyset(&mask);
2094	sigaddset(&mask, SIGALRM);
2095	sigaddset(&mask, SIGHUP);
2096	sigprocmask(SIG_BLOCK, &mask, &omask);
2097	switch ((*pid = fork())) {
2098	case -1:
2099		sigprocmask(SIG_SETMASK, &omask, 0);
2100		close(nulldesc);
2101		return -1;
2102
2103	case 0:
2104		argv[0] = "sh";
2105		argv[1] = "-c";
2106		argv[2] = prog;
2107		argv[3] = NULL;
2108
2109		alarm(0);
2110		(void)setsid();	/* Avoid catching SIGHUPs. */
2111
2112		/*
2113		 * Throw away pending signals, and reset signal
2114		 * behaviour to standard values.
2115		 */
2116		signal(SIGALRM, SIG_IGN);
2117		signal(SIGHUP, SIG_IGN);
2118		sigprocmask(SIG_SETMASK, &omask, 0);
2119		signal(SIGPIPE, SIG_DFL);
2120		signal(SIGQUIT, SIG_DFL);
2121		signal(SIGALRM, SIG_DFL);
2122		signal(SIGHUP, SIG_DFL);
2123
2124		dup2(pfd[0], STDIN_FILENO);
2125		dup2(nulldesc, STDOUT_FILENO);
2126		dup2(nulldesc, STDERR_FILENO);
2127		for (i = getdtablesize(); i > 2; i--)
2128			(void) close(i);
2129
2130		(void) execvp(_PATH_BSHELL, argv);
2131		_exit(255);
2132	}
2133
2134	sigprocmask(SIG_SETMASK, &omask, 0);
2135	close(nulldesc);
2136	close(pfd[0]);
2137	/*
2138	 * Avoid blocking on a hung pipe.  With O_NONBLOCK, we are
2139	 * supposed to get an EWOULDBLOCK on writev(2), which is
2140	 * caught by the logic above anyway, which will in turn close
2141	 * the pipe, and fork a new logging subprocess if necessary.
2142	 * The stale subprocess will be killed some time later unless
2143	 * it terminated itself due to closing its input pipe (so we
2144	 * get rid of really dead puppies).
2145	 */
2146	if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
2147		/* This is bad. */
2148		(void)snprintf(errmsg, sizeof errmsg,
2149			       "Warning: cannot change pipe to PID %d to "
2150			       "non-blocking behaviour.",
2151			       (int)*pid);
2152		logerror(errmsg);
2153	}
2154	return pfd[1];
2155}
2156
2157void
2158deadq_enter(pid, name)
2159	pid_t pid;
2160	const char *name;
2161{
2162	dq_t p;
2163	int status;
2164
2165	/*
2166	 * Be paranoid, if we can't signal the process, don't enter it
2167	 * into the dead queue (perhaps it's already dead).  If possible,
2168	 * we try to fetch and log the child's status.
2169	 */
2170	if (kill(pid, 0) != 0) {
2171		if (waitpid(pid, &status, WNOHANG) > 0)
2172			log_deadchild(pid, status, name);
2173		return;
2174	}
2175
2176	p = malloc(sizeof(struct deadq_entry));
2177	if (p == 0) {
2178		errno = 0;
2179		logerror("panic: out of virtual memory!");
2180		exit(1);
2181	}
2182
2183	p->dq_pid = pid;
2184	p->dq_timeout = DQ_TIMO_INIT;
2185	TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries);
2186}
2187
2188int
2189deadq_remove(pid)
2190	pid_t pid;
2191{
2192	dq_t q;
2193
2194	for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries))
2195		if (q->dq_pid == pid) {
2196			TAILQ_REMOVE(&deadq_head, q, dq_entries);
2197				free(q);
2198				return 1;
2199		}
2200
2201	return 0;
2202}
2203
2204void
2205log_deadchild(pid, status, name)
2206	pid_t pid;
2207	int status;
2208	const char *name;
2209{
2210	int code;
2211	char buf[256];
2212	const char *reason;
2213
2214	errno = 0; /* Keep strerror() stuff out of logerror messages. */
2215	if (WIFSIGNALED(status)) {
2216		reason = "due to signal";
2217		code = WTERMSIG(status);
2218	} else {
2219		reason = "with status";
2220		code = WEXITSTATUS(status);
2221		if (code == 0)
2222			return;
2223	}
2224	(void)snprintf(buf, sizeof buf,
2225		       "Logging subprocess %d (%s) exited %s %d.",
2226		       pid, name, reason, code);
2227	logerror(buf);
2228}
2229
2230int *
2231socksetup(af)
2232	int af;
2233{
2234	struct addrinfo hints, *res, *r;
2235	int error, maxs, *s, *socks;
2236
2237	memset(&hints, 0, sizeof(hints));
2238	hints.ai_flags = AI_PASSIVE;
2239	hints.ai_family = af;
2240	hints.ai_socktype = SOCK_DGRAM;
2241	error = getaddrinfo(NULL, "syslog", &hints, &res);
2242	if (error) {
2243		logerror(gai_strerror(error));
2244		errno = 0;
2245		die(0);
2246	}
2247
2248	/* Count max number of sockets we may open */
2249	for (maxs = 0, r = res; r; r = r->ai_next, maxs++);
2250	socks = malloc((maxs+1) * sizeof(int));
2251	if (!socks) {
2252		logerror("couldn't allocate memory for sockets");
2253		die(0);
2254	}
2255
2256	*socks = 0;   /* num of sockets counter at start of array */
2257	s = socks + 1;
2258	for (r = res; r; r = r->ai_next) {
2259		*s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
2260		if (*s < 0) {
2261			logerror("socket");
2262			continue;
2263		}
2264#ifdef IPV6_BINDV6ONLY
2265		if (r->ai_family == AF_INET6) {
2266			int on = 1;
2267			if (setsockopt(*s, IPPROTO_IPV6, IPV6_BINDV6ONLY,
2268				       (char *)&on, sizeof (on)) < 0) {
2269				logerror("setsockopt");
2270				close(*s);
2271				continue;
2272			}
2273		}
2274#endif
2275		if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
2276			close(*s);
2277			logerror("bind");
2278			continue;
2279		}
2280
2281		(*socks)++;
2282		s++;
2283	}
2284
2285	if (*socks == 0) {
2286		free(socks);
2287		if (Debug)
2288			return(NULL);
2289		else
2290			die(0);
2291	}
2292	if (res)
2293		freeaddrinfo(res);
2294
2295	return(socks);
2296}
2297