xref: /netbsd-src/usr.sbin/syslogd/syslogd.c (revision d48f14661dda8638fee055ba15d35bdfb29b9fa8)
1 /*	$NetBSD: syslogd.c,v 1.78 2006/04/24 19:00:30 snj Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1988, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993, 1994\n\
35 	The Regents of the University of California.  All rights reserved.\n");
36 #endif /* not lint */
37 
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)syslogd.c	8.3 (Berkeley) 4/4/94";
41 #else
42 __RCSID("$NetBSD: syslogd.c,v 1.78 2006/04/24 19:00:30 snj Exp $");
43 #endif
44 #endif /* not lint */
45 
46 /*
47  *  syslogd -- log system messages
48  *
49  * This program implements a system log. It takes a series of lines.
50  * Each line may have a priority, signified as "<n>" as
51  * the first characters of the line.  If this is
52  * not present, a default priority is used.
53  *
54  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
55  * cause it to reread its configuration file.
56  *
57  * Defined Constants:
58  *
59  * MAXLINE -- the maximimum line length that can be handled.
60  * DEFUPRI -- the default priority for user messages
61  * DEFSPRI -- the default priority for kernel messages
62  *
63  * Author: Eric Allman
64  * extensive changes by Ralph Campbell
65  * more extensive changes by Eric Allman (again)
66  * Extension to log by program name as well as facility and priority
67  *   by Peter da Silva.
68  * -U and -v by Harlan Stenn.
69  * Priority comparison code by Harlan Stenn.
70  */
71 
72 #define	MAXLINE		1024		/* maximum line length */
73 #define	MAXSVLINE	120		/* maximum saved line length */
74 #define DEFUPRI		(LOG_USER|LOG_NOTICE)
75 #define DEFSPRI		(LOG_KERN|LOG_NOTICE)
76 #define TIMERINTVL	30		/* interval for checking flush, mark */
77 #define TTYMSGTIME	1		/* timeout passed to ttymsg */
78 
79 #include <sys/param.h>
80 #include <sys/socket.h>
81 #include <sys/sysctl.h>
82 #include <sys/types.h>
83 #include <sys/un.h>
84 #include <sys/wait.h>
85 #include <sys/queue.h>
86 #include <sys/event.h>
87 
88 #include <netinet/in.h>
89 
90 #include <assert.h>
91 #include <ctype.h>
92 #include <errno.h>
93 #include <fcntl.h>
94 #include <grp.h>
95 #include <locale.h>
96 #include <netdb.h>
97 #include <pwd.h>
98 #include <signal.h>
99 #include <stdarg.h>
100 #include <stdio.h>
101 #include <stdlib.h>
102 #include <string.h>
103 #include <unistd.h>
104 #include <util.h>
105 
106 #include "utmpentry.h"
107 #include "pathnames.h"
108 
109 #define SYSLOG_NAMES
110 #include <sys/syslog.h>
111 
112 #ifdef LIBWRAP
113 #include <tcpd.h>
114 
115 int allow_severity = LOG_AUTH|LOG_INFO;
116 int deny_severity = LOG_AUTH|LOG_WARNING;
117 #endif
118 
119 char	*ConfFile = _PATH_LOGCONF;
120 char	ctty[] = _PATH_CONSOLE;
121 
122 #define FDMASK(fd)	(1 << (fd))
123 
124 #define	dprintf		if (Debug) printf
125 
126 #define MAXUNAMES	20	/* maximum number of user names */
127 
128 /*
129  * Flags to logmsg().
130  */
131 
132 #define IGN_CONS	0x001	/* don't print on console */
133 #define SYNC_FILE	0x002	/* do fsync on file after printing */
134 #define ADDDATE		0x004	/* add a date to the message */
135 #define MARK		0x008	/* this message is a mark */
136 #define	ISKERNEL	0x010	/* kernel generated message */
137 
138 /*
139  * This structure represents the files that will have log
140  * copies printed.
141  * We require f_file to be valid if f_type is F_FILE, F_CONSOLE, F_TTY,
142  * or if f_type is F_PIPE and f_pid > 0.
143  */
144 
145 struct filed {
146 	struct	filed *f_next;		/* next in linked list */
147 	short	f_type;			/* entry type, see below */
148 	short	f_file;			/* file descriptor */
149 	time_t	f_time;			/* time this was last written */
150 	char	*f_host;		/* host from which to record */
151 	u_char	f_pmask[LOG_NFACILITIES+1];	/* priority mask */
152 	u_char	f_pcmp[LOG_NFACILITIES+1];	/* compare priority */
153 #define	PRI_LT	0x1
154 #define	PRI_EQ	0x2
155 #define	PRI_GT	0x4
156 	char	*f_program;		/* program this applies to */
157 	union {
158 		char	f_uname[MAXUNAMES][UT_NAMESIZE+1];
159 		struct {
160 			char	f_hname[MAXHOSTNAMELEN];
161 			struct	addrinfo *f_addr;
162 		} f_forw;		/* forwarding address */
163 		char	f_fname[MAXPATHLEN];
164 		struct {
165 			char	f_pname[MAXPATHLEN];
166 			pid_t	f_pid;
167 		} f_pipe;
168 	} f_un;
169 	char	f_prevline[MAXSVLINE];		/* last message logged */
170 	char	f_lasttime[16];			/* time of last occurrence */
171 	char	f_prevhost[MAXHOSTNAMELEN];	/* host from which recd. */
172 	int	f_prevpri;			/* pri of f_prevline */
173 	int	f_prevlen;			/* length of f_prevline */
174 	int	f_prevcount;			/* repetition cnt of prevline */
175 	int	f_repeatcount;			/* number of "repeated" msgs */
176 	int	f_lasterror;			/* last error on writev() */
177 	int	f_flags;			/* file-specific flags */
178 #define	FFLAG_SYNC	0x01
179 };
180 
181 /*
182  * Queue of about-to-be-dead processes we should watch out for.
183  */
184 TAILQ_HEAD(, deadq_entry) deadq_head = TAILQ_HEAD_INITIALIZER(deadq_head);
185 
186 typedef struct deadq_entry {
187 	pid_t				dq_pid;
188 	int				dq_timeout;
189 	TAILQ_ENTRY(deadq_entry)	dq_entries;
190 } *dq_t;
191 
192 /*
193  * The timeout to apply to processes waiting on the dead queue.  Unit
194  * of measure is "mark intervals", i.e. 20 minutes by default.
195  * Processes on the dead queue will be terminated after that time.
196  */
197 #define	DQ_TIMO_INIT	2
198 
199 /*
200  * Intervals at which we flush out "message repeated" messages,
201  * in seconds after previous message is logged.  After each flush,
202  * we move to the next interval until we reach the largest.
203  */
204 int	repeatinterval[] = { 30, 120, 600 };	/* # of secs before flush */
205 #define	MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
206 #define	REPEATTIME(f)	((f)->f_time + repeatinterval[(f)->f_repeatcount])
207 #define	BACKOFF(f)	{ if (++(f)->f_repeatcount > MAXREPEAT) \
208 				 (f)->f_repeatcount = MAXREPEAT; \
209 			}
210 
211 /* values for f_type */
212 #define F_UNUSED	0		/* unused entry */
213 #define F_FILE		1		/* regular file */
214 #define F_TTY		2		/* terminal */
215 #define F_CONSOLE	3		/* console terminal */
216 #define F_FORW		4		/* remote machine */
217 #define F_USERS		5		/* list of users */
218 #define F_WALL		6		/* everyone logged on */
219 #define	F_PIPE		7		/* pipe to program */
220 
221 char	*TypeNames[8] = {
222 	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
223 	"FORW",		"USERS",	"WALL",		"PIPE"
224 };
225 
226 struct	filed *Files;
227 struct	filed consfile;
228 
229 int	Debug;			/* debug flag */
230 int	daemonized = 0;		/* we are not daemonized yet */
231 char	LocalHostName[MAXHOSTNAMELEN];	/* our hostname */
232 char	oldLocalHostName[MAXHOSTNAMELEN];/* previous hostname */
233 char	*LocalDomain;		/* our local domain name */
234 size_t	LocalDomainLen;		/* length of LocalDomain */
235 int	*finet = NULL;		/* Internet datagram sockets */
236 int	Initialized;		/* set when we have initialized ourselves */
237 int	ShuttingDown;		/* set when we die() */
238 int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
239 int	MarkSeq = 0;		/* mark sequence number */
240 int	SecureMode = 0;		/* listen only on unix domain socks */
241 int	UseNameService = 1;	/* make domain name queries */
242 int	NumForwards = 0;	/* number of forwarding actions in conf file */
243 char	**LogPaths;		/* array of pathnames to read messages from */
244 int	NoRepeat = 0;		/* disable "repeated"; log always */
245 int	RemoteAddDate = 0;	/* always add date to messages from network */
246 int	SyncKernel = 0;		/* write kernel messages synchronously */
247 int	UniquePriority = 0;	/* only log specified priority */
248 int	LogFacPri = 0;		/* put facility and priority in log messages: */
249 				/* 0=no, 1=numeric, 2=names */
250 
251 void	cfline(char *, struct filed *, char *, char *);
252 char   *cvthname(struct sockaddr_storage *);
253 void	deadq_enter(pid_t, const char *);
254 int	deadq_remove(pid_t);
255 int	decode(const char *, CODE *);
256 void	die(struct kevent *);	/* SIGTERM kevent dispatch routine */
257 void	domark(struct kevent *);/* timer kevent dispatch routine */
258 void	fprintlog(struct filed *, int, char *);
259 int	getmsgbufsize(void);
260 int*	socksetup(int);
261 void	init(struct kevent *);	/* SIGHUP kevent dispatch routine */
262 void	logerror(const char *, ...);
263 void	logmsg(int, char *, char *, int);
264 void	log_deadchild(pid_t, int, const char *);
265 int	matches_spec(const char *, const char *,
266 		     char *(*)(const char *, const char *));
267 void	printline(char *, char *, int);
268 void	printsys(char *);
269 int	p_open(char *, pid_t *);
270 void	trim_localdomain(char *);
271 void	reapchild(struct kevent *); /* SIGCHLD kevent dispatch routine */
272 void	usage(void);
273 void	wallmsg(struct filed *, struct iovec *, size_t);
274 int	main(int, char *[]);
275 void	logpath_add(char ***, int *, int *, char *);
276 void	logpath_fileadd(char ***, int *, int *, char *);
277 
278 static int fkq;
279 
280 static struct kevent *allocevchange(void);
281 static int wait_for_events(struct kevent *, size_t);
282 
283 static void dispatch_read_klog(struct kevent *);
284 static void dispatch_read_finet(struct kevent *);
285 static void dispatch_read_funix(struct kevent *);
286 
287 /*
288  * Global line buffer.  Since we only process one event at a time,
289  * a global one will do.
290  */
291 static char *linebuf;
292 static size_t linebufsize;
293 
294 #define	A_CNT(x)	(sizeof((x)) / sizeof((x)[0]))
295 
296 int
297 main(int argc, char *argv[])
298 {
299 	int ch, *funix, j, fklog;
300 	int funixsize = 0, funixmaxsize = 0;
301 	struct kevent events[16];
302 	struct sockaddr_un sunx;
303 	char **pp;
304 	struct kevent *ev;
305 	uid_t uid = 0;
306 	gid_t gid = 0;
307 	char *user = NULL;
308 	char *group = NULL;
309 	char *root = "/";
310 	char *endp;
311 	struct group   *gr;
312 	struct passwd  *pw;
313 	unsigned long l;
314 
315 	(void)setlocale(LC_ALL, "");
316 
317 	while ((ch = getopt(argc, argv, "dnsSf:m:p:P:ru:g:t:TUv")) != -1)
318 		switch(ch) {
319 		case 'd':		/* debug */
320 			Debug++;
321 			break;
322 		case 'f':		/* configuration file */
323 			ConfFile = optarg;
324 			break;
325 		case 'g':
326 			group = optarg;
327 			if (*group == '\0')
328 				usage();
329 			break;
330 		case 'm':		/* mark interval */
331 			MarkInterval = atoi(optarg) * 60;
332 			break;
333 		case 'n':		/* turn off DNS queries */
334 			UseNameService = 0;
335 			break;
336 		case 'p':		/* path */
337 			logpath_add(&LogPaths, &funixsize,
338 			    &funixmaxsize, optarg);
339 			break;
340 		case 'P':		/* file of paths */
341 			logpath_fileadd(&LogPaths, &funixsize,
342 			    &funixmaxsize, optarg);
343 			break;
344 		case 'r':		/* disable "repeated" compression */
345 			NoRepeat++;
346 			break;
347 		case 's':		/* no network listen mode */
348 			SecureMode++;
349 			break;
350 		case 'S':
351 			SyncKernel = 1;
352 			break;
353 		case 't':
354 			root = optarg;
355 			if (*root == '\0')
356 				usage();
357 			break;
358 		case 'T':
359 			RemoteAddDate = 1;
360 			break;
361 		case 'u':
362 			user = optarg;
363 			if (*user == '\0')
364 				usage();
365 			break;
366 		case 'U':		/* only log specified priority */
367 			UniquePriority = 1;
368 			break;
369 		case 'v':		/* log facility and priority */
370 			if (LogFacPri < 2)
371 				LogFacPri++;
372 			break;
373 		default:
374 			usage();
375 		}
376 	if ((argc -= optind) != 0)
377 		usage();
378 
379 	setlinebuf(stdout);
380 
381 	if (user != NULL) {
382 		if (isdigit((unsigned char)*user)) {
383 			errno = 0;
384 			endp = NULL;
385 			l = strtoul(user, &endp, 0);
386 			if (errno || *endp != '\0')
387 	    			goto getuser;
388 			uid = (uid_t)l;
389 			if (uid != l) {
390 				errno = 0;
391 				logerror("UID out of range");
392 				die(NULL);
393 			}
394 		} else {
395 getuser:
396 			if ((pw = getpwnam(user)) != NULL) {
397 				uid = pw->pw_uid;
398 			} else {
399 				errno = 0;
400 				logerror("Cannot find user `%s'", user);
401 				die(NULL);
402 			}
403 		}
404 	}
405 
406 	if (group != NULL) {
407 		if (isdigit((unsigned char)*group)) {
408 			errno = 0;
409 			endp = NULL;
410 			l = strtoul(group, &endp, 0);
411 			if (errno || *endp != '\0')
412 	    			goto getgroup;
413 			gid = (gid_t)l;
414 			if (gid != l) {
415 				errno = 0;
416 				logerror("GID out of range");
417 				die(NULL);
418 			}
419 		} else {
420 getgroup:
421 			if ((gr = getgrnam(group)) != NULL) {
422 				gid = gr->gr_gid;
423 			} else {
424 				errno = 0;
425 				logerror("Cannot find group `%s'", group);
426 				die(NULL);
427 			}
428 		}
429 	}
430 
431 	if (access(root, F_OK | R_OK)) {
432 		logerror("Cannot access `%s'", root);
433 		die(NULL);
434 	}
435 
436 	consfile.f_type = F_CONSOLE;
437 	(void)strlcpy(consfile.f_un.f_fname, ctty,
438 	    sizeof(consfile.f_un.f_fname));
439 	linebufsize = getmsgbufsize();
440 	if (linebufsize < MAXLINE)
441 		linebufsize = MAXLINE;
442 	linebufsize++;
443 	linebuf = malloc(linebufsize);
444 	if (linebuf == NULL) {
445 		logerror("Couldn't allocate line buffer");
446 		die(NULL);
447 	}
448 
449 #ifndef SUN_LEN
450 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
451 #endif
452 	if (funixsize == 0)
453 		logpath_add(&LogPaths, &funixsize,
454 		    &funixmaxsize, _PATH_LOG);
455 	funix = (int *)malloc(sizeof(int) * funixsize);
456 	if (funix == NULL) {
457 		logerror("Couldn't allocate funix descriptors");
458 		die(NULL);
459 	}
460 	for (j = 0, pp = LogPaths; *pp; pp++, j++) {
461 		dprintf("Making unix dgram socket `%s'\n", *pp);
462 		unlink(*pp);
463 		memset(&sunx, 0, sizeof(sunx));
464 		sunx.sun_family = AF_LOCAL;
465 		(void)strncpy(sunx.sun_path, *pp, sizeof(sunx.sun_path));
466 		funix[j] = socket(AF_LOCAL, SOCK_DGRAM, 0);
467 		if (funix[j] < 0 || bind(funix[j],
468 		    (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 ||
469 		    chmod(*pp, 0666) < 0) {
470 			logerror("Cannot create `%s'", *pp);
471 			die(NULL);
472 		}
473 		dprintf("Listening on unix dgram socket `%s'\n", *pp);
474 	}
475 
476 	if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0) {
477 		dprintf("Can't open `%s' (%d)\n", _PATH_KLOG, errno);
478 	} else {
479 		dprintf("Listening on kernel log `%s'\n", _PATH_KLOG);
480 	}
481 
482 	/*
483 	 * All files are open, we can drop privileges and chroot
484 	 */
485 	dprintf("Attempt to chroot to `%s'\n", root);
486 	if (chroot(root)) {
487 		logerror("Failed to chroot to `%s'", root);
488 		die(NULL);
489 	}
490 	dprintf("Attempt to set GID/EGID to `%d'\n", gid);
491 	if (setgid(gid) || setegid(gid)) {
492 		logerror("Failed to set gid to `%d'", gid);
493 		die(NULL);
494 	}
495 	dprintf("Attempt to set UID/EUID to `%d'\n", uid);
496 	if (setuid(uid) || seteuid(uid)) {
497 		logerror("Failed to set uid to `%d'", uid);
498 		die(NULL);
499 	}
500 
501 	/*
502 	 * We cannot detach from the terminal before we are sure we won't
503 	 * have a fatal error, because error message would not go to the
504 	 * terminal and would not be logged because syslogd dies.
505 	 * All die() calls are behind us, we can call daemon()
506 	 */
507 	if (!Debug) {
508 		(void)daemon(0, 0);
509 		daemonized = 1;
510 
511 		/* tuck my process id away, if i'm not in debug mode */
512 		pidfile(NULL);
513 	}
514 
515 	/*
516 	 * Create the global kernel event descriptor.
517 	 *
518 	 * NOTE: We MUST do this after daemon(), bacause the kqueue()
519 	 * API dictates that kqueue descriptors are not inherited
520 	 * across forks (lame!).
521 	 */
522 	if ((fkq = kqueue()) < 0) {
523 		logerror("Cannot create event queue");
524 		die(NULL);	/* XXX This error is lost! */
525 	}
526 
527 	/*
528 	 * We must read the configuration file for the first time
529 	 * after the kqueue descriptor is created, because we install
530 	 * events during this process.
531 	 */
532 	init(NULL);
533 
534 	/*
535 	 * Always exit on SIGTERM.  Also exit on SIGINT and SIGQUIT
536 	 * if we're debugging.
537 	 */
538 	(void)signal(SIGTERM, SIG_IGN);
539 	(void)signal(SIGINT, SIG_IGN);
540 	(void)signal(SIGQUIT, SIG_IGN);
541 	ev = allocevchange();
542 	EV_SET(ev, SIGTERM, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0,
543 	    (intptr_t) die);
544 	if (Debug) {
545 		ev = allocevchange();
546 		EV_SET(ev, SIGINT, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0,
547 		    (intptr_t) die);
548 
549 		ev = allocevchange();
550 		EV_SET(ev, SIGQUIT, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0,
551 		    (intptr_t) die);
552 	}
553 
554 	ev = allocevchange();
555 	EV_SET(ev, SIGCHLD, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0,
556 	    (intptr_t) reapchild);
557 
558 	ev = allocevchange();
559 	EV_SET(ev, 0, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0,
560 	    TIMERINTVL * 1000 /* seconds -> ms */, (intptr_t) domark);
561 
562 	(void)signal(SIGPIPE, SIG_IGN);	/* We'll catch EPIPE instead. */
563 
564 	/* Re-read configuration on SIGHUP. */
565 	(void) signal(SIGHUP, SIG_IGN);
566 	ev = allocevchange();
567 	EV_SET(ev, SIGHUP, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0,
568 	    (intptr_t) init);
569 
570 	if (fklog >= 0) {
571 		ev = allocevchange();
572 		EV_SET(ev, fklog, EVFILT_READ, EV_ADD | EV_ENABLE,
573 		    0, 0, (intptr_t) dispatch_read_klog);
574 	}
575 	for (j = 0, pp = LogPaths; *pp; pp++, j++) {
576 		ev = allocevchange();
577 		EV_SET(ev, funix[j], EVFILT_READ, EV_ADD | EV_ENABLE,
578 		    0, 0, (intptr_t) dispatch_read_funix);
579 	}
580 
581 	dprintf("Off & running....\n");
582 
583 	for (;;) {
584 		void (*handler)(struct kevent *);
585 		int i, rv;
586 
587 		rv = wait_for_events(events, A_CNT(events));
588 		if (rv == 0)
589 			continue;
590 		if (rv < 0) {
591 			if (errno != EINTR)
592 				logerror("kevent() failed");
593 			continue;
594 		}
595 		dprintf("Got an event (%d)\n", rv);
596 		for (i = 0; i < rv; i++) {
597 			handler = (void *) events[i].udata;
598 			(*handler)(&events[i]);
599 		}
600 	}
601 }
602 
603 void
604 usage(void)
605 {
606 
607 	(void)fprintf(stderr,
608 	    "usage: %s [-dnrSsTUv] [-f config_file] [-g group] [-m mark_interval]\n"
609 	    "\t[-P file_list] [-p log_socket [-p log_socket2 ...]]\n"
610 	    "\t[-t chroot_dir] [-u user]\n", getprogname());
611 	exit(1);
612 }
613 
614 /*
615  * Dispatch routine for reading /dev/klog
616  */
617 static void
618 dispatch_read_klog(struct kevent *ev)
619 {
620 	ssize_t rv;
621 	int fd = ev->ident;
622 
623 	dprintf("Kernel log active\n");
624 
625 	rv = read(fd, linebuf, linebufsize - 1);
626 	if (rv > 0) {
627 		linebuf[rv] = '\0';
628 		printsys(linebuf);
629 	} else if (rv < 0 && errno != EINTR) {
630 		/*
631 		 * /dev/klog has croaked.  Disable the event
632 		 * so it won't bother us again.
633 		 */
634 		struct kevent *cev = allocevchange();
635 		logerror("klog failed");
636 		EV_SET(cev, fd, EVFILT_READ, EV_DISABLE,
637 		    0, 0, (intptr_t) dispatch_read_klog);
638 	}
639 }
640 
641 /*
642  * Dispatch routine for reading Unix domain sockets.
643  */
644 static void
645 dispatch_read_funix(struct kevent *ev)
646 {
647 	struct sockaddr_un myname, fromunix;
648 	ssize_t rv;
649 	socklen_t sunlen;
650 	int fd = ev->ident;
651 
652 	sunlen = sizeof(myname);
653 	if (getsockname(fd, (struct sockaddr *)&myname, &sunlen) != 0) {
654 		/*
655 		 * This should never happen, so ensure that it doesn't
656 		 * happen again.
657 		 */
658 		struct kevent *cev = allocevchange();
659 		logerror("getsockname() unix failed");
660 		EV_SET(cev, fd, EVFILT_READ, EV_DISABLE,
661 		    0, 0, (intptr_t) dispatch_read_funix);
662 		return;
663 	}
664 
665 	dprintf("Unix socket (%s) active\n", myname.sun_path);
666 
667 	sunlen = sizeof(fromunix);
668 	rv = recvfrom(fd, linebuf, MAXLINE, 0,
669 	    (struct sockaddr *)&fromunix, &sunlen);
670 	if (rv > 0) {
671 		linebuf[rv] = '\0';
672 		printline(LocalHostName, linebuf, 0);
673 	} else if (rv < 0 && errno != EINTR) {
674 		logerror("recvfrom() unix `%s'", myname.sun_path);
675 	}
676 }
677 
678 /*
679  * Dispatch routine for reading Internet sockets.
680  */
681 static void
682 dispatch_read_finet(struct kevent *ev)
683 {
684 #ifdef LIBWRAP
685 	struct request_info req;
686 #endif
687 	struct sockaddr_storage frominet;
688 	ssize_t rv;
689 	socklen_t len;
690 	int fd = ev->ident;
691 	int reject = 0;
692 
693 	dprintf("inet socket active\n");
694 
695 #ifdef LIBWRAP
696 	request_init(&req, RQ_DAEMON, "syslogd", RQ_FILE, fd, NULL);
697 	fromhost(&req);
698 	reject = !hosts_access(&req);
699 	if (reject)
700 		dprintf("access denied\n");
701 #endif
702 
703 	len = sizeof(frominet);
704 	rv = recvfrom(fd, linebuf, MAXLINE, 0,
705 	    (struct sockaddr *)&frominet, &len);
706 	if (rv == 0 || (rv < 0 && errno == EINTR))
707 		return;
708 	else if (rv < 0) {
709 		logerror("recvfrom inet");
710 		return;
711 	}
712 
713 	linebuf[rv] = '\0';
714 	if (!reject)
715 		printline(cvthname(&frominet), linebuf,
716 			  RemoteAddDate ? ADDDATE : 0);
717 }
718 
719 /*
720  * given a pointer to an array of char *'s, a pointer to its current
721  * size and current allocated max size, and a new char * to add, add
722  * it, update everything as necessary, possibly allocating a new array
723  */
724 void
725 logpath_add(char ***lp, int *szp, int *maxszp, char *new)
726 {
727 	char **nlp;
728 	int newmaxsz;
729 
730 	dprintf("Adding `%s' to the %p logpath list\n", new, *lp);
731 	if (*szp == *maxszp) {
732 		if (*maxszp == 0) {
733 			newmaxsz = 4;	/* start of with enough for now */
734 			*lp = NULL;
735 		} else
736 			newmaxsz = *maxszp * 2;
737 		nlp = realloc(*lp, sizeof(char *) * (newmaxsz + 1));
738 		if (nlp == NULL) {
739 			logerror("Couldn't allocate line buffer");
740 			die(NULL);
741 		}
742 		*lp = nlp;
743 		*maxszp = newmaxsz;
744 	}
745 	if (((*lp)[(*szp)++] = strdup(new)) == NULL) {
746 		logerror("Couldn't allocate logpath");
747 		die(NULL);
748 	}
749 	(*lp)[(*szp)] = NULL;		/* always keep it NULL terminated */
750 }
751 
752 /* do a file of log sockets */
753 void
754 logpath_fileadd(char ***lp, int *szp, int *maxszp, char *file)
755 {
756 	FILE *fp;
757 	char *line;
758 	size_t len;
759 
760 	fp = fopen(file, "r");
761 	if (fp == NULL) {
762 		logerror("Could not open socket file list `%s'", file);
763 		die(NULL);
764 	}
765 
766 	while ((line = fgetln(fp, &len))) {
767 		line[len - 1] = 0;
768 		logpath_add(lp, szp, maxszp, line);
769 	}
770 	fclose(fp);
771 }
772 
773 /*
774  * Take a raw input line, decode the message, and print the message
775  * on the appropriate log files.
776  */
777 void
778 printline(char *hname, char *msg, int flags)
779 {
780 	int c, pri;
781 	char *p, *q, line[MAXLINE + 1];
782 	long n;
783 
784 	/* test for special codes */
785 	pri = DEFUPRI;
786 	p = msg;
787 	if (*p == '<') {
788 		errno = 0;
789 		n = strtol(p + 1, &q, 10);
790 		if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
791 			p = q + 1;
792 			pri = (int)n;
793 		}
794 	}
795 	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
796 		pri = DEFUPRI;
797 
798 	/*
799 	 * Don't allow users to log kernel messages.
800 	 * NOTE: Since LOG_KERN == 0, this will also match
801 	 *	 messages with no facility specified.
802 	 */
803 	if ((pri & LOG_FACMASK) == LOG_KERN)
804 		pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
805 
806 	q = line;
807 
808 	while ((c = *p++) != '\0' &&
809 	    q < &line[sizeof(line) - 2]) {
810 		c &= 0177;
811 		if (iscntrl(c))
812 			if (c == '\n')
813 				*q++ = ' ';
814 			else if (c == '\t')
815 				*q++ = '\t';
816 			else {
817 				*q++ = '^';
818 				*q++ = c ^ 0100;
819 			}
820 		else
821 			*q++ = c;
822 	}
823 	*q = '\0';
824 
825 	logmsg(pri, line, hname, flags);
826 }
827 
828 /*
829  * Take a raw input line from /dev/klog, split and format similar to syslog().
830  */
831 void
832 printsys(char *msg)
833 {
834 	int n, pri, flags, is_printf;
835 	char *p, *q;
836 
837 	for (p = msg; *p != '\0'; ) {
838 		flags = ISKERNEL | ADDDATE;
839 		if (SyncKernel)
840 			flags |= SYNC_FILE;
841 		pri = DEFSPRI;
842 		is_printf = 1;
843 		if (*p == '<') {
844 			errno = 0;
845 			n = (int)strtol(p + 1, &q, 10);
846 			if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
847 				p = q + 1;
848 				pri = n;
849 				is_printf = 0;
850 			}
851 		}
852 		if (is_printf) {
853 			/* kernel printf's come out on console */
854 			flags |= IGN_CONS;
855 		}
856 		if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
857 			pri = DEFSPRI;
858 		for (q = p; *q != '\0' && *q != '\n'; q++)
859 			/* look for end of line */;
860 		if (*q != '\0')
861 			*q++ = '\0';
862 		logmsg(pri, p, LocalHostName, flags);
863 		p = q;
864 	}
865 }
866 
867 time_t	now;
868 
869 /*
870  * Check to see if `name' matches the provided specification, using the
871  * specified strstr function.
872  */
873 int
874 matches_spec(const char *name, const char *spec,
875     char *(*check)(const char *, const char *))
876 {
877 	const char *s;
878 	char prev, next;
879 
880 	if ((s = (*check)(spec, name)) != NULL) {
881 		prev = s == spec ? ',' : *(s - 1);
882 		next = *(s + strlen(name));
883 
884 		if (prev == ',' && (next == '\0' || next == ','))
885 			return (1);
886 	}
887 
888 	return (0);
889 }
890 
891 /*
892  * Log a message to the appropriate log files, users, etc. based on
893  * the priority.
894  */
895 void
896 logmsg(int pri, char *msg, char *from, int flags)
897 {
898 	struct filed *f;
899 	int fac, msglen, omask, prilev, i;
900 	char *timestamp;
901 	char prog[NAME_MAX + 1];
902 	char buf[MAXLINE + 1];
903 
904 	dprintf("logmsg: pri 0%o, flags 0x%x, from %s, msg %s\n",
905 	    pri, flags, from, msg);
906 
907 	omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
908 
909 	/*
910 	 * Check to see if msg looks non-standard.
911 	 */
912 	msglen = strlen(msg);
913 	if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
914 	    msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
915 		flags |= ADDDATE;
916 
917 	(void)time(&now);
918 	if (flags & ADDDATE)
919 		timestamp = ctime(&now) + 4;
920 	else {
921 		timestamp = msg;
922 		msg += 16;
923 		msglen -= 16;
924 	}
925 
926 	/* skip leading whitespace */
927 	while (isspace((unsigned char)*msg)) {
928 		msg++;
929 		msglen--;
930 	}
931 
932 	/* extract facility and priority level */
933 	if (flags & MARK)
934 		fac = LOG_NFACILITIES;
935 	else
936 		fac = LOG_FAC(pri);
937 	prilev = LOG_PRI(pri);
938 
939 	/* extract program name */
940 	for (i = 0; i < NAME_MAX; i++) {
941 		if (!isprint((unsigned char)msg[i]) ||
942 		    msg[i] == ':' || msg[i] == '[')
943 			break;
944 		prog[i] = msg[i];
945 	}
946 	prog[i] = '\0';
947 
948 	/* add kernel prefix for kernel messages */
949 	if (flags & ISKERNEL) {
950 		snprintf(buf, sizeof(buf), "%s: %s",
951 		    _PATH_UNIX, msg);
952 		msg = buf;
953 		msglen = strlen(buf);
954 	}
955 
956 	/* log the message to the particular outputs */
957 	if (!Initialized) {
958 		f = &consfile;
959 		f->f_file = open(ctty, O_WRONLY, 0);
960 
961 		if (f->f_file >= 0) {
962 			(void)strncpy(f->f_lasttime, timestamp, 15);
963 			fprintlog(f, flags, msg);
964 			(void)close(f->f_file);
965 		}
966 		(void)sigsetmask(omask);
967 		return;
968 	}
969 	for (f = Files; f; f = f->f_next) {
970 		/* skip messages that are incorrect priority */
971 		if (!(((f->f_pcmp[fac] & PRI_EQ) && (f->f_pmask[fac] == prilev))
972 		     ||((f->f_pcmp[fac] & PRI_LT) && (f->f_pmask[fac] < prilev))
973 		     ||((f->f_pcmp[fac] & PRI_GT) && (f->f_pmask[fac] > prilev))
974 		     )
975 		    || f->f_pmask[fac] == INTERNAL_NOPRI)
976 			continue;
977 
978 		/* skip messages with the incorrect host name */
979 		if (f->f_host != NULL) {
980 			switch (f->f_host[0]) {
981 			case '+':
982 				if (! matches_spec(from, f->f_host + 1,
983 						   strcasestr))
984 					continue;
985 				break;
986 			case '-':
987 				if (matches_spec(from, f->f_host + 1,
988 						 strcasestr))
989 					continue;
990 				break;
991 			}
992 		}
993 
994 		/* skip messages with the incorrect program name */
995 		if (f->f_program != NULL) {
996 			switch (f->f_program[0]) {
997 			case '+':
998 				if (! matches_spec(prog, f->f_program + 1,
999 						   strstr))
1000 					continue;
1001 				break;
1002 			case '-':
1003 				if (matches_spec(prog, f->f_program + 1,
1004 						 strstr))
1005 					continue;
1006 				break;
1007 			default:
1008 				if (! matches_spec(prog, f->f_program,
1009 						   strstr))
1010 					continue;
1011 				break;
1012 			}
1013 		}
1014 
1015 		if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
1016 			continue;
1017 
1018 		/* don't output marks to recently written files */
1019 		if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
1020 			continue;
1021 
1022 		/*
1023 		 * suppress duplicate lines to this file unless NoRepeat
1024 		 */
1025 		if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
1026 		    !NoRepeat &&
1027 		    !strcmp(msg, f->f_prevline) &&
1028 		    !strcasecmp(from, f->f_prevhost)) {
1029 			(void)strncpy(f->f_lasttime, timestamp, 15);
1030 			f->f_prevcount++;
1031 			dprintf("Msg repeated %d times, %ld sec of %d\n",
1032 			    f->f_prevcount, (long)(now - f->f_time),
1033 			    repeatinterval[f->f_repeatcount]);
1034 			/*
1035 			 * If domark would have logged this by now,
1036 			 * flush it now (so we don't hold isolated messages),
1037 			 * but back off so we'll flush less often
1038 			 * in the future.
1039 			 */
1040 			if (now > REPEATTIME(f)) {
1041 				fprintlog(f, flags, (char *)NULL);
1042 				BACKOFF(f);
1043 			}
1044 		} else {
1045 			/* new line, save it */
1046 			if (f->f_prevcount)
1047 				fprintlog(f, 0, (char *)NULL);
1048 			f->f_repeatcount = 0;
1049 			f->f_prevpri = pri;
1050 			(void)strncpy(f->f_lasttime, timestamp, 15);
1051 			(void)strncpy(f->f_prevhost, from,
1052 					sizeof(f->f_prevhost));
1053 			if (msglen < MAXSVLINE) {
1054 				f->f_prevlen = msglen;
1055 				(void)strlcpy(f->f_prevline, msg,
1056 				    sizeof(f->f_prevline));
1057 				fprintlog(f, flags, (char *)NULL);
1058 			} else {
1059 				f->f_prevline[0] = 0;
1060 				f->f_prevlen = 0;
1061 				fprintlog(f, flags, msg);
1062 			}
1063 		}
1064 	}
1065 	(void)sigsetmask(omask);
1066 }
1067 
1068 void
1069 fprintlog(struct filed *f, int flags, char *msg)
1070 {
1071 	struct iovec iov[10];
1072 	struct iovec *v;
1073 	struct addrinfo *r;
1074 	int j, l, lsent;
1075 	char line[MAXLINE + 1], repbuf[80], greetings[200];
1076 #define ADDEV() assert(++v - iov < A_CNT(iov))
1077 
1078 	v = iov;
1079 	if (f->f_type == F_WALL) {
1080 		v->iov_base = greetings;
1081 		v->iov_len = snprintf(greetings, sizeof greetings,
1082 		    "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
1083 		    f->f_prevhost, ctime(&now));
1084 		ADDEV();
1085 		v->iov_base = "";
1086 		v->iov_len = 0;
1087 		ADDEV();
1088 	} else {
1089 		v->iov_base = f->f_lasttime;
1090 		v->iov_len = 15;
1091 		ADDEV();
1092 		v->iov_base = " ";
1093 		v->iov_len = 1;
1094 		ADDEV();
1095 	}
1096 
1097 	if (LogFacPri) {
1098 		static char fp_buf[30];
1099 		const char *f_s = NULL, *p_s = NULL;
1100 		int fac = f->f_prevpri & LOG_FACMASK;
1101 		int pri = LOG_PRI(f->f_prevpri);
1102 		char f_n[5], p_n[5];
1103 
1104 		if (LogFacPri > 1) {
1105 			CODE *c;
1106 
1107 			for (c = facilitynames; c->c_name != NULL; c++) {
1108 				if (c->c_val == fac) {
1109 					f_s = c->c_name;
1110 					break;
1111 				}
1112 			}
1113 			for (c = prioritynames; c->c_name != NULL; c++) {
1114 				if (c->c_val == pri) {
1115 					p_s = c->c_name;
1116 					break;
1117 				}
1118 			}
1119 		}
1120 		if (f_s == NULL) {
1121 			snprintf(f_n, sizeof(f_n), "%d", LOG_FAC(fac));
1122 			f_s = f_n;
1123 		}
1124 		if (p_s == NULL) {
1125 			snprintf(p_n, sizeof(p_n), "%d", pri);
1126 			p_s = p_n;
1127 		}
1128 		snprintf(fp_buf, sizeof(fp_buf), "<%s.%s>", f_s, p_s);
1129 		v->iov_base = fp_buf;
1130 		v->iov_len = strlen(fp_buf);
1131 	} else {
1132 		v->iov_base = "";
1133 		v->iov_len = 0;
1134 	}
1135 	ADDEV();
1136 
1137 	v->iov_base = f->f_prevhost;
1138 	v->iov_len = strlen(v->iov_base);
1139 	ADDEV();
1140 	v->iov_base = " ";
1141 	v->iov_len = 1;
1142 	ADDEV();
1143 
1144 	if (msg) {
1145 		v->iov_base = msg;
1146 		v->iov_len = strlen(msg);
1147 	} else if (f->f_prevcount > 1) {
1148 		v->iov_base = repbuf;
1149 		v->iov_len = snprintf(repbuf, sizeof repbuf,
1150 		    "last message repeated %d times", f->f_prevcount);
1151 	} else {
1152 		v->iov_base = f->f_prevline;
1153 		v->iov_len = f->f_prevlen;
1154 	}
1155 	ADDEV();
1156 
1157 	dprintf("Logging to %s", TypeNames[f->f_type]);
1158 	f->f_time = now;
1159 
1160 	switch (f->f_type) {
1161 	case F_UNUSED:
1162 		dprintf("\n");
1163 		break;
1164 
1165 	case F_FORW:
1166 		dprintf(" %s\n", f->f_un.f_forw.f_hname);
1167 			/*
1168 			 * check for local vs remote messages
1169 			 * (from FreeBSD PR#bin/7055)
1170 			 */
1171 		if (strcasecmp(f->f_prevhost, LocalHostName)) {
1172 			l = snprintf(line, sizeof(line) - 1,
1173 				     "<%d>%.15s [%s]: %s",
1174 				     f->f_prevpri, (char *) iov[0].iov_base,
1175 				     f->f_prevhost, (char *) iov[5].iov_base);
1176 		} else {
1177 			l = snprintf(line, sizeof(line) - 1, "<%d>%.15s %s",
1178 				     f->f_prevpri, (char *) iov[0].iov_base,
1179 				     (char *) iov[5].iov_base);
1180 		}
1181 		if (l > MAXLINE)
1182 			l = MAXLINE;
1183 		if (finet) {
1184 			lsent = -1;
1185 			for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
1186 				for (j = 0; j < *finet; j++) {
1187 #if 0
1188 					/*
1189 					 * should we check AF first, or just
1190 					 * trial and error? FWD
1191 					 */
1192 					if (r->ai_family ==
1193 					    address_family_of(finet[j+1]))
1194 #endif
1195 					lsent = sendto(finet[j+1], line, l, 0,
1196 					    r->ai_addr, r->ai_addrlen);
1197 					if (lsent == l)
1198 						break;
1199 				}
1200 			}
1201 			if (lsent != l) {
1202 				f->f_type = F_UNUSED;
1203 				logerror("sendto() failed");
1204 			}
1205 		}
1206 		break;
1207 
1208 	case F_PIPE:
1209 		dprintf(" %s\n", f->f_un.f_pipe.f_pname);
1210 		v->iov_base = "\n";
1211 		v->iov_len = 1;
1212 		ADDEV();
1213 		if (f->f_un.f_pipe.f_pid == 0) {
1214 			if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
1215 						&f->f_un.f_pipe.f_pid)) < 0) {
1216 				f->f_type = F_UNUSED;
1217 				logerror(f->f_un.f_pipe.f_pname);
1218 				break;
1219 			}
1220 		}
1221 		if (writev(f->f_file, iov, v - iov) < 0) {
1222 			int e = errno;
1223 			if (f->f_un.f_pipe.f_pid > 0) {
1224 				(void) close(f->f_file);
1225 				deadq_enter(f->f_un.f_pipe.f_pid,
1226 					    f->f_un.f_pipe.f_pname);
1227 			}
1228 			f->f_un.f_pipe.f_pid = 0;
1229 			/*
1230 			 * If the error was EPIPE, then what is likely
1231 			 * has happened is we have a command that is
1232 			 * designed to take a single message line and
1233 			 * then exit, but we tried to feed it another
1234 			 * one before we reaped the child and thus
1235 			 * reset our state.
1236 			 *
1237 			 * Well, now we've reset our state, so try opening
1238 			 * the pipe and sending the message again if EPIPE
1239 			 * was the error.
1240 			 */
1241 			if (e == EPIPE) {
1242 				if ((f->f_file = p_open(f->f_un.f_pipe.f_pname,
1243 				     &f->f_un.f_pipe.f_pid)) < 0) {
1244 					f->f_type = F_UNUSED;
1245 					logerror(f->f_un.f_pipe.f_pname);
1246 					break;
1247 				}
1248 				if (writev(f->f_file, iov, v - iov) < 0) {
1249 					e = errno;
1250 					if (f->f_un.f_pipe.f_pid > 0) {
1251 					    (void) close(f->f_file);
1252 					    deadq_enter(f->f_un.f_pipe.f_pid,
1253 							f->f_un.f_pipe.f_pname);
1254 					}
1255 					f->f_un.f_pipe.f_pid = 0;
1256 				} else
1257 					e = 0;
1258 			}
1259 			if (e != 0) {
1260 				errno = e;
1261 				logerror(f->f_un.f_pipe.f_pname);
1262 			}
1263 		}
1264 		break;
1265 
1266 	case F_CONSOLE:
1267 		if (flags & IGN_CONS) {
1268 			dprintf(" (ignored)\n");
1269 			break;
1270 		}
1271 		/* FALLTHROUGH */
1272 
1273 	case F_TTY:
1274 	case F_FILE:
1275 		dprintf(" %s\n", f->f_un.f_fname);
1276 		if (f->f_type != F_FILE) {
1277 			v->iov_base = "\r\n";
1278 			v->iov_len = 2;
1279 		} else {
1280 			v->iov_base = "\n";
1281 			v->iov_len = 1;
1282 		}
1283 		ADDEV();
1284 	again:
1285 		if (writev(f->f_file, iov, v - iov) < 0) {
1286 			int e = errno;
1287 			if (f->f_type == F_FILE && e == ENOSPC) {
1288 				int lasterror = f->f_lasterror;
1289 				f->f_lasterror = e;
1290 				if (lasterror != e)
1291 					logerror(f->f_un.f_fname);
1292 				break;
1293 			}
1294 			(void)close(f->f_file);
1295 			/*
1296 			 * Check for errors on TTY's due to loss of tty
1297 			 */
1298 			if ((e == EIO || e == EBADF) && f->f_type != F_FILE) {
1299 				f->f_file = open(f->f_un.f_fname,
1300 				    O_WRONLY|O_APPEND, 0);
1301 				if (f->f_file < 0) {
1302 					f->f_type = F_UNUSED;
1303 					logerror(f->f_un.f_fname);
1304 				} else
1305 					goto again;
1306 			} else {
1307 				f->f_type = F_UNUSED;
1308 				errno = e;
1309 				f->f_lasterror = e;
1310 				logerror(f->f_un.f_fname);
1311 			}
1312 		} else {
1313 			f->f_lasterror = 0;
1314 			if ((flags & SYNC_FILE) && (f->f_flags & FFLAG_SYNC))
1315 				(void)fsync(f->f_file);
1316 		}
1317 		break;
1318 
1319 	case F_USERS:
1320 	case F_WALL:
1321 		dprintf("\n");
1322 		v->iov_base = "\r\n";
1323 		v->iov_len = 2;
1324 		ADDEV();
1325 		wallmsg(f, iov, v - iov);
1326 		break;
1327 	}
1328 	f->f_prevcount = 0;
1329 }
1330 
1331 /*
1332  *  WALLMSG -- Write a message to the world at large
1333  *
1334  *	Write the specified message to either the entire
1335  *	world, or a list of approved users.
1336  */
1337 void
1338 wallmsg(struct filed *f, struct iovec *iov, size_t iovcnt)
1339 {
1340 	static int reenter;			/* avoid calling ourselves */
1341 	int i;
1342 	char *p;
1343 	static struct utmpentry *ohead = NULL;
1344 	struct utmpentry *ep;
1345 
1346 	if (reenter++)
1347 		return;
1348 
1349 	(void)getutentries(NULL, &ep);
1350 	if (ep != ohead) {
1351 		freeutentries(ohead);
1352 		ohead = ep;
1353 	}
1354 	/* NOSTRICT */
1355 	for (; ep; ep = ep->next) {
1356 		if (f->f_type == F_WALL) {
1357 			if ((p = ttymsg(iov, iovcnt, ep->line, TTYMSGTIME))
1358 			    != NULL) {
1359 				errno = 0;	/* already in msg */
1360 				logerror(p);
1361 			}
1362 			continue;
1363 		}
1364 		/* should we send the message to this user? */
1365 		for (i = 0; i < MAXUNAMES; i++) {
1366 			if (!f->f_un.f_uname[i][0])
1367 				break;
1368 			if (strcmp(f->f_un.f_uname[i], ep->name) == 0) {
1369 				if ((p = ttymsg(iov, iovcnt, ep->line,
1370 				    TTYMSGTIME)) != NULL) {
1371 					errno = 0;	/* already in msg */
1372 					logerror(p);
1373 				}
1374 				break;
1375 			}
1376 		}
1377 	}
1378 	reenter = 0;
1379 }
1380 
1381 void
1382 reapchild(struct kevent *ev)
1383 {
1384 	int status;
1385 	pid_t pid;
1386 	struct filed *f;
1387 
1388 	while ((pid = wait3(&status, WNOHANG, NULL)) > 0) {
1389 		if (!Initialized || ShuttingDown) {
1390 			/*
1391 			 * Be silent while we are initializing or
1392 			 * shutting down.
1393 			 */
1394 			continue;
1395 		}
1396 
1397 		if (deadq_remove(pid))
1398 			continue;
1399 
1400 		/* Now, look in the list of active processes. */
1401 		for (f = Files; f != NULL; f = f->f_next) {
1402 			if (f->f_type == F_PIPE &&
1403 			    f->f_un.f_pipe.f_pid == pid) {
1404 				(void) close(f->f_file);
1405 				f->f_un.f_pipe.f_pid = 0;
1406 				log_deadchild(pid, status,
1407 					      f->f_un.f_pipe.f_pname);
1408 				break;
1409 			}
1410 		}
1411 	}
1412 }
1413 
1414 /*
1415  * Return a printable representation of a host address.
1416  */
1417 char *
1418 cvthname(struct sockaddr_storage *f)
1419 {
1420 	int error;
1421 	const int niflag = NI_DGRAM;
1422 	static char host[NI_MAXHOST], ip[NI_MAXHOST];
1423 
1424 	error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len,
1425 			ip, sizeof ip, NULL, 0, NI_NUMERICHOST|niflag);
1426 
1427 	dprintf("cvthname(%s)\n", ip);
1428 
1429 	if (error) {
1430 		dprintf("Malformed from address %s\n", gai_strerror(error));
1431 		return ("???");
1432 	}
1433 
1434 	if (!UseNameService)
1435 		return (ip);
1436 
1437 	error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len,
1438 			host, sizeof host, NULL, 0, niflag);
1439 	if (error) {
1440 		dprintf("Host name for your address (%s) unknown\n", ip);
1441 		return (ip);
1442 	}
1443 
1444 	trim_localdomain(host);
1445 
1446 	return (host);
1447 }
1448 
1449 void
1450 trim_localdomain(char *host)
1451 {
1452 	size_t hl;
1453 
1454 	hl = strlen(host);
1455 	if (hl > 0 && host[hl - 1] == '.')
1456 		host[--hl] = '\0';
1457 
1458 	if (hl > LocalDomainLen && host[hl - LocalDomainLen - 1] == '.' &&
1459 	    strcasecmp(&host[hl - LocalDomainLen], LocalDomain) == 0)
1460 		host[hl - LocalDomainLen - 1] = '\0';
1461 }
1462 
1463 void
1464 domark(struct kevent *ev)
1465 {
1466 	struct filed *f;
1467 	dq_t q, nextq;
1468 
1469 	/*
1470 	 * XXX Should we bother to adjust for the # of times the timer
1471 	 * has expired (i.e. in case we miss one?).  This information is
1472 	 * returned to us in ev->data.
1473 	 */
1474 
1475 	now = time((time_t *)NULL);
1476 	MarkSeq += TIMERINTVL;
1477 	if (MarkSeq >= MarkInterval) {
1478 		logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
1479 		MarkSeq = 0;
1480 	}
1481 
1482 	for (f = Files; f; f = f->f_next) {
1483 		if (f->f_prevcount && now >= REPEATTIME(f)) {
1484 			dprintf("Flush %s: repeated %d times, %d sec.\n",
1485 			    TypeNames[f->f_type], f->f_prevcount,
1486 			    repeatinterval[f->f_repeatcount]);
1487 			fprintlog(f, 0, (char *)NULL);
1488 			BACKOFF(f);
1489 		}
1490 	}
1491 
1492 	/* Walk the dead queue, and see if we should signal somebody. */
1493 	for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = nextq) {
1494 		nextq = TAILQ_NEXT(q, dq_entries);
1495 		switch (q->dq_timeout) {
1496 		case 0:
1497 			/* Already signalled once, try harder now. */
1498 			if (kill(q->dq_pid, SIGKILL) != 0)
1499 				(void) deadq_remove(q->dq_pid);
1500 			break;
1501 
1502 		case 1:
1503 			/*
1504 			 * Timed out on the dead queue, send terminate
1505 			 * signal.  Note that we leave the removal from
1506 			 * the dead queue to reapchild(), which will
1507 			 * also log the event (unless the process
1508 			 * didn't even really exist, in case we simply
1509 			 * drop it from the dead queue).
1510 			 */
1511 			if (kill(q->dq_pid, SIGTERM) != 0) {
1512 				(void) deadq_remove(q->dq_pid);
1513 				break;
1514 			}
1515 			/* FALLTHROUGH */
1516 
1517 		default:
1518 			q->dq_timeout--;
1519 		}
1520 	}
1521 }
1522 
1523 /*
1524  * Print syslogd errors some place.
1525  */
1526 void
1527 logerror(const char *fmt, ...)
1528 {
1529 	static int logerror_running;
1530 	va_list ap;
1531 	char tmpbuf[BUFSIZ];
1532 	char buf[BUFSIZ];
1533 
1534 	/* If there's an error while trying to log an error, give up. */
1535 	if (logerror_running)
1536 		return;
1537 	logerror_running = 1;
1538 
1539 	va_start(ap, fmt);
1540 
1541 	(void)vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap);
1542 
1543 	va_end(ap);
1544 
1545 	if (errno)
1546 		(void)snprintf(buf, sizeof(buf), "syslogd: %s: %s",
1547 		    tmpbuf, strerror(errno));
1548 	else
1549 		(void)snprintf(buf, sizeof(buf), "syslogd: %s", tmpbuf);
1550 
1551 	if (daemonized)
1552 		logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
1553 	if (!daemonized && Debug)
1554 		dprintf("%s\n", buf);
1555 	if (!daemonized && !Debug)
1556 		printf("%s\n", buf);
1557 
1558 	logerror_running = 0;
1559 }
1560 
1561 void
1562 die(struct kevent *ev)
1563 {
1564 	struct filed *f;
1565 	char **p;
1566 
1567 	ShuttingDown = 1;	/* Don't log SIGCHLDs. */
1568 	for (f = Files; f != NULL; f = f->f_next) {
1569 		/* flush any pending output */
1570 		if (f->f_prevcount)
1571 			fprintlog(f, 0, (char *)NULL);
1572 		if (f->f_type == F_PIPE && f->f_un.f_pipe.f_pid > 0) {
1573 			(void) close(f->f_file);
1574 			f->f_un.f_pipe.f_pid = 0;
1575 		}
1576 	}
1577 	errno = 0;
1578 	if (ev != NULL)
1579 		logerror("Exiting on signal %d", (int) ev->ident);
1580 	else
1581 		logerror("Fatal error, exiting");
1582 	for (p = LogPaths; p && *p; p++)
1583 		unlink(*p);
1584 	exit(0);
1585 }
1586 
1587 /*
1588  *  INIT -- Initialize syslogd from configuration table
1589  */
1590 void
1591 init(struct kevent *ev)
1592 {
1593 	int i;
1594 	FILE *cf;
1595 	struct filed *f, *next, **nextp;
1596 	char *p;
1597 	char cline[LINE_MAX];
1598 	char prog[NAME_MAX + 1];
1599 	char host[MAXHOSTNAMELEN];
1600 	char hostMsg[2*MAXHOSTNAMELEN + 40];
1601 
1602 	dprintf("init\n");
1603 
1604 	(void)strlcpy(oldLocalHostName, LocalHostName,
1605 		      sizeof(oldLocalHostName));
1606 	(void)gethostname(LocalHostName, sizeof(LocalHostName));
1607 	if ((p = strchr(LocalHostName, '.')) != NULL) {
1608 		*p++ = '\0';
1609 		LocalDomain = p;
1610 	} else
1611 		LocalDomain = "";
1612 	LocalDomainLen = strlen(LocalDomain);
1613 
1614 	/*
1615 	 *  Close all open log files.
1616 	 */
1617 	Initialized = 0;
1618 	for (f = Files; f != NULL; f = next) {
1619 		/* flush any pending output */
1620 		if (f->f_prevcount)
1621 			fprintlog(f, 0, (char *)NULL);
1622 
1623 		switch (f->f_type) {
1624 		case F_FILE:
1625 		case F_TTY:
1626 		case F_CONSOLE:
1627 			(void)close(f->f_file);
1628 			break;
1629 		case F_PIPE:
1630 			if (f->f_un.f_pipe.f_pid > 0) {
1631 				(void)close(f->f_file);
1632 				deadq_enter(f->f_un.f_pipe.f_pid,
1633 					    f->f_un.f_pipe.f_pname);
1634 			}
1635 			f->f_un.f_pipe.f_pid = 0;
1636 			break;
1637 		case F_FORW:
1638 			if (f->f_un.f_forw.f_addr)
1639 				freeaddrinfo(f->f_un.f_forw.f_addr);
1640 			break;
1641 		}
1642 		next = f->f_next;
1643 		if (f->f_program != NULL)
1644 			free(f->f_program);
1645 		if (f->f_host != NULL)
1646 			free(f->f_host);
1647 		free((char *)f);
1648 	}
1649 	Files = NULL;
1650 	nextp = &Files;
1651 
1652 	/*
1653 	 *  Close all open sockets
1654 	 */
1655 
1656 	if (finet) {
1657 		for (i = 0; i < *finet; i++) {
1658 			if (close(finet[i+1]) < 0) {
1659 				logerror("close() failed");
1660 				die(NULL);
1661 			}
1662 		}
1663 	}
1664 
1665 	/*
1666 	 *  Reset counter of forwarding actions
1667 	 */
1668 
1669 	NumForwards=0;
1670 
1671 	/* open the configuration file */
1672 	if ((cf = fopen(ConfFile, "r")) == NULL) {
1673 		dprintf("Cannot open `%s'\n", ConfFile);
1674 		*nextp = (struct filed *)calloc(1, sizeof(*f));
1675 		cfline("*.ERR\t/dev/console", *nextp, "*", "*");
1676 		(*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
1677 		cfline("*.PANIC\t*", (*nextp)->f_next, "*", "*");
1678 		Initialized = 1;
1679 		return;
1680 	}
1681 
1682 	/*
1683 	 *  Foreach line in the conf table, open that file.
1684 	 */
1685 	f = NULL;
1686 	strcpy(prog, "*");
1687 	strcpy(host, "*");
1688 	while (fgets(cline, sizeof(cline), cf) != NULL) {
1689 		/*
1690 		 * check for end-of-section, comments, strip off trailing
1691 		 * spaces and newline character.  #!prog is treated specially:
1692 		 * following lines apply only to that program.
1693 		 */
1694 		for (p = cline; isspace((unsigned char)*p); ++p)
1695 			continue;
1696 		if (*p == '\0')
1697 			continue;
1698 		if (*p == '#') {
1699 			p++;
1700 			if (*p != '!' && *p != '+' && *p != '-')
1701 				continue;
1702 		}
1703 		if (*p == '+' || *p == '-') {
1704 			host[0] = *p++;
1705 			while (isspace((unsigned char)*p))
1706 				p++;
1707 			if (*p == '\0' || *p == '*') {
1708 				strcpy(host, "*");
1709 				continue;
1710 			}
1711 			if (*p == '@')
1712 				p = LocalHostName;
1713 			for (i = 1; i < MAXHOSTNAMELEN - 1; i++) {
1714 				if (!isalnum((unsigned char)*p) &&
1715 				    *p != '.' && *p != '-' && *p != ',')
1716 					break;
1717 				host[i] = *p++;
1718 			}
1719 			host[i] = '\0';
1720 			continue;
1721 		}
1722 		if (*p == '!') {
1723 			p++;
1724 			while (isspace((unsigned char)*p))
1725 				p++;
1726 			if (*p == '\0' || *p == '*') {
1727 				strcpy(prog, "*");
1728 				continue;
1729 			}
1730 			for (i = 0; i < NAME_MAX; i++) {
1731 				if (!isprint((unsigned char)p[i]))
1732 					break;
1733 				prog[i] = p[i];
1734 			}
1735 			prog[i] = '\0';
1736 			continue;
1737 		}
1738 		for (p = strchr(cline, '\0'); isspace((unsigned char)*--p);)
1739 			continue;
1740 		*++p = '\0';
1741 		f = (struct filed *)calloc(1, sizeof(*f));
1742 		*nextp = f;
1743 		nextp = &f->f_next;
1744 		cfline(cline, f, prog, host);
1745 	}
1746 
1747 	/* close the configuration file */
1748 	(void)fclose(cf);
1749 
1750 	Initialized = 1;
1751 
1752 	if (Debug) {
1753 		for (f = Files; f; f = f->f_next) {
1754 			for (i = 0; i <= LOG_NFACILITIES; i++)
1755 				if (f->f_pmask[i] == INTERNAL_NOPRI)
1756 					printf("X ");
1757 				else
1758 					printf("%d ", f->f_pmask[i]);
1759 			printf("%s: ", TypeNames[f->f_type]);
1760 			switch (f->f_type) {
1761 			case F_FILE:
1762 			case F_TTY:
1763 			case F_CONSOLE:
1764 				printf("%s", f->f_un.f_fname);
1765 				break;
1766 
1767 			case F_FORW:
1768 				printf("%s", f->f_un.f_forw.f_hname);
1769 				break;
1770 
1771 			case F_PIPE:
1772 				printf("%s", f->f_un.f_pipe.f_pname);
1773 				break;
1774 
1775 			case F_USERS:
1776 				for (i = 0;
1777 				    i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
1778 					printf("%s, ", f->f_un.f_uname[i]);
1779 				break;
1780 			}
1781 			if (f->f_program != NULL)
1782 				printf(" (%s)", f->f_program);
1783 			printf("\n");
1784 		}
1785 	}
1786 
1787 	finet = socksetup(PF_UNSPEC);
1788 	if (finet) {
1789 		if (SecureMode) {
1790 			for (i = 0; i < *finet; i++) {
1791 				if (shutdown(finet[i+1], SHUT_RD) < 0) {
1792 					logerror("shutdown() failed");
1793 					die(NULL);
1794 				}
1795 			}
1796 		} else
1797 			dprintf("Listening on inet and/or inet6 socket\n");
1798 		dprintf("Sending on inet and/or inet6 socket\n");
1799 	}
1800 
1801 	logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
1802 	dprintf("syslogd: restarted\n");
1803 	/*
1804 	 * Log a change in hostname, but only on a restart (we detect this
1805 	 * by checking to see if we're passed a kevent).
1806 	 */
1807 	if (ev != NULL && strcmp(oldLocalHostName, LocalHostName) != 0) {
1808 		(void)snprintf(hostMsg, sizeof(hostMsg),
1809 		    "syslogd: host name changed, \"%s\" to \"%s\"",
1810 		    oldLocalHostName, LocalHostName);
1811 		logmsg(LOG_SYSLOG|LOG_INFO, hostMsg, LocalHostName, ADDDATE);
1812 		dprintf("%s\n", hostMsg);
1813 	}
1814 }
1815 
1816 /*
1817  * Crack a configuration file line
1818  */
1819 void
1820 cfline(char *line, struct filed *f, char *prog, char *host)
1821 {
1822 	struct addrinfo hints, *res;
1823 	int    error, i, pri, syncfile;
1824 	char   *bp, *p, *q;
1825 	char   buf[MAXLINE];
1826 
1827 	dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line, prog, host);
1828 
1829 	errno = 0;	/* keep strerror() stuff out of logerror messages */
1830 
1831 	/* clear out file entry */
1832 	memset(f, 0, sizeof(*f));
1833 	for (i = 0; i <= LOG_NFACILITIES; i++)
1834 		f->f_pmask[i] = INTERNAL_NOPRI;
1835 
1836 	/*
1837 	 * There should not be any space before the log facility.
1838 	 * Check this is okay, complain and fix if it is not.
1839 	 */
1840 	q = line;
1841 	if (isblank((unsigned char)*line)) {
1842 		errno = 0;
1843 		logerror(
1844 		    "Warning: `%s' space or tab before the log facility",
1845 		    line);
1846 		/* Fix: strip all spaces/tabs before the log facility */
1847 		while (*q++ && isblank((unsigned char)*q))
1848 			/* skip blanks */;
1849 		line = q;
1850 	}
1851 
1852 	/*
1853 	 * q is now at the first char of the log facility
1854 	 * There should be at least one tab after the log facility
1855 	 * Check this is okay, and complain and fix if it is not.
1856 	 */
1857 	q = line + strlen(line);
1858 	while (!isblank((unsigned char)*q) && (q != line))
1859 		q--;
1860 	if ((q == line) && strlen(line)) {
1861 		/* No tabs or space in a non empty line: complain */
1862 		errno = 0;
1863 		logerror(
1864 		    "Error: `%s' log facility or log target missing",
1865 		    line);
1866 		return;
1867 	}
1868 
1869 	/* save host name, if any */
1870 	if (*host == '*')
1871 		f->f_host = NULL;
1872 	else {
1873 		f->f_host = strdup(host);
1874 		trim_localdomain(f->f_host);
1875 	}
1876 
1877 	/* save program name, if any */
1878 	if (*prog == '*')
1879 		f->f_program = NULL;
1880 	else
1881 		f->f_program = strdup(prog);
1882 
1883 	/* scan through the list of selectors */
1884 	for (p = line; *p && !isblank((unsigned char)*p);) {
1885 		int pri_done, pri_cmp, pri_invert;
1886 
1887 		/* find the end of this facility name list */
1888 		for (q = p; *q && !isblank((unsigned char)*q) && *q++ != '.'; )
1889 			continue;
1890 
1891 		/* get the priority comparison */
1892 		pri_cmp = 0;
1893 		pri_done = 0;
1894 		pri_invert = 0;
1895 		if (*q == '!') {
1896 			pri_invert = 1;
1897 			q++;
1898 		}
1899 		while (! pri_done) {
1900 			switch (*q) {
1901 			case '<':
1902 				pri_cmp = PRI_LT;
1903 				q++;
1904 				break;
1905 			case '=':
1906 				pri_cmp = PRI_EQ;
1907 				q++;
1908 				break;
1909 			case '>':
1910 				pri_cmp = PRI_GT;
1911 				q++;
1912 				break;
1913 			default:
1914 				pri_done = 1;
1915 				break;
1916 			}
1917 		}
1918 
1919 		/* collect priority name */
1920 		for (bp = buf; *q && !strchr("\t ,;", *q); )
1921 			*bp++ = *q++;
1922 		*bp = '\0';
1923 
1924 		/* skip cruft */
1925 		while (strchr(",;", *q))
1926 			q++;
1927 
1928 		/* decode priority name */
1929 		if (*buf == '*') {
1930 			pri = LOG_PRIMASK + 1;
1931 			pri_cmp = PRI_LT | PRI_EQ | PRI_GT;
1932 		} else {
1933 			pri = decode(buf, prioritynames);
1934 			if (pri < 0) {
1935 				errno = 0;
1936 				logerror("Unknown priority name `%s'", buf);
1937 				return;
1938 			}
1939 		}
1940 		if (pri_cmp == 0)
1941 			pri_cmp = UniquePriority ? PRI_EQ
1942 						 : PRI_EQ | PRI_GT;
1943 		if (pri_invert)
1944 			pri_cmp ^= PRI_LT | PRI_EQ | PRI_GT;
1945 
1946 		/* scan facilities */
1947 		while (*p && !strchr("\t .;", *p)) {
1948 			for (bp = buf; *p && !strchr("\t ,;.", *p); )
1949 				*bp++ = *p++;
1950 			*bp = '\0';
1951 			if (*buf == '*')
1952 				for (i = 0; i < LOG_NFACILITIES; i++) {
1953 					f->f_pmask[i] = pri;
1954 					f->f_pcmp[i] = pri_cmp;
1955 				}
1956 			else {
1957 				i = decode(buf, facilitynames);
1958 				if (i < 0) {
1959 					errno = 0;
1960 					logerror("Unknown facility name `%s'",
1961 					    buf);
1962 					return;
1963 				}
1964 				f->f_pmask[i >> 3] = pri;
1965 				f->f_pcmp[i >> 3] = pri_cmp;
1966 			}
1967 			while (*p == ',' || *p == ' ')
1968 				p++;
1969 		}
1970 
1971 		p = q;
1972 	}
1973 
1974 	/* skip to action part */
1975 	while (isblank((unsigned char)*p))
1976 		p++;
1977 
1978 	if (*p == '-') {
1979 		syncfile = 0;
1980 		p++;
1981 	} else
1982 		syncfile = 1;
1983 
1984 	switch (*p) {
1985 	case '@':
1986 		(void)strlcpy(f->f_un.f_forw.f_hname, ++p,
1987 		    sizeof(f->f_un.f_forw.f_hname));
1988 		memset(&hints, 0, sizeof(hints));
1989 		hints.ai_family = AF_UNSPEC;
1990 		hints.ai_socktype = SOCK_DGRAM;
1991 		hints.ai_protocol = 0;
1992 		error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints,
1993 		    &res);
1994 		if (error) {
1995 			logerror(gai_strerror(error));
1996 			break;
1997 		}
1998 		f->f_un.f_forw.f_addr = res;
1999 		f->f_type = F_FORW;
2000 		NumForwards++;
2001 		break;
2002 
2003 	case '/':
2004 		(void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname));
2005 		if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
2006 			f->f_type = F_UNUSED;
2007 			logerror(p);
2008 			break;
2009 		}
2010 		if (syncfile)
2011 			f->f_flags |= FFLAG_SYNC;
2012 		if (isatty(f->f_file))
2013 			f->f_type = F_TTY;
2014 		else
2015 			f->f_type = F_FILE;
2016 		if (strcmp(p, ctty) == 0)
2017 			f->f_type = F_CONSOLE;
2018 		break;
2019 
2020 	case '|':
2021 		f->f_un.f_pipe.f_pid = 0;
2022 		(void) strlcpy(f->f_un.f_pipe.f_pname, p + 1,
2023 		    sizeof(f->f_un.f_pipe.f_pname));
2024 		f->f_type = F_PIPE;
2025 		break;
2026 
2027 	case '*':
2028 		f->f_type = F_WALL;
2029 		break;
2030 
2031 	default:
2032 		for (i = 0; i < MAXUNAMES && *p; i++) {
2033 			for (q = p; *q && *q != ','; )
2034 				q++;
2035 			(void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
2036 			if ((q - p) > UT_NAMESIZE)
2037 				f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
2038 			else
2039 				f->f_un.f_uname[i][q - p] = '\0';
2040 			while (*q == ',' || *q == ' ')
2041 				q++;
2042 			p = q;
2043 		}
2044 		f->f_type = F_USERS;
2045 		break;
2046 	}
2047 }
2048 
2049 
2050 /*
2051  *  Decode a symbolic name to a numeric value
2052  */
2053 int
2054 decode(const char *name, CODE *codetab)
2055 {
2056 	CODE *c;
2057 	char *p, buf[40];
2058 
2059 	if (isdigit((unsigned char)*name))
2060 		return (atoi(name));
2061 
2062 	for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
2063 		if (isupper((unsigned char)*name))
2064 			*p = tolower((unsigned char)*name);
2065 		else
2066 			*p = *name;
2067 	}
2068 	*p = '\0';
2069 	for (c = codetab; c->c_name; c++)
2070 		if (!strcmp(buf, c->c_name))
2071 			return (c->c_val);
2072 
2073 	return (-1);
2074 }
2075 
2076 /*
2077  * Retrieve the size of the kernel message buffer, via sysctl.
2078  */
2079 int
2080 getmsgbufsize(void)
2081 {
2082 	int msgbufsize, mib[2];
2083 	size_t size;
2084 
2085 	mib[0] = CTL_KERN;
2086 	mib[1] = KERN_MSGBUFSIZE;
2087 	size = sizeof msgbufsize;
2088 	if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) {
2089 		dprintf("Couldn't get kern.msgbufsize\n");
2090 		return (0);
2091 	}
2092 	return (msgbufsize);
2093 }
2094 
2095 int *
2096 socksetup(int af)
2097 {
2098 	struct addrinfo hints, *res, *r;
2099 	struct kevent *ev;
2100 	int error, maxs, *s, *socks;
2101 	const int on = 1;
2102 
2103 	if(SecureMode && !NumForwards)
2104 		return(NULL);
2105 
2106 	memset(&hints, 0, sizeof(hints));
2107 	hints.ai_flags = AI_PASSIVE;
2108 	hints.ai_family = af;
2109 	hints.ai_socktype = SOCK_DGRAM;
2110 	error = getaddrinfo(NULL, "syslog", &hints, &res);
2111 	if (error) {
2112 		logerror(gai_strerror(error));
2113 		errno = 0;
2114 		die(NULL);
2115 	}
2116 
2117 	/* Count max number of sockets we may open */
2118 	for (maxs = 0, r = res; r; r = r->ai_next, maxs++)
2119 		continue;
2120 	socks = malloc((maxs+1) * sizeof(int));
2121 	if (!socks) {
2122 		logerror("Couldn't allocate memory for sockets");
2123 		die(NULL);
2124 	}
2125 
2126 	*socks = 0;   /* num of sockets counter at start of array */
2127 	s = socks + 1;
2128 	for (r = res; r; r = r->ai_next) {
2129 		*s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
2130 		if (*s < 0) {
2131 			logerror("socket() failed");
2132 			continue;
2133 		}
2134 		if (r->ai_family == AF_INET6 && setsockopt(*s, IPPROTO_IPV6,
2135 		    IPV6_V6ONLY, &on, sizeof(on)) < 0) {
2136 			logerror("setsockopt(IPV6_V6ONLY) failed");
2137 			close(*s);
2138 			continue;
2139 		}
2140 
2141 		if (!SecureMode) {
2142 			if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
2143 				logerror("bind() failed");
2144 				close(*s);
2145 				continue;
2146 			}
2147 			ev = allocevchange();
2148 			EV_SET(ev, *s, EVFILT_READ, EV_ADD | EV_ENABLE,
2149 			    0, 0, (intptr_t) dispatch_read_finet);
2150 		}
2151 
2152 		*socks = *socks + 1;
2153 		s++;
2154 	}
2155 
2156 	if (*socks == 0) {
2157 		free (socks);
2158 		if(Debug)
2159 			return(NULL);
2160 		else
2161 			die(NULL);
2162 	}
2163 	if (res)
2164 		freeaddrinfo(res);
2165 
2166 	return(socks);
2167 }
2168 
2169 /*
2170  * Fairly similar to popen(3), but returns an open descriptor, as opposed
2171  * to a FILE *.
2172  */
2173 int
2174 p_open(char *prog, pid_t *rpid)
2175 {
2176 	int pfd[2], nulldesc, i;
2177 	pid_t pid;
2178 	char *argv[4];	/* sh -c cmd NULL */
2179 	char errmsg[200];
2180 
2181 	if (pipe(pfd) == -1)
2182 		return (-1);
2183 	if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1) {
2184 		/* We are royally screwed anyway. */
2185 		return (-1);
2186 	}
2187 
2188 	switch ((pid = fork())) {
2189 	case -1:
2190 		(void) close(nulldesc);
2191 		return (-1);
2192 
2193 	case 0:
2194 		argv[0] = "sh";
2195 		argv[1] = "-c";
2196 		argv[2] = prog;
2197 		argv[3] = NULL;
2198 
2199 		(void) setsid();	/* avoid catching SIGHUPs. */
2200 
2201 		/*
2202 		 * Reset ignored signals to their default behavior.
2203 		 */
2204 		(void)signal(SIGTERM, SIG_DFL);
2205 		(void)signal(SIGINT, SIG_DFL);
2206 		(void)signal(SIGQUIT, SIG_DFL);
2207 		(void)signal(SIGPIPE, SIG_DFL);
2208 		(void)signal(SIGHUP, SIG_DFL);
2209 
2210 		dup2(pfd[0], STDIN_FILENO);
2211 		dup2(nulldesc, STDOUT_FILENO);
2212 		dup2(nulldesc, STDERR_FILENO);
2213 		for (i = getdtablesize(); i > 2; i--)
2214 			(void) close(i);
2215 
2216 		(void) execvp(_PATH_BSHELL, argv);
2217 		_exit(255);
2218 	}
2219 
2220 	(void) close(nulldesc);
2221 	(void) close(pfd[0]);
2222 
2223 	/*
2224 	 * Avoid blocking on a hung pipe.  With O_NONBLOCK, we are
2225 	 * supposed to get an EWOULDBLOCK on writev(2), which is
2226 	 * caught by the logic above anyway, which will in turn
2227 	 * close the pipe, and fork a new logging subprocess if
2228 	 * necessary.  The stale subprocess will be killed some
2229 	 * time later unless it terminated itself due to closing
2230 	 * its input pipe.
2231 	 */
2232 	if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
2233 		/* This is bad. */
2234 		(void) snprintf(errmsg, sizeof(errmsg),
2235 		    "Warning: cannot change pipe to pid %d to "
2236 		    "non-blocking.", (int) pid);
2237 		logerror(errmsg);
2238 	}
2239 	*rpid = pid;
2240 	return (pfd[1]);
2241 }
2242 
2243 void
2244 deadq_enter(pid_t pid, const char *name)
2245 {
2246 	dq_t p;
2247 	int status;
2248 
2249 	/*
2250 	 * Be paranoid: if we can't signal the process, don't enter it
2251 	 * into the dead queue (perhaps it's already dead).  If possible,
2252 	 * we try to fetch and log the child's status.
2253 	 */
2254 	if (kill(pid, 0) != 0) {
2255 		if (waitpid(pid, &status, WNOHANG) > 0)
2256 			log_deadchild(pid, status, name);
2257 		return;
2258 	}
2259 
2260 	p = malloc(sizeof(*p));
2261 	if (p == NULL) {
2262 		errno = 0;
2263 		logerror("panic: out of memory!");
2264 		exit(1);
2265 	}
2266 
2267 	p->dq_pid = pid;
2268 	p->dq_timeout = DQ_TIMO_INIT;
2269 	TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries);
2270 }
2271 
2272 int
2273 deadq_remove(pid_t pid)
2274 {
2275 	dq_t q;
2276 
2277 	for (q = TAILQ_FIRST(&deadq_head); q != NULL;
2278 	     q = TAILQ_NEXT(q, dq_entries)) {
2279 		if (q->dq_pid == pid) {
2280 			TAILQ_REMOVE(&deadq_head, q, dq_entries);
2281 			free(q);
2282 			return (1);
2283 		}
2284 	}
2285 	return (0);
2286 }
2287 
2288 void
2289 log_deadchild(pid_t pid, int status, const char *name)
2290 {
2291 	int code;
2292 	char buf[256];
2293 	const char *reason;
2294 
2295 	/* Keep strerror() struff out of logerror messages. */
2296 	errno = 0;
2297 	if (WIFSIGNALED(status)) {
2298 		reason = "due to signal";
2299 		code = WTERMSIG(status);
2300 	} else {
2301 		reason = "with status";
2302 		code = WEXITSTATUS(status);
2303 		if (code == 0)
2304 			return;
2305 	}
2306 	(void) snprintf(buf, sizeof(buf),
2307 	    "Logging subprocess %d (%s) exited %s %d.",
2308 	    pid, name, reason, code);
2309 	logerror(buf);
2310 }
2311 
2312 static struct kevent changebuf[8];
2313 static int nchanges;
2314 
2315 static struct kevent *
2316 allocevchange(void)
2317 {
2318 
2319 	if (nchanges == A_CNT(changebuf)) {
2320 		/* XXX Error handling could be improved. */
2321 		(void) wait_for_events(NULL, 0);
2322 	}
2323 
2324 	return (&changebuf[nchanges++]);
2325 }
2326 
2327 static int
2328 wait_for_events(struct kevent *events, size_t nevents)
2329 {
2330 	int rv;
2331 
2332 	rv = kevent(fkq, nchanges ? changebuf : NULL, nchanges,
2333 		    events, nevents, NULL);
2334 	nchanges = 0;
2335 	return (rv);
2336 }
2337