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