xref: /openbsd-src/usr.sbin/syslogd/syslogd.c (revision f191fa1fe4a3161a974e141a68a46aa2ff59ecbb)
1 /*	$OpenBSD: syslogd.c,v 1.132 2014/12/03 17:00:15 millert 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 /*
33  *  syslogd -- log system messages
34  *
35  * This program implements a system log. It takes a series of lines.
36  * Each line may have a priority, signified as "<n>" as
37  * the first characters of the line.  If this is
38  * not present, a default priority is used.
39  *
40  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
41  * cause it to reread its configuration file.
42  *
43  * Defined Constants:
44  *
45  * MAXLINE -- the maximum line length that can be handled.
46  * DEFUPRI -- the default priority for user messages
47  * DEFSPRI -- the default priority for kernel messages
48  *
49  * Author: Eric Allman
50  * extensive changes by Ralph Campbell
51  * more extensive changes by Eric Allman (again)
52  * memory buffer logging by Damien Miller
53  * IPv6, libevent by Alexander Bluhm
54  */
55 
56 #define	MAXLINE		1024		/* maximum line length */
57 #define MIN_MEMBUF	(MAXLINE * 4)	/* Minimum memory buffer size */
58 #define MAX_MEMBUF	(256 * 1024)	/* Maximum memory buffer size */
59 #define MAX_MEMBUF_NAME	64		/* Max length of membuf log name */
60 #define	MAXSVLINE	120		/* maximum saved line length */
61 #define DEFUPRI		(LOG_USER|LOG_NOTICE)
62 #define DEFSPRI		(LOG_KERN|LOG_CRIT)
63 #define TIMERINTVL	30		/* interval for checking flush, mark */
64 #define TTYMSGTIME	1		/* timeout passed to ttymsg */
65 
66 #include <sys/param.h>
67 #include <sys/ioctl.h>
68 #include <sys/stat.h>
69 #include <sys/wait.h>
70 #include <sys/socket.h>
71 #include <sys/msgbuf.h>
72 #include <sys/uio.h>
73 #include <sys/sysctl.h>
74 #include <sys/un.h>
75 #include <sys/time.h>
76 #include <sys/resource.h>
77 
78 #include <netinet/in.h>
79 #include <netdb.h>
80 #include <arpa/inet.h>
81 
82 #include <ctype.h>
83 #include <errno.h>
84 #include <err.h>
85 #include <event.h>
86 #include <fcntl.h>
87 #include <paths.h>
88 #include <poll.h>
89 #include <signal.h>
90 #include <stdio.h>
91 #include <stdlib.h>
92 #include <string.h>
93 #include <unistd.h>
94 #include <utmp.h>
95 #include <vis.h>
96 
97 #define SYSLOG_NAMES
98 #include <sys/syslog.h>
99 
100 #include "syslogd.h"
101 
102 char *ConfFile = _PATH_LOGCONF;
103 const char ctty[] = _PATH_CONSOLE;
104 
105 #define MAXUNAMES	20	/* maximum number of user names */
106 
107 
108 /*
109  * Flags to logmsg().
110  */
111 
112 #define IGN_CONS	0x001	/* don't print on console */
113 #define SYNC_FILE	0x002	/* do fsync on file after printing */
114 #define ADDDATE		0x004	/* add a date to the message */
115 #define MARK		0x008	/* this message is a mark */
116 
117 /*
118  * This structure represents the files that will have log
119  * copies printed.
120  */
121 
122 struct filed {
123 	struct	filed *f_next;		/* next in linked list */
124 	short	f_type;			/* entry type, see below */
125 	short	f_file;			/* file descriptor */
126 	time_t	f_time;			/* time this was last written */
127 	u_char	f_pmask[LOG_NFACILITIES+1];	/* priority mask */
128 	char	*f_program;		/* program this applies to */
129 	union {
130 		char	f_uname[MAXUNAMES][UT_NAMESIZE+1];
131 		struct {
132 			char	f_loghost[1+4+3+1+MAXHOSTNAMELEN+1+NI_MAXSERV];
133 				/* @proto46://[hostname]:servname\0 */
134 			struct sockaddr_storage	f_addr;
135 		} f_forw;		/* forwarding address */
136 		char	f_fname[MAXPATHLEN];
137 		struct {
138 			char	f_mname[MAX_MEMBUF_NAME];
139 			struct ringbuf *f_rb;
140 			int	f_overflow;
141 			int	f_attached;
142 			size_t	f_len;
143 		} f_mb;		/* Memory buffer */
144 	} f_un;
145 	char	f_prevline[MAXSVLINE];		/* last message logged */
146 	char	f_lasttime[16];			/* time of last occurrence */
147 	char	f_prevhost[MAXHOSTNAMELEN];	/* host from which recd. */
148 	int	f_prevpri;			/* pri of f_prevline */
149 	int	f_prevlen;			/* length of f_prevline */
150 	int	f_prevcount;			/* repetition cnt of prevline */
151 	unsigned int f_repeatcount;		/* number of "repeated" msgs */
152 	int	f_quick;			/* abort when matched */
153 	time_t	f_lasterrtime;			/* last error was reported */
154 };
155 
156 /*
157  * Intervals at which we flush out "message repeated" messages,
158  * in seconds after previous message is logged.  After each flush,
159  * we move to the next interval until we reach the largest.
160  */
161 int	repeatinterval[] = { 30, 120, 600 };	/* # of secs before flush */
162 #define	MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
163 #define	REPEATTIME(f)	((f)->f_time + repeatinterval[(f)->f_repeatcount])
164 #define	BACKOFF(f)	{ if (++(f)->f_repeatcount > MAXREPEAT) \
165 				(f)->f_repeatcount = MAXREPEAT; \
166 			}
167 
168 /* values for f_type */
169 #define F_UNUSED	0		/* unused entry */
170 #define F_FILE		1		/* regular file */
171 #define F_TTY		2		/* terminal */
172 #define F_CONSOLE	3		/* console terminal */
173 #define F_FORW		4		/* remote machine */
174 #define F_USERS		5		/* list of users */
175 #define F_WALL		6		/* everyone logged on */
176 #define F_MEMBUF	7		/* memory buffer */
177 #define F_PIPE		8		/* pipe to external program */
178 
179 char	*TypeNames[9] = {
180 	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
181 	"FORW",		"USERS",	"WALL",		"MEMBUF",
182 	"PIPE"
183 };
184 
185 struct	filed *Files;
186 struct	filed consfile;
187 
188 int	nunix = 1;		/* Number of Unix domain sockets requested */
189 char	*path_unix[MAXUNIX] = { _PATH_LOG }; /* Paths to Unix domain sockets */
190 int	Debug;			/* debug flag */
191 int	Startup = 1;		/* startup flag */
192 char	LocalHostName[MAXHOSTNAMELEN];	/* our hostname */
193 char	*LocalDomain;		/* our local domain name */
194 int	Initialized = 0;	/* set when we have initialized ourselves */
195 
196 int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
197 int	MarkSeq = 0;		/* mark sequence number */
198 int	SecureMode = 1;		/* when true, speak only unix domain socks */
199 int	NoDNS = 0;		/* when true, will refrain from doing DNS lookups */
200 int	IPv4Only = 0;		/* when true, disable IPv6 */
201 int	IPv6Only = 0;		/* when true, disable IPv4 */
202 int	IncludeHostname = 0;	/* include RFC 3164 style hostnames when forwarding */
203 
204 char	*path_ctlsock = NULL;	/* Path to control socket */
205 
206 #define CTL_READING_CMD		1
207 #define CTL_WRITING_REPLY	2
208 #define CTL_WRITING_CONT_REPLY	3
209 int	ctl_state = 0;		/* What the control socket is up to */
210 int	membuf_drop = 0;	/* logs were dropped in continuous membuf read */
211 
212 /*
213  * Client protocol NB. all numeric fields in network byte order
214  */
215 #define CTL_VERSION		2
216 
217 /* Request */
218 struct	{
219 	u_int32_t	version;
220 #define CMD_READ	1	/* Read out log */
221 #define CMD_READ_CLEAR	2	/* Read and clear log */
222 #define CMD_CLEAR	3	/* Clear log */
223 #define CMD_LIST	4	/* List available logs */
224 #define CMD_FLAGS	5	/* Query flags only */
225 #define CMD_READ_CONT	6	/* Read out log continuously */
226 	u_int32_t	cmd;
227 	u_int32_t	lines;
228 	char		logname[MAX_MEMBUF_NAME];
229 }	ctl_cmd;
230 
231 size_t	ctl_cmd_bytes = 0;	/* number of bytes of ctl_cmd read */
232 
233 /* Reply */
234 struct ctl_reply_hdr {
235 	u_int32_t	version;
236 #define CTL_HDR_FLAG_OVERFLOW	0x01
237 	u_int32_t	flags;
238 	/* Reply text follows, up to MAX_MEMBUF long */
239 };
240 
241 #define CTL_HDR_LEN		(sizeof(struct ctl_reply_hdr))
242 #define CTL_REPLY_MAXSIZE	(CTL_HDR_LEN + MAX_MEMBUF)
243 #define CTL_REPLY_SIZE		(strlen(reply_text) + CTL_HDR_LEN)
244 
245 char	*ctl_reply = NULL;	/* Buffer for control connection reply */
246 char	*reply_text;		/* Start of reply text in buffer */
247 size_t	ctl_reply_size = 0;	/* Number of bytes used in reply */
248 size_t	ctl_reply_offset = 0;	/* Number of bytes of reply written so far */
249 
250 char	*linebuf;
251 int	 linesize;
252 
253 int		 fd_ctlsock, fd_ctlconn, fd_klog, fd_sendsys,
254 		 fd_udp, fd_udp6, fd_unix[MAXUNIX];
255 struct event	 ev_ctlaccept, ev_ctlread, ev_ctlwrite, ev_klog, ev_sendsys,
256 		 ev_udp, ev_udp6, ev_unix[MAXUNIX],
257 		 ev_hup, ev_int, ev_quit, ev_term, ev_mark;
258 
259 void	 klog_readcb(int, short, void *);
260 void	 udp_readcb(int, short, void *);
261 void	 unix_readcb(int, short, void *);
262 void	 die_signalcb(int, short, void *);
263 void	 mark_timercb(int, short, void *);
264 void	 init_signalcb(int, short, void *);
265 void	 ctlsock_acceptcb(int, short, void *);
266 void	 ctlconn_readcb(int, short, void *);
267 void	 ctlconn_writecb(int, short, void *);
268 void	 ctlconn_logto(char *);
269 void	 ctlconn_cleanup(void);
270 
271 struct filed *cfline(char *, char *);
272 void	cvthname(struct sockaddr *, char *, size_t);
273 int	decode(const char *, const CODE *);
274 void	die(int);
275 void	markit(void);
276 void	fprintlog(struct filed *, int, char *);
277 void	init(void);
278 void	logerror(const char *);
279 void	logmsg(int, char *, char *, int);
280 struct filed *find_dup(struct filed *);
281 void	printline(char *, char *);
282 void	printsys(char *);
283 char   *ttymsg(struct iovec *, int, char *, int);
284 void	usage(void);
285 void	wallmsg(struct filed *, struct iovec *);
286 int	loghost(char *, char **, char **, char **);
287 int	getmsgbufsize(void);
288 int	unix_socket(char *, int, mode_t);
289 void	double_rbuf(int);
290 void	tailify_replytext(char *, int);
291 
292 int
293 main(int argc, char *argv[])
294 {
295 	struct addrinfo	 hints, *res, *res0;
296 	struct timeval	 to;
297 	char		*p;
298 	int		 ch, i;
299 	int		 lockpipe[2] = { -1, -1}, pair[2], nullfd, fd;
300 
301 	while ((ch = getopt(argc, argv, "46dhnuf:m:p:a:s:")) != -1)
302 		switch (ch) {
303 		case '4':		/* disable IPv6 */
304 			IPv4Only = 1;
305 			IPv6Only = 0;
306 			break;
307 		case '6':		/* disable IPv4 */
308 			IPv6Only = 1;
309 			IPv4Only = 0;
310 			break;
311 		case 'd':		/* debug */
312 			Debug++;
313 			break;
314 		case 'f':		/* configuration file */
315 			ConfFile = optarg;
316 			break;
317 		case 'h':		/* RFC 3164 hostnames */
318 			IncludeHostname = 1;
319 			break;
320 		case 'm':		/* mark interval */
321 			MarkInterval = atoi(optarg) * 60;
322 			break;
323 		case 'n':		/* don't do DNS lookups */
324 			NoDNS = 1;
325 			break;
326 		case 'p':		/* path */
327 			path_unix[0] = optarg;
328 			break;
329 		case 'u':		/* allow udp input port */
330 			SecureMode = 0;
331 			break;
332 		case 'a':
333 			if (nunix >= MAXUNIX)
334 				fprintf(stderr, "syslogd: "
335 				    "out of descriptors, ignoring %s\n",
336 				    optarg);
337 			else
338 				path_unix[nunix++] = optarg;
339 			break;
340 		case 's':
341 			path_ctlsock = optarg;
342 			break;
343 		default:
344 			usage();
345 		}
346 	if ((argc -= optind) != 0)
347 		usage();
348 
349 	if (Debug)
350 		setvbuf(stdout, NULL, _IOLBF, 0);
351 
352 	if ((fd = nullfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
353 		logerror("Couldn't open /dev/null");
354 		die(0);
355 	}
356 	while (fd++ <= 2) {
357 		if (fcntl(fd, F_GETFL, 0) == -1)
358 			if (dup2(nullfd, fd) == -1)
359 				logerror("dup2");
360 	}
361 
362 	consfile.f_type = F_CONSOLE;
363 	(void)strlcpy(consfile.f_un.f_fname, ctty,
364 	    sizeof(consfile.f_un.f_fname));
365 	(void)gethostname(LocalHostName, sizeof(LocalHostName));
366 	if ((p = strchr(LocalHostName, '.')) != NULL) {
367 		*p++ = '\0';
368 		LocalDomain = p;
369 	} else
370 		LocalDomain = "";
371 
372 	linesize = getmsgbufsize();
373 	if (linesize < MAXLINE)
374 		linesize = MAXLINE;
375 	linesize++;
376 	if ((linebuf = malloc(linesize)) == NULL) {
377 		logerror("Couldn't allocate line buffer");
378 		die(0);
379 	}
380 
381 	memset(&hints, 0, sizeof(hints));
382 	hints.ai_family = AF_UNSPEC;
383 	hints.ai_socktype = SOCK_DGRAM;
384 	hints.ai_protocol = IPPROTO_UDP;
385 	hints.ai_flags = AI_PASSIVE;
386 
387 	i = getaddrinfo(NULL, "syslog", &hints, &res0);
388 	if (i) {
389 		errno = 0;
390 		logerror("syslog/udp: unknown service");
391 		die(0);
392 	}
393 
394 	fd_udp = fd_udp6 = -1;
395 	for (res = res0; res; res = res->ai_next) {
396 		int *fdp;
397 
398 		switch (res->ai_family) {
399 		case AF_INET:
400 			if (IPv6Only)
401 				continue;
402 			fdp = &fd_udp;
403 			break;
404 		case AF_INET6:
405 			if (IPv4Only)
406 				continue;
407 			fdp = &fd_udp6;
408 			break;
409 		default:
410 			continue;
411 		}
412 
413 		if (*fdp >= 0)
414 			continue;
415 
416 		*fdp = socket(res->ai_family, res->ai_socktype,
417 		    res->ai_protocol);
418 		if (*fdp == -1)
419 			continue;
420 
421 		if (bind(*fdp, res->ai_addr, res->ai_addrlen) < 0) {
422 			logerror("bind");
423 			close(*fdp);
424 			*fdp = -1;
425 			if (!Debug)
426 				die(0);
427 			continue;
428 		}
429 
430 		if (SecureMode)
431 			shutdown(*fdp, SHUT_RD);
432 		else
433 			double_rbuf(*fdp);
434 	}
435 
436 	freeaddrinfo(res0);
437 
438 #ifndef SUN_LEN
439 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
440 #endif
441 	for (i = 0; i < nunix; i++) {
442 		fd_unix[i] = unix_socket(path_unix[i], SOCK_DGRAM, 0666);
443 		if (fd_unix[i] == -1) {
444 			if (i == 0 && !Debug)
445 				die(0);
446 			continue;
447 		}
448 		double_rbuf(fd_unix[i]);
449 	}
450 
451 	if (socketpair(AF_UNIX, SOCK_DGRAM, PF_UNSPEC, pair) == -1)
452 		die(0);
453 	fd_sendsys = pair[0];
454 	double_rbuf(fd_sendsys);
455 
456 	fd_ctlsock = fd_ctlconn = -1;
457 	if (path_ctlsock != NULL) {
458 		fd_ctlsock = unix_socket(path_ctlsock, SOCK_STREAM, 0600);
459 		if (fd_ctlsock == -1) {
460 			dprintf("can't open %s (%d)\n", path_ctlsock, errno);
461 			if (!Debug)
462 				die(0);
463 		} else {
464 			if (listen(fd_ctlsock, 16) == -1) {
465 				logerror("ctlsock listen");
466 				die(0);
467 			}
468 		}
469 	}
470 
471 	fd_klog = open(_PATH_KLOG, O_RDONLY, 0);
472 	if (fd_klog == -1) {
473 		dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
474 	} else {
475 		if (ioctl(fd_klog, LIOCSFD, &pair[1]) == -1)
476 			dprintf("LIOCSFD errno %d\n", errno);
477 	}
478 	close(pair[1]);
479 
480 	dprintf("off & running....\n");
481 
482 	chdir("/");
483 
484 	tzset();
485 
486 	if (!Debug) {
487 		char c;
488 
489 		pipe(lockpipe);
490 
491 		switch(fork()) {
492 		case -1:
493 			exit(1);
494 		case 0:
495 			setsid();
496 			close(lockpipe[0]);
497 			break;
498 		default:
499 			close(lockpipe[1]);
500 			read(lockpipe[0], &c, 1);
501 			_exit(0);
502 		}
503 	}
504 
505 	/* tuck my process id away */
506 	if (!Debug) {
507 		FILE *fp;
508 
509 		fp = fopen(_PATH_LOGPID, "w");
510 		if (fp != NULL) {
511 			fprintf(fp, "%ld\n", (long)getpid());
512 			(void) fclose(fp);
513 		}
514 	}
515 
516 	/* Privilege separation begins here */
517 	if (priv_init(ConfFile, NoDNS, lockpipe[1], nullfd, argv) < 0)
518 		errx(1, "unable to privsep");
519 
520 	/* Process is now unprivileged and inside a chroot */
521 	event_init();
522 
523 	event_set(&ev_ctlaccept, fd_ctlsock, EV_READ|EV_PERSIST,
524 	    ctlsock_acceptcb, &ev_ctlaccept);
525 	event_set(&ev_ctlread, fd_ctlconn, EV_READ|EV_PERSIST,
526 	    ctlconn_readcb, &ev_ctlread);
527 	event_set(&ev_ctlwrite, fd_ctlconn, EV_WRITE|EV_PERSIST,
528 	    ctlconn_writecb, &ev_ctlwrite);
529 	event_set(&ev_klog, fd_klog, EV_READ|EV_PERSIST, klog_readcb, &ev_klog);
530 	event_set(&ev_sendsys, fd_sendsys, EV_READ|EV_PERSIST, unix_readcb,
531 	    &ev_sendsys);
532 	event_set(&ev_udp, fd_udp, EV_READ|EV_PERSIST, udp_readcb, &ev_udp);
533 	event_set(&ev_udp6, fd_udp6, EV_READ|EV_PERSIST, udp_readcb, &ev_udp6);
534 	for (i = 0; i < nunix; i++)
535 		event_set(&ev_unix[i], fd_unix[i], EV_READ|EV_PERSIST,
536 		    unix_readcb, &ev_unix[i]);
537 
538 	signal_set(&ev_hup, SIGHUP, init_signalcb, &ev_hup);
539 	signal_set(&ev_int, SIGINT, die_signalcb, &ev_int);
540 	signal_set(&ev_quit, SIGQUIT, die_signalcb, &ev_quit);
541 	signal_set(&ev_term, SIGTERM, die_signalcb, &ev_term);
542 
543 	evtimer_set(&ev_mark, mark_timercb, &ev_mark);
544 
545 	init();
546 
547 	Startup = 0;
548 
549 	/* Allocate ctl socket reply buffer if we have a ctl socket */
550 	if (fd_ctlsock != -1 &&
551 	    (ctl_reply = malloc(CTL_REPLY_MAXSIZE)) == NULL) {
552 		logerror("Couldn't allocate ctlsock reply buffer");
553 		die(0);
554 	}
555 	reply_text = ctl_reply + CTL_HDR_LEN;
556 
557 	if (!Debug) {
558 		dup2(nullfd, STDIN_FILENO);
559 		dup2(nullfd, STDOUT_FILENO);
560 		dup2(nullfd, STDERR_FILENO);
561 		close(lockpipe[1]);
562 	}
563 	if (nullfd > 2)
564 		close(nullfd);
565 
566 	/*
567 	 * Signal to the priv process that the initial config parsing is done
568 	 * so that it will reject any future attempts to open more files
569 	 */
570 	priv_config_parse_done();
571 
572 	if (fd_ctlsock != -1)
573 		event_add(&ev_ctlaccept, NULL);
574 	if (fd_klog != -1)
575 		event_add(&ev_klog, NULL);
576 	if (fd_sendsys != -1)
577 		event_add(&ev_sendsys, NULL);
578 	if (!SecureMode) {
579 		if (fd_udp != -1)
580 			event_add(&ev_udp, NULL);
581 		if (fd_udp6 != -1)
582 			event_add(&ev_udp6, NULL);
583 	}
584 	for (i = 0; i < nunix; i++)
585 		if (fd_unix[i] != -1)
586 			event_add(&ev_unix[i], NULL);
587 
588 	signal_add(&ev_hup, NULL);
589 	signal_add(&ev_term, NULL);
590 	if (Debug) {
591 		signal_add(&ev_int, NULL);
592 		signal_add(&ev_quit, NULL);
593 	} else {
594 		(void)signal(SIGINT, SIG_IGN);
595 		(void)signal(SIGQUIT, SIG_IGN);
596 	}
597 	(void)signal(SIGCHLD, SIG_IGN);
598 	(void)signal(SIGPIPE, SIG_IGN);
599 
600 	to.tv_sec = TIMERINTVL;
601 	to.tv_usec = 0;
602 	evtimer_add(&ev_mark, &to);
603 
604 	logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: start", LocalHostName, ADDDATE);
605 	dprintf("syslogd: started\n");
606 
607 	event_dispatch();
608 	/* NOTREACHED */
609 	return (0);
610 }
611 
612 void
613 klog_readcb(int fd, short event, void *arg)
614 {
615 	struct event		*ev = arg;
616 	ssize_t			 n;
617 
618 	n = read(fd, linebuf, linesize - 1);
619 	if (n > 0) {
620 		linebuf[n] = '\0';
621 		printsys(linebuf);
622 	} else if (n < 0 && errno != EINTR) {
623 		logerror("klog");
624 		event_del(ev);
625 	}
626 }
627 
628 void
629 udp_readcb(int fd, short event, void *arg)
630 {
631 	struct sockaddr_storage	 sa;
632 	socklen_t		 salen;
633 	ssize_t			 n;
634 
635 	salen = sizeof(sa);
636 	n = recvfrom(fd, linebuf, MAXLINE, 0, (struct sockaddr *)&sa, &salen);
637 	if (n > 0) {
638 		char	 resolve[MAXHOSTNAMELEN];
639 
640 		linebuf[n] = '\0';
641 		cvthname((struct sockaddr *)&sa, resolve, sizeof(resolve));
642 		dprintf("cvthname res: %s\n", resolve);
643 		printline(resolve, linebuf);
644 	} else if (n < 0 && errno != EINTR)
645 		logerror("recvfrom udp");
646 }
647 
648 void
649 unix_readcb(int fd, short event, void *arg)
650 {
651 	struct sockaddr_un	 sa;
652 	socklen_t		 salen;
653 	ssize_t			 n;
654 
655 	salen = sizeof(sa);
656 	n = recvfrom(fd, linebuf, MAXLINE, 0, (struct sockaddr *)&sa, &salen);
657 	if (n > 0) {
658 		linebuf[n] = '\0';
659 		printline(LocalHostName, linebuf);
660 	} else if (n == -1 && errno != EINTR)
661 		logerror("recvfrom unix");
662 }
663 
664 void
665 usage(void)
666 {
667 
668 	(void)fprintf(stderr,
669 	    "usage: syslogd [-46dhnu] [-a path] [-f config_file] [-m mark_interval]\n"
670 	    "               [-p log_socket] [-s reporting_socket]\n");
671 	exit(1);
672 }
673 
674 /*
675  * Take a raw input line, decode the message, and print the message
676  * on the appropriate log files.
677  */
678 void
679 printline(char *hname, char *msg)
680 {
681 	int pri;
682 	char *p, *q, line[MAXLINE + 1];
683 
684 	/* test for special codes */
685 	pri = DEFUPRI;
686 	p = msg;
687 	if (*p == '<') {
688 		pri = 0;
689 		while (isdigit((unsigned char)*++p))
690 			pri = 10 * pri + (*p - '0');
691 		if (*p == '>')
692 			++p;
693 	}
694 	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
695 		pri = DEFUPRI;
696 
697 	/*
698 	 * Don't allow users to log kernel messages.
699 	 * NOTE: since LOG_KERN == 0 this will also match
700 	 * messages with no facility specified.
701 	 */
702 	if (LOG_FAC(pri) == LOG_KERN)
703 		pri = LOG_USER | LOG_PRI(pri);
704 
705 	for (q = line; *p && q < &line[sizeof(line) - 4]; p++) {
706 		if (*p == '\n')
707 			*q++ = ' ';
708 		else
709 			q = vis(q, *p, 0, 0);
710 	}
711 	*q = '\0';
712 
713 	logmsg(pri, line, hname, 0);
714 }
715 
716 /*
717  * Take a raw input line from /dev/klog, split and format similar to syslog().
718  */
719 void
720 printsys(char *msg)
721 {
722 	int c, pri, flags;
723 	char *lp, *p, *q, line[MAXLINE + 1];
724 
725 	(void)snprintf(line, sizeof line, "%s: ", _PATH_UNIX);
726 	lp = line + strlen(line);
727 	for (p = msg; *p != '\0'; ) {
728 		flags = SYNC_FILE | ADDDATE;	/* fsync file after write */
729 		pri = DEFSPRI;
730 		if (*p == '<') {
731 			pri = 0;
732 			while (isdigit((unsigned char)*++p))
733 				pri = 10 * pri + (*p - '0');
734 			if (*p == '>')
735 				++p;
736 		} else {
737 			/* kernel printf's come out on console */
738 			flags |= IGN_CONS;
739 		}
740 		if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
741 			pri = DEFSPRI;
742 
743 		q = lp;
744 		while (*p && (c = *p++) != '\n' && q < &line[sizeof(line) - 4])
745 			q = vis(q, c, 0, 0);
746 
747 		logmsg(pri, line, LocalHostName, flags);
748 	}
749 }
750 
751 time_t	now;
752 
753 /*
754  * Log a message to the appropriate log files, users, etc. based on
755  * the priority.
756  */
757 void
758 logmsg(int pri, char *msg, char *from, int flags)
759 {
760 	struct filed *f;
761 	int fac, msglen, prilev, i;
762 	char *timestamp;
763 	char prog[NAME_MAX+1];
764 
765 	dprintf("logmsg: pri 0%o, flags 0x%x, from %s, msg %s\n",
766 	    pri, flags, from, msg);
767 
768 	/*
769 	 * Check to see if msg looks non-standard.
770 	 */
771 	msglen = strlen(msg);
772 	if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
773 	    msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
774 		flags |= ADDDATE;
775 
776 	(void)time(&now);
777 	if (flags & ADDDATE)
778 		timestamp = ctime(&now) + 4;
779 	else {
780 		timestamp = msg;
781 		msg += 16;
782 		msglen -= 16;
783 	}
784 
785 	/* extract facility and priority level */
786 	if (flags & MARK)
787 		fac = LOG_NFACILITIES;
788 	else {
789 		fac = LOG_FAC(pri);
790 		if (fac >= LOG_NFACILITIES || fac < 0)
791 			fac = LOG_USER;
792 	}
793 	prilev = LOG_PRI(pri);
794 
795 	/* extract program name */
796 	while (isspace((unsigned char)*msg))
797 		msg++;
798 	for (i = 0; i < NAME_MAX; i++) {
799 		if (!isalnum((unsigned char)msg[i]) && msg[i] != '-')
800 			break;
801 		prog[i] = msg[i];
802 	}
803 	prog[i] = 0;
804 
805 	/* log the message to the particular outputs */
806 	if (!Initialized) {
807 		f = &consfile;
808 		f->f_file = priv_open_tty(ctty);
809 
810 		if (f->f_file >= 0) {
811 			fprintlog(f, flags, msg);
812 			(void)close(f->f_file);
813 			f->f_file = -1;
814 		}
815 		return;
816 	}
817 	for (f = Files; f; f = f->f_next) {
818 		/* skip messages that are incorrect priority */
819 		if (f->f_pmask[fac] < prilev ||
820 		    f->f_pmask[fac] == INTERNAL_NOPRI)
821 			continue;
822 
823 		/* skip messages with the incorrect program name */
824 		if (f->f_program)
825 			if (strcmp(prog, f->f_program) != 0)
826 				continue;
827 
828 		if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
829 			continue;
830 
831 		/* don't output marks to recently written files */
832 		if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
833 			continue;
834 
835 		/*
836 		 * suppress duplicate lines to this file
837 		 */
838 		if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
839 		    !strcmp(msg, f->f_prevline) &&
840 		    !strcmp(from, f->f_prevhost)) {
841 			strlcpy(f->f_lasttime, timestamp, 16);
842 			f->f_prevcount++;
843 			dprintf("msg repeated %d times, %ld sec of %d\n",
844 			    f->f_prevcount, (long)(now - f->f_time),
845 			    repeatinterval[f->f_repeatcount]);
846 			/*
847 			 * If domark would have logged this by now,
848 			 * flush it now (so we don't hold isolated messages),
849 			 * but back off so we'll flush less often
850 			 * in the future.
851 			 */
852 			if (now > REPEATTIME(f)) {
853 				fprintlog(f, flags, (char *)NULL);
854 				BACKOFF(f);
855 			}
856 		} else {
857 			/* new line, save it */
858 			if (f->f_prevcount)
859 				fprintlog(f, 0, (char *)NULL);
860 			f->f_repeatcount = 0;
861 			f->f_prevpri = pri;
862 			strlcpy(f->f_lasttime, timestamp, 16);
863 			strlcpy(f->f_prevhost, from,
864 			    sizeof(f->f_prevhost));
865 			if (msglen < MAXSVLINE) {
866 				f->f_prevlen = msglen;
867 				strlcpy(f->f_prevline, msg, sizeof(f->f_prevline));
868 				fprintlog(f, flags, (char *)NULL);
869 			} else {
870 				f->f_prevline[0] = 0;
871 				f->f_prevlen = 0;
872 				fprintlog(f, flags, msg);
873 			}
874 		}
875 
876 		if (f->f_quick)
877 			break;
878 	}
879 }
880 
881 void
882 fprintlog(struct filed *f, int flags, char *msg)
883 {
884 	struct iovec iov[6];
885 	struct iovec *v;
886 	int fd, l, retryonce;
887 	char line[MAXLINE + 1], repbuf[80], greetings[500];
888 
889 	v = iov;
890 	if (f->f_type == F_WALL) {
891 		l = snprintf(greetings, sizeof(greetings),
892 		    "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
893 		    f->f_prevhost, ctime(&now));
894 		if (l < 0 || (size_t)l >= sizeof(greetings))
895 			l = strlen(greetings);
896 		v->iov_base = greetings;
897 		v->iov_len = l;
898 		v++;
899 		v->iov_base = "";
900 		v->iov_len = 0;
901 		v++;
902 	} else {
903 		v->iov_base = f->f_lasttime;
904 		v->iov_len = 15;
905 		v++;
906 		v->iov_base = " ";
907 		v->iov_len = 1;
908 		v++;
909 	}
910 	v->iov_base = f->f_prevhost;
911 	v->iov_len = strlen(v->iov_base);
912 	v++;
913 	v->iov_base = " ";
914 	v->iov_len = 1;
915 	v++;
916 
917 	if (msg) {
918 		v->iov_base = msg;
919 		v->iov_len = strlen(msg);
920 	} else if (f->f_prevcount > 1) {
921 		l = snprintf(repbuf, sizeof(repbuf),
922 		    "last message repeated %d times", f->f_prevcount);
923 		if (l < 0 || (size_t)l >= sizeof(repbuf))
924 			l = strlen(repbuf);
925 		v->iov_base = repbuf;
926 		v->iov_len = l;
927 	} else {
928 		v->iov_base = f->f_prevline;
929 		v->iov_len = f->f_prevlen;
930 	}
931 	v++;
932 
933 	dprintf("Logging to %s", TypeNames[f->f_type]);
934 	f->f_time = now;
935 
936 	switch (f->f_type) {
937 	case F_UNUSED:
938 		dprintf("\n");
939 		break;
940 
941 	case F_FORW:
942 		dprintf(" %s\n", f->f_un.f_forw.f_loghost);
943 		switch (f->f_un.f_forw.f_addr.ss_family) {
944 		case AF_INET:
945 			fd = fd_udp;
946 			break;
947 		case AF_INET6:
948 			fd = fd_udp6;
949 			break;
950 		default:
951 			fd = -1;
952 			break;
953 		}
954 		l = snprintf(line, sizeof(line), "<%d>%.15s %s%s%s",
955 		    f->f_prevpri, (char *)iov[0].iov_base,
956 		    IncludeHostname ? LocalHostName : "",
957 		    IncludeHostname ? " " : "",
958 		    (char *)iov[4].iov_base);
959 		if (l < 0 || (size_t)l >= sizeof(line))
960 			l = strlen(line);
961 		if (sendto(fd, line, l, 0,
962 		    (struct sockaddr *)&f->f_un.f_forw.f_addr,
963 		    f->f_un.f_forw.f_addr.ss_len) != l) {
964 			switch (errno) {
965 			case EHOSTDOWN:
966 			case EHOSTUNREACH:
967 			case ENETDOWN:
968 			case ENETUNREACH:
969 			case ENOBUFS:
970 				/* silently dropped */
971 				break;
972 			default:
973 				f->f_type = F_UNUSED;
974 				logerror("sendto");
975 				break;
976 			}
977 		}
978 		break;
979 
980 	case F_CONSOLE:
981 		if (flags & IGN_CONS) {
982 			dprintf(" (ignored)\n");
983 			break;
984 		}
985 		/* FALLTHROUGH */
986 
987 	case F_TTY:
988 	case F_FILE:
989 	case F_PIPE:
990 		dprintf(" %s\n", f->f_un.f_fname);
991 		if (f->f_type != F_FILE && f->f_type != F_PIPE) {
992 			v->iov_base = "\r\n";
993 			v->iov_len = 2;
994 		} else {
995 			v->iov_base = "\n";
996 			v->iov_len = 1;
997 		}
998 		retryonce = 0;
999 	again:
1000 		if (writev(f->f_file, iov, 6) < 0) {
1001 			int e = errno;
1002 
1003 			/* pipe is non-blocking. log and drop message if full */
1004 			if (e == EAGAIN && f->f_type == F_PIPE) {
1005 				if (now - f->f_lasterrtime > 120) {
1006 					f->f_lasterrtime = now;
1007 					logerror(f->f_un.f_fname);
1008 				}
1009 				break;
1010 			}
1011 
1012 			(void)close(f->f_file);
1013 			/*
1014 			 * Check for errors on TTY's or program pipes.
1015 			 * Errors happen due to loss of tty or died programs.
1016 			 */
1017 			if (e == EAGAIN) {
1018 				/*
1019 				 * Silently drop messages on blocked write.
1020 				 * This can happen when logging to a locked tty.
1021 				 */
1022 				break;
1023 			} else if ((e == EIO || e == EBADF) &&
1024 			    f->f_type != F_FILE && f->f_type != F_PIPE &&
1025 			    !retryonce) {
1026 				f->f_file = priv_open_tty(f->f_un.f_fname);
1027 				retryonce = 1;
1028 				if (f->f_file < 0) {
1029 					f->f_type = F_UNUSED;
1030 					logerror(f->f_un.f_fname);
1031 				} else
1032 					goto again;
1033 			} else if ((e == EPIPE || e == EBADF) &&
1034 			    f->f_type == F_PIPE && !retryonce) {
1035 				f->f_file = priv_open_log(f->f_un.f_fname);
1036 				retryonce = 1;
1037 				if (f->f_file < 0) {
1038 					f->f_type = F_UNUSED;
1039 					logerror(f->f_un.f_fname);
1040 				} else
1041 					goto again;
1042 			} else {
1043 				f->f_type = F_UNUSED;
1044 				f->f_file = -1;
1045 				errno = e;
1046 				logerror(f->f_un.f_fname);
1047 			}
1048 		} else if (flags & SYNC_FILE)
1049 			(void)fsync(f->f_file);
1050 		break;
1051 
1052 	case F_USERS:
1053 	case F_WALL:
1054 		dprintf("\n");
1055 		v->iov_base = "\r\n";
1056 		v->iov_len = 2;
1057 		wallmsg(f, iov);
1058 		break;
1059 
1060 	case F_MEMBUF:
1061 		dprintf("\n");
1062 		snprintf(line, sizeof(line), "%.15s %s %s",
1063 		    (char *)iov[0].iov_base, (char *)iov[2].iov_base,
1064 		    (char *)iov[4].iov_base);
1065 		if (ringbuf_append_line(f->f_un.f_mb.f_rb, line) == 1)
1066 			f->f_un.f_mb.f_overflow = 1;
1067 		if (f->f_un.f_mb.f_attached)
1068 			ctlconn_logto(line);
1069 		break;
1070 	}
1071 	f->f_prevcount = 0;
1072 }
1073 
1074 /*
1075  *  WALLMSG -- Write a message to the world at large
1076  *
1077  *	Write the specified message to either the entire
1078  *	world, or a list of approved users.
1079  */
1080 void
1081 wallmsg(struct filed *f, struct iovec *iov)
1082 {
1083 	struct utmp ut;
1084 	char line[sizeof(ut.ut_line) + 1], *p;
1085 	static int reenter;			/* avoid calling ourselves */
1086 	FILE *uf;
1087 	int i;
1088 
1089 	if (reenter++)
1090 		return;
1091 	if ((uf = priv_open_utmp()) == NULL) {
1092 		logerror(_PATH_UTMP);
1093 		reenter = 0;
1094 		return;
1095 	}
1096 	/* NOSTRICT */
1097 	while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) {
1098 		if (ut.ut_name[0] == '\0')
1099 			continue;
1100 		/* must use strncpy since ut_* may not be NUL terminated */
1101 		strncpy(line, ut.ut_line, sizeof(line) - 1);
1102 		line[sizeof(line) - 1] = '\0';
1103 		if (f->f_type == F_WALL) {
1104 			if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) != NULL) {
1105 				errno = 0;	/* already in msg */
1106 				logerror(p);
1107 			}
1108 			continue;
1109 		}
1110 		/* should we send the message to this user? */
1111 		for (i = 0; i < MAXUNAMES; i++) {
1112 			if (!f->f_un.f_uname[i][0])
1113 				break;
1114 			if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
1115 			    UT_NAMESIZE)) {
1116 				if ((p = ttymsg(iov, 6, line, TTYMSGTIME))
1117 								!= NULL) {
1118 					errno = 0;	/* already in msg */
1119 					logerror(p);
1120 				}
1121 				break;
1122 			}
1123 		}
1124 	}
1125 	(void)fclose(uf);
1126 	reenter = 0;
1127 }
1128 
1129 /*
1130  * Return a printable representation of a host address.
1131  */
1132 void
1133 cvthname(struct sockaddr *f, char *result, size_t res_len)
1134 {
1135 	if (getnameinfo(f, f->sa_len, result, res_len, NULL, 0,
1136 	    NI_NUMERICHOST|NI_NUMERICSERV|NI_DGRAM) != 0) {
1137 		dprintf("Malformed from address\n");
1138 		strlcpy(result, "???", res_len);
1139 		return;
1140 	}
1141 	dprintf("cvthname(%s)\n", result);
1142 	if (NoDNS)
1143 		return;
1144 
1145 	if (priv_getnameinfo(f, f->sa_len, result, res_len) != 0)
1146 		dprintf("Host name for your address (%s) unknown\n", result);
1147 }
1148 
1149 void
1150 die_signalcb(int signum, short event, void *arg)
1151 {
1152 	die(signum);
1153 }
1154 
1155 void
1156 mark_timercb(int unused, short event, void *arg)
1157 {
1158 	markit();
1159 }
1160 
1161 void
1162 init_signalcb(int signum, short event, void *arg)
1163 {
1164 	init();
1165 
1166 	logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart",
1167 	    LocalHostName, ADDDATE);
1168 	dprintf("syslogd: restarted\n");
1169 }
1170 
1171 /*
1172  * Print syslogd errors some place.
1173  */
1174 void
1175 logerror(const char *type)
1176 {
1177 	char buf[100];
1178 
1179 	if (errno)
1180 		(void)snprintf(buf, sizeof(buf), "syslogd: %s: %s",
1181 		    type, strerror(errno));
1182 	else
1183 		(void)snprintf(buf, sizeof(buf), "syslogd: %s", type);
1184 	errno = 0;
1185 	dprintf("%s\n", buf);
1186 	if (Startup)
1187 		fprintf(stderr, "%s\n", buf);
1188 	else
1189 		logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
1190 }
1191 
1192 void
1193 die(int signo)
1194 {
1195 	struct filed *f;
1196 	int was_initialized = Initialized;
1197 	char buf[100];
1198 
1199 	Initialized = 0;		/* Don't log SIGCHLDs */
1200 	for (f = Files; f != NULL; f = f->f_next) {
1201 		/* flush any pending output */
1202 		if (f->f_prevcount)
1203 			fprintlog(f, 0, (char *)NULL);
1204 	}
1205 	Initialized = was_initialized;
1206 	if (signo) {
1207 		dprintf("syslogd: exiting on signal %d\n", signo);
1208 		(void)snprintf(buf, sizeof buf, "exiting on signal %d", signo);
1209 		errno = 0;
1210 		logerror(buf);
1211 	}
1212 	dprintf("[unpriv] syslogd child about to exit\n");
1213 	exit(0);
1214 }
1215 
1216 /*
1217  *  INIT -- Initialize syslogd from configuration table
1218  */
1219 void
1220 init(void)
1221 {
1222 	char cline[LINE_MAX], prog[NAME_MAX+1], *p;
1223 	struct filed *f, *next, **nextp, *mb, *m;
1224 	FILE *cf;
1225 	int i;
1226 
1227 	dprintf("init\n");
1228 
1229 	/* If config file has been modified, then just die to restart */
1230 	if (priv_config_modified()) {
1231 		dprintf("config file changed: dying\n");
1232 		die(0);
1233 	}
1234 
1235 	/*
1236 	 *  Close all open log files.
1237 	 */
1238 	Initialized = 0;
1239 	mb = NULL;
1240 	for (f = Files; f != NULL; f = next) {
1241 		/* flush any pending output */
1242 		if (f->f_prevcount)
1243 			fprintlog(f, 0, (char *)NULL);
1244 
1245 		switch (f->f_type) {
1246 		case F_FILE:
1247 		case F_TTY:
1248 		case F_CONSOLE:
1249 		case F_PIPE:
1250 			(void)close(f->f_file);
1251 			break;
1252 		case F_FORW:
1253 			break;
1254 		}
1255 		next = f->f_next;
1256 		if (f->f_program)
1257 			free(f->f_program);
1258 		if (f->f_type == F_MEMBUF) {
1259 			f->f_next = mb;
1260 			f->f_program = NULL;
1261 			dprintf("add %p to mb: %p\n", f, mb);
1262 			mb = f;
1263 		} else
1264 			free((char *)f);
1265 	}
1266 	Files = NULL;
1267 	nextp = &Files;
1268 
1269 	/* open the configuration file */
1270 	if ((cf = priv_open_config()) == NULL) {
1271 		dprintf("cannot open %s\n", ConfFile);
1272 		*nextp = cfline("*.ERR\t/dev/console", "*");
1273 		(*nextp)->f_next = cfline("*.PANIC\t*", "*");
1274 		Initialized = 1;
1275 		return;
1276 	}
1277 
1278 	/*
1279 	 *  Foreach line in the conf table, open that file.
1280 	 */
1281 	f = NULL;
1282 	strlcpy(prog, "*", sizeof(prog));
1283 	while (fgets(cline, sizeof(cline), cf) != NULL) {
1284 		/*
1285 		 * check for end-of-section, comments, strip off trailing
1286 		 * spaces and newline character. !prog is treated
1287 		 * specially: the following lines apply only to that program.
1288 		 */
1289 		for (p = cline; isspace((unsigned char)*p); ++p)
1290 			continue;
1291 		if (*p == '\0' || *p == '#')
1292 			continue;
1293 		if (*p == '!') {
1294 			p++;
1295 			while (isspace((unsigned char)*p))
1296 				p++;
1297 			if (!*p || (*p == '*' && (!p[1] ||
1298 			    isspace((unsigned char)p[1])))) {
1299 				strlcpy(prog, "*", sizeof(prog));
1300 				continue;
1301 			}
1302 			for (i = 0; i < NAME_MAX; i++) {
1303 				if (!isalnum((unsigned char)p[i]) &&
1304 				    p[i] != '-' && p[i] != '!')
1305 					break;
1306 				prog[i] = p[i];
1307 			}
1308 			prog[i] = 0;
1309 			continue;
1310 		}
1311 		p = cline + strlen(cline);
1312 		while (p > cline)
1313 			if (!isspace((unsigned char)*--p)) {
1314 				p++;
1315 				break;
1316 			}
1317 		*p = '\0';
1318 		f = cfline(cline, prog);
1319 		if (f != NULL) {
1320 			*nextp = f;
1321 			nextp = &f->f_next;
1322 		}
1323 	}
1324 
1325 	/* Match and initialize the memory buffers */
1326 	for (f = Files; f != NULL; f = f->f_next) {
1327 		if (f->f_type != F_MEMBUF)
1328 			continue;
1329 		dprintf("Initialize membuf %s at %p\n", f->f_un.f_mb.f_mname, f);
1330 
1331 		for (m = mb; m != NULL; m = m->f_next) {
1332 			if (m->f_un.f_mb.f_rb == NULL)
1333 				continue;
1334 			if (strcmp(m->f_un.f_mb.f_mname,
1335 			    f->f_un.f_mb.f_mname) == 0)
1336 				break;
1337 		}
1338 		if (m == NULL) {
1339 			dprintf("Membuf no match\n");
1340 			f->f_un.f_mb.f_rb = ringbuf_init(f->f_un.f_mb.f_len);
1341 			if (f->f_un.f_mb.f_rb == NULL) {
1342 				f->f_type = F_UNUSED;
1343 				logerror("Failed to allocate membuf");
1344 			}
1345 		} else {
1346 			dprintf("Membuf match f:%p, m:%p\n", f, m);
1347 			f->f_un = m->f_un;
1348 			m->f_un.f_mb.f_rb = NULL;
1349 		}
1350 	}
1351 
1352 	/* make sure remaining buffers are freed */
1353 	while (mb != NULL) {
1354 		m = mb;
1355 		if (m->f_un.f_mb.f_rb != NULL) {
1356 			logerror("Mismatched membuf");
1357 			ringbuf_free(m->f_un.f_mb.f_rb);
1358 		}
1359 		dprintf("Freeing membuf %p\n", m);
1360 
1361 		mb = m->f_next;
1362 		free(m);
1363 	}
1364 
1365 	/* close the configuration file */
1366 	(void)fclose(cf);
1367 
1368 	Initialized = 1;
1369 
1370 	if (Debug) {
1371 		for (f = Files; f; f = f->f_next) {
1372 			for (i = 0; i <= LOG_NFACILITIES; i++)
1373 				if (f->f_pmask[i] == INTERNAL_NOPRI)
1374 					printf("X ");
1375 				else
1376 					printf("%d ", f->f_pmask[i]);
1377 			printf("%s: ", TypeNames[f->f_type]);
1378 			switch (f->f_type) {
1379 			case F_FILE:
1380 			case F_TTY:
1381 			case F_CONSOLE:
1382 			case F_PIPE:
1383 				printf("%s", f->f_un.f_fname);
1384 				break;
1385 
1386 			case F_FORW:
1387 				printf("%s", f->f_un.f_forw.f_loghost);
1388 				break;
1389 
1390 			case F_USERS:
1391 				for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
1392 					printf("%s, ", f->f_un.f_uname[i]);
1393 				break;
1394 
1395 			case F_MEMBUF:
1396 				printf("%s", f->f_un.f_mb.f_mname);
1397 				break;
1398 
1399 			}
1400 			if (f->f_program)
1401 				printf(" (%s)", f->f_program);
1402 			printf("\n");
1403 		}
1404 	}
1405 }
1406 
1407 #define progmatches(p1, p2) \
1408 	(p1 == p2 || (p1 != NULL && p2 != NULL && strcmp(p1, p2) == 0))
1409 
1410 /*
1411  * Spot a line with a duplicate file, pipe, console, tty, or membuf target.
1412  */
1413 struct filed *
1414 find_dup(struct filed *f)
1415 {
1416 	struct filed *list;
1417 
1418 	for (list = Files; list; list = list->f_next) {
1419 		if (list->f_quick || f->f_quick)
1420 			continue;
1421 		switch (list->f_type) {
1422 		case F_FILE:
1423 		case F_TTY:
1424 		case F_CONSOLE:
1425 		case F_PIPE:
1426 			if (strcmp(list->f_un.f_fname, f->f_un.f_fname) == 0 &&
1427 			    progmatches(list->f_program, f->f_program))
1428 				return (list);
1429 			break;
1430 		case F_MEMBUF:
1431 			if (strcmp(list->f_un.f_mb.f_mname,
1432 			    f->f_un.f_mb.f_mname) == 0 &&
1433 			    progmatches(list->f_program, f->f_program))
1434 				return (list);
1435 			break;
1436 		}
1437 	}
1438 	return (NULL);
1439 }
1440 
1441 /*
1442  * Crack a configuration file line
1443  */
1444 struct filed *
1445 cfline(char *line, char *prog)
1446 {
1447 	int i, pri;
1448 	size_t rb_len;
1449 	char *bp, *p, *q, *proto, *host, *port;
1450 	char buf[MAXLINE], ebuf[100];
1451 	struct filed *xf, *f, *d;
1452 
1453 	dprintf("cfline(\"%s\", f, \"%s\")\n", line, prog);
1454 
1455 	errno = 0;	/* keep strerror() stuff out of logerror messages */
1456 
1457 	if ((f = calloc(1, sizeof(*f))) == NULL) {
1458 		logerror("Couldn't allocate struct filed");
1459 		die(0);
1460 	}
1461 	for (i = 0; i <= LOG_NFACILITIES; i++)
1462 		f->f_pmask[i] = INTERNAL_NOPRI;
1463 
1464 	/* save program name if any */
1465 	if (*prog == '!') {
1466 		f->f_quick = 1;
1467 		prog++;
1468 	} else
1469 		f->f_quick = 0;
1470 	if (!strcmp(prog, "*"))
1471 		prog = NULL;
1472 	else
1473 		f->f_program = strdup(prog);
1474 
1475 	/* scan through the list of selectors */
1476 	for (p = line; *p && *p != '\t';) {
1477 
1478 		/* find the end of this facility name list */
1479 		for (q = p; *q && *q != '\t' && *q++ != '.'; )
1480 			continue;
1481 
1482 		/* collect priority name */
1483 		for (bp = buf; *q && !strchr("\t,;", *q); )
1484 			*bp++ = *q++;
1485 		*bp = '\0';
1486 
1487 		/* skip cruft */
1488 		while (*q && strchr(", ;", *q))
1489 			q++;
1490 
1491 		/* decode priority name */
1492 		if (*buf == '*')
1493 			pri = LOG_PRIMASK + 1;
1494 		else {
1495 			/* ignore trailing spaces */
1496 			for (i=strlen(buf)-1; i >= 0 && buf[i] == ' '; i--) {
1497 				buf[i]='\0';
1498 			}
1499 
1500 			pri = decode(buf, prioritynames);
1501 			if (pri < 0) {
1502 				(void)snprintf(ebuf, sizeof ebuf,
1503 				    "unknown priority name \"%s\"", buf);
1504 				logerror(ebuf);
1505 				free(f);
1506 				return (NULL);
1507 			}
1508 		}
1509 
1510 		/* scan facilities */
1511 		while (*p && !strchr("\t.;", *p)) {
1512 			for (bp = buf; *p && !strchr("\t,;.", *p); )
1513 				*bp++ = *p++;
1514 			*bp = '\0';
1515 			if (*buf == '*')
1516 				for (i = 0; i < LOG_NFACILITIES; i++)
1517 					f->f_pmask[i] = pri;
1518 			else {
1519 				i = decode(buf, facilitynames);
1520 				if (i < 0) {
1521 					(void)snprintf(ebuf, sizeof(ebuf),
1522 					    "unknown facility name \"%s\"",
1523 					    buf);
1524 					logerror(ebuf);
1525 					free(f);
1526 					return (NULL);
1527 				}
1528 				f->f_pmask[i >> 3] = pri;
1529 			}
1530 			while (*p == ',' || *p == ' ')
1531 				p++;
1532 		}
1533 
1534 		p = q;
1535 	}
1536 
1537 	/* skip to action part */
1538 	while (*p == '\t')
1539 		p++;
1540 
1541 	switch (*p) {
1542 	case '@':
1543 		if ((strlcpy(f->f_un.f_forw.f_loghost, p,
1544 		    sizeof(f->f_un.f_forw.f_loghost)) >=
1545 		    sizeof(f->f_un.f_forw.f_loghost))) {
1546 			snprintf(ebuf, sizeof(ebuf), "loghost too long \"%s\"",
1547 			    p);
1548 			logerror(ebuf);
1549 			break;
1550 		}
1551 		if (loghost(++p, &proto, &host, &port) == -1) {
1552 			snprintf(ebuf, sizeof(ebuf), "bad loghost \"%s\"",
1553 			    f->f_un.f_forw.f_loghost);
1554 			logerror(ebuf);
1555 			break;
1556 		}
1557 		if (proto == NULL)
1558 			proto = "udp";
1559 		if (strcmp(proto, "udp") == 0) {
1560 			if (fd_udp == -1)
1561 				proto = "udp6";
1562 			if (fd_udp6 == -1)
1563 				proto = "udp4";
1564 		} else if (strcmp(proto, "udp4") == 0) {
1565 			if (fd_udp == -1) {
1566 				snprintf(ebuf, sizeof(ebuf), "no udp4 \"%s\"",
1567 				    f->f_un.f_forw.f_loghost);
1568 				logerror(ebuf);
1569 				break;
1570 			}
1571 		} else if (strcmp(proto, "udp6") == 0) {
1572 			if (fd_udp6 == -1) {
1573 				snprintf(ebuf, sizeof(ebuf), "no udp6 \"%s\"",
1574 				    f->f_un.f_forw.f_loghost);
1575 				logerror(ebuf);
1576 				break;
1577 			}
1578 		} else {
1579 			snprintf(ebuf, sizeof(ebuf), "bad protocol \"%s\"",
1580 			    f->f_un.f_forw.f_loghost);
1581 			logerror(ebuf);
1582 			break;
1583 		}
1584 		if (strlen(host) >= MAXHOSTNAMELEN) {
1585 			snprintf(ebuf, sizeof(ebuf), "host too long \"%s\"",
1586 			    f->f_un.f_forw.f_loghost);
1587 			logerror(ebuf);
1588 			break;
1589 		}
1590 		if (port == NULL)
1591 			port = "syslog";
1592 		if (strlen(port) >= NI_MAXSERV) {
1593 			snprintf(ebuf, sizeof(ebuf), "port too long \"%s\"",
1594 			    f->f_un.f_forw.f_loghost);
1595 			logerror(ebuf);
1596 			break;
1597 		}
1598 		if (priv_getaddrinfo(proto, host, port,
1599 		    (struct sockaddr*)&f->f_un.f_forw.f_addr,
1600 		    sizeof(f->f_un.f_forw.f_addr)) != 0) {
1601 			snprintf(ebuf, sizeof(ebuf), "bad hostname \"%s\"",
1602 			    f->f_un.f_forw.f_loghost);
1603 			logerror(ebuf);
1604 			break;
1605 		}
1606 		f->f_type = F_FORW;
1607 		break;
1608 
1609 	case '/':
1610 	case '|':
1611 		(void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname));
1612 		d = find_dup(f);
1613 		if (d != NULL) {
1614 			for (i = 0; i <= LOG_NFACILITIES; i++)
1615 				if (f->f_pmask[i] != INTERNAL_NOPRI)
1616 					d->f_pmask[i] = f->f_pmask[i];
1617 			free(f);
1618 			return (NULL);
1619 		}
1620 		if (strcmp(p, ctty) == 0)
1621 			f->f_file = priv_open_tty(p);
1622 		else
1623 			f->f_file = priv_open_log(p);
1624 		if (f->f_file < 0) {
1625 			f->f_type = F_UNUSED;
1626 			logerror(p);
1627 			break;
1628 		}
1629 		if (isatty(f->f_file)) {
1630 			if (strcmp(p, ctty) == 0)
1631 				f->f_type = F_CONSOLE;
1632 			else
1633 				f->f_type = F_TTY;
1634 		} else {
1635 			if (*p == '|')
1636 				f->f_type = F_PIPE;
1637 			else {
1638 				f->f_type = F_FILE;
1639 
1640 				/* Clear O_NONBLOCK flag on f->f_file */
1641 				if ((i = fcntl(f->f_file, F_GETFL, 0)) != -1) {
1642 					i &= ~O_NONBLOCK;
1643 					fcntl(f->f_file, F_SETFL, i);
1644 				}
1645 			}
1646 		}
1647 		break;
1648 
1649 	case '*':
1650 		f->f_type = F_WALL;
1651 		break;
1652 
1653 	case ':':
1654 		f->f_type = F_MEMBUF;
1655 
1656 		/* Parse buffer size (in kb) */
1657 		errno = 0;
1658 		rb_len = strtoul(++p, &q, 0);
1659 		if (*p == '\0' || (errno == ERANGE && rb_len == ULONG_MAX) ||
1660 		    *q != ':' || rb_len == 0) {
1661 			f->f_type = F_UNUSED;
1662 			logerror(p);
1663 			break;
1664 		}
1665 		q++;
1666 		rb_len *= 1024;
1667 
1668 		/* Copy buffer name */
1669 		for(i = 0; (size_t)i < sizeof(f->f_un.f_mb.f_mname) - 1; i++) {
1670 			if (!isalnum((unsigned char)q[i]))
1671 				break;
1672 			f->f_un.f_mb.f_mname[i] = q[i];
1673 		}
1674 
1675 		/* Make sure buffer name is unique */
1676 		xf = find_dup(f);
1677 
1678 		/* Error on missing or non-unique name, or bad buffer length */
1679 		if (i == 0 || rb_len > MAX_MEMBUF || xf != NULL) {
1680 			f->f_type = F_UNUSED;
1681 			logerror(p);
1682 			break;
1683 		}
1684 
1685 		/* Set buffer length */
1686 		rb_len = MAX(rb_len, MIN_MEMBUF);
1687 		f->f_un.f_mb.f_len = rb_len;
1688 		f->f_un.f_mb.f_overflow = 0;
1689 		f->f_un.f_mb.f_attached = 0;
1690 		break;
1691 
1692 	default:
1693 		for (i = 0; i < MAXUNAMES && *p; i++) {
1694 			for (q = p; *q && *q != ','; )
1695 				q++;
1696 			(void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
1697 			if ((q - p) > UT_NAMESIZE)
1698 				f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
1699 			else
1700 				f->f_un.f_uname[i][q - p] = '\0';
1701 			while (*q == ',' || *q == ' ')
1702 				q++;
1703 			p = q;
1704 		}
1705 		f->f_type = F_USERS;
1706 		break;
1707 	}
1708 	return (f);
1709 }
1710 
1711 /*
1712  * Parse the host and port parts from a loghost string.
1713  */
1714 int
1715 loghost(char *str, char **proto, char **host, char **port)
1716 {
1717 	*proto = NULL;
1718 	if ((*host = strchr(str, ':')) &&
1719 	    (*host)[1] == '/' && (*host)[2] == '/') {
1720 		*proto = str;
1721 		**host = '\0';
1722 		str = *host + 3;
1723 	}
1724 	*host = str;
1725 	if (**host == '[') {
1726 		(*host)++;
1727 		str = strchr(*host, ']');
1728 		if (str == NULL)
1729 			return (-1);
1730 		*str++ = '\0';
1731 	}
1732 	*port = strrchr(str, ':');
1733 	if (*port != NULL)
1734 		*(*port)++ = '\0';
1735 
1736 	return (0);
1737 }
1738 
1739 /*
1740  * Retrieve the size of the kernel message buffer, via sysctl.
1741  */
1742 int
1743 getmsgbufsize(void)
1744 {
1745 	int msgbufsize, mib[2];
1746 	size_t size;
1747 
1748 	mib[0] = CTL_KERN;
1749 	mib[1] = KERN_MSGBUFSIZE;
1750 	size = sizeof msgbufsize;
1751 	if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) {
1752 		dprintf("couldn't get kern.msgbufsize\n");
1753 		return (0);
1754 	}
1755 	return (msgbufsize);
1756 }
1757 
1758 /*
1759  *  Decode a symbolic name to a numeric value
1760  */
1761 int
1762 decode(const char *name, const CODE *codetab)
1763 {
1764 	const CODE *c;
1765 	char *p, buf[40];
1766 
1767 	if (isdigit((unsigned char)*name))
1768 		return (atoi(name));
1769 
1770 	for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
1771 		if (isupper((unsigned char)*name))
1772 			*p = tolower((unsigned char)*name);
1773 		else
1774 			*p = *name;
1775 	}
1776 	*p = '\0';
1777 	for (c = codetab; c->c_name; c++)
1778 		if (!strcmp(buf, c->c_name))
1779 			return (c->c_val);
1780 
1781 	return (-1);
1782 }
1783 
1784 void
1785 markit(void)
1786 {
1787 	struct filed *f;
1788 
1789 	now = time(NULL);
1790 	MarkSeq += TIMERINTVL;
1791 	if (MarkSeq >= MarkInterval) {
1792 		logmsg(LOG_INFO, "-- MARK --",
1793 		    LocalHostName, ADDDATE|MARK);
1794 		MarkSeq = 0;
1795 	}
1796 
1797 	for (f = Files; f; f = f->f_next) {
1798 		if (f->f_prevcount && now >= REPEATTIME(f)) {
1799 			dprintf("flush %s: repeated %d times, %d sec.\n",
1800 			    TypeNames[f->f_type], f->f_prevcount,
1801 			    repeatinterval[f->f_repeatcount]);
1802 			fprintlog(f, 0, (char *)NULL);
1803 			BACKOFF(f);
1804 		}
1805 	}
1806 }
1807 
1808 int
1809 unix_socket(char *path, int type, mode_t mode)
1810 {
1811 	struct sockaddr_un s_un;
1812 	char errbuf[512];
1813 	int fd;
1814 	mode_t old_umask;
1815 
1816 	memset(&s_un, 0, sizeof(s_un));
1817 	s_un.sun_family = AF_UNIX;
1818 	if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) >=
1819 	    sizeof(s_un.sun_path)) {
1820 		snprintf(errbuf, sizeof(errbuf), "socket path too long: %s",
1821 		    path);
1822 		logerror(errbuf);
1823 		die(0);
1824 	}
1825 
1826 	if ((fd = socket(AF_UNIX, type, 0)) == -1) {
1827 		logerror("socket");
1828 		return (-1);
1829 	}
1830 
1831 	if (Debug) {
1832 		if (connect(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == 0 ||
1833 		    errno == EPROTOTYPE) {
1834 			close(fd);
1835 			errno = EISCONN;
1836 			logerror("connect");
1837 			return (-1);
1838 		}
1839 	}
1840 
1841 	old_umask = umask(0177);
1842 
1843 	unlink(path);
1844 	if (bind(fd, (struct sockaddr *)&s_un, SUN_LEN(&s_un)) == -1) {
1845 		snprintf(errbuf, sizeof(errbuf), "cannot bind %s", path);
1846 		logerror(errbuf);
1847 		umask(old_umask);
1848 		close(fd);
1849 		return (-1);
1850 	}
1851 
1852 	umask(old_umask);
1853 
1854 	if (chmod(path, mode) == -1) {
1855 		snprintf(errbuf, sizeof(errbuf), "cannot chmod %s", path);
1856 		logerror(errbuf);
1857 		close(fd);
1858 		unlink(path);
1859 		return (-1);
1860 	}
1861 
1862 	return (fd);
1863 }
1864 
1865 void
1866 double_rbuf(int fd)
1867 {
1868 	socklen_t slen, len;
1869 
1870 	slen = sizeof(len);
1871 	if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &slen) == 0) {
1872 		len *= 2;
1873 		setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, slen);
1874 	}
1875 }
1876 
1877 void
1878 ctlconn_cleanup(void)
1879 {
1880 	struct filed *f;
1881 
1882 	if (close(fd_ctlconn) == -1)
1883 		logerror("close ctlconn");
1884 	fd_ctlconn = -1;
1885 	event_del(&ev_ctlread);
1886 	event_del(&ev_ctlwrite);
1887 	event_add(&ev_ctlaccept, NULL);
1888 
1889 	if (ctl_state == CTL_WRITING_CONT_REPLY)
1890 		for (f = Files; f != NULL; f = f->f_next)
1891 			if (f->f_type == F_MEMBUF)
1892 				f->f_un.f_mb.f_attached = 0;
1893 
1894 	ctl_state = ctl_cmd_bytes = ctl_reply_offset = ctl_reply_size = 0;
1895 }
1896 
1897 void
1898 ctlsock_acceptcb(int fd, short event, void *arg)
1899 {
1900 	struct event		*ev = arg;
1901 	int			 flags;
1902 
1903 	dprintf("Accepting control connection\n");
1904 	fd = accept(fd, NULL, NULL);
1905 	if (fd == -1) {
1906 		if (errno != EINTR && errno != EWOULDBLOCK &&
1907 		    errno != ECONNABORTED)
1908 			logerror("accept ctlsock");
1909 		return;
1910 	}
1911 
1912 	if (fd_ctlconn != -1)
1913 		ctlconn_cleanup();
1914 
1915 	/* Only one connection at a time */
1916 	event_del(ev);
1917 
1918 	if ((flags = fcntl(fd, F_GETFL)) == -1 ||
1919 	    fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
1920 		logerror("fcntl ctlconn");
1921 		close(fd);
1922 		return;
1923 	}
1924 
1925 	fd_ctlconn = fd;
1926 	/* file descriptor has changed, reset event */
1927 	event_set(&ev_ctlread, fd_ctlconn, EV_READ|EV_PERSIST,
1928 	    ctlconn_readcb, &ev_ctlread);
1929 	event_set(&ev_ctlwrite, fd_ctlconn, EV_WRITE|EV_PERSIST,
1930 	    ctlconn_writecb, &ev_ctlwrite);
1931 	event_add(&ev_ctlread, NULL);
1932 	ctl_state = CTL_READING_CMD;
1933 	ctl_cmd_bytes = 0;
1934 }
1935 
1936 static struct filed
1937 *find_membuf_log(const char *name)
1938 {
1939 	struct filed *f;
1940 
1941 	for (f = Files; f != NULL; f = f->f_next) {
1942 		if (f->f_type == F_MEMBUF &&
1943 		    strcmp(f->f_un.f_mb.f_mname, name) == 0)
1944 			break;
1945 	}
1946 	return (f);
1947 }
1948 
1949 void
1950 ctlconn_readcb(int fd, short event, void *arg)
1951 {
1952 	struct filed		*f;
1953 	struct ctl_reply_hdr	*reply_hdr = (struct ctl_reply_hdr *)ctl_reply;
1954 	ssize_t			 n;
1955 	u_int32_t		 flags = 0;
1956 
1957 	if (ctl_state == CTL_WRITING_REPLY ||
1958 	    ctl_state == CTL_WRITING_CONT_REPLY) {
1959 		/* client has closed the connection */
1960 		ctlconn_cleanup();
1961 		return;
1962 	}
1963 
1964  retry:
1965 	n = read(fd, (char*)&ctl_cmd + ctl_cmd_bytes,
1966 	    sizeof(ctl_cmd) - ctl_cmd_bytes);
1967 	switch (n) {
1968 	case -1:
1969 		if (errno == EINTR)
1970 			goto retry;
1971 		logerror("ctlconn read");
1972 		/* FALLTHROUGH */
1973 	case 0:
1974 		ctlconn_cleanup();
1975 		return;
1976 	default:
1977 		ctl_cmd_bytes += n;
1978 	}
1979 	if (ctl_cmd_bytes < sizeof(ctl_cmd))
1980 		return;
1981 
1982 	if (ntohl(ctl_cmd.version) != CTL_VERSION) {
1983 		logerror("Unknown client protocol version");
1984 		ctlconn_cleanup();
1985 		return;
1986 	}
1987 
1988 	/* Ensure that logname is \0 terminated */
1989 	if (memchr(ctl_cmd.logname, '\0', sizeof(ctl_cmd.logname)) == NULL) {
1990 		logerror("Corrupt ctlsock command");
1991 		ctlconn_cleanup();
1992 		return;
1993 	}
1994 
1995 	*reply_text = '\0';
1996 
1997 	ctl_reply_size = ctl_reply_offset = 0;
1998 	memset(reply_hdr, '\0', sizeof(*reply_hdr));
1999 
2000 	ctl_cmd.cmd = ntohl(ctl_cmd.cmd);
2001 	dprintf("ctlcmd %x logname \"%s\"\n", ctl_cmd.cmd, ctl_cmd.logname);
2002 
2003 	switch (ctl_cmd.cmd) {
2004 	case CMD_READ:
2005 	case CMD_READ_CLEAR:
2006 	case CMD_READ_CONT:
2007 	case CMD_FLAGS:
2008 		f = find_membuf_log(ctl_cmd.logname);
2009 		if (f == NULL) {
2010 			strlcpy(reply_text, "No such log\n", MAX_MEMBUF);
2011 		} else {
2012 			if (ctl_cmd.cmd != CMD_FLAGS) {
2013 				ringbuf_to_string(reply_text, MAX_MEMBUF,
2014 				    f->f_un.f_mb.f_rb);
2015 			}
2016 			if (f->f_un.f_mb.f_overflow)
2017 				flags |= CTL_HDR_FLAG_OVERFLOW;
2018 			if (ctl_cmd.cmd == CMD_READ_CLEAR) {
2019 				ringbuf_clear(f->f_un.f_mb.f_rb);
2020 				f->f_un.f_mb.f_overflow = 0;
2021 			}
2022 			if (ctl_cmd.cmd == CMD_READ_CONT) {
2023 				f->f_un.f_mb.f_attached = 1;
2024 				tailify_replytext(reply_text,
2025 				    ctl_cmd.lines > 0 ? ctl_cmd.lines : 10);
2026 			} else if (ctl_cmd.lines > 0) {
2027 				tailify_replytext(reply_text, ctl_cmd.lines);
2028 			}
2029 		}
2030 		break;
2031 	case CMD_CLEAR:
2032 		f = find_membuf_log(ctl_cmd.logname);
2033 		if (f == NULL) {
2034 			strlcpy(reply_text, "No such log\n", MAX_MEMBUF);
2035 		} else {
2036 			ringbuf_clear(f->f_un.f_mb.f_rb);
2037 			if (f->f_un.f_mb.f_overflow)
2038 				flags |= CTL_HDR_FLAG_OVERFLOW;
2039 			f->f_un.f_mb.f_overflow = 0;
2040 			strlcpy(reply_text, "Log cleared\n", MAX_MEMBUF);
2041 		}
2042 		break;
2043 	case CMD_LIST:
2044 		for (f = Files; f != NULL; f = f->f_next) {
2045 			if (f->f_type == F_MEMBUF) {
2046 				strlcat(reply_text, f->f_un.f_mb.f_mname,
2047 				    MAX_MEMBUF);
2048 				if (f->f_un.f_mb.f_overflow) {
2049 					strlcat(reply_text, "*", MAX_MEMBUF);
2050 					flags |= CTL_HDR_FLAG_OVERFLOW;
2051 				}
2052 				strlcat(reply_text, " ", MAX_MEMBUF);
2053 			}
2054 		}
2055 		strlcat(reply_text, "\n", MAX_MEMBUF);
2056 		break;
2057 	default:
2058 		logerror("Unsupported ctlsock command");
2059 		ctlconn_cleanup();
2060 		return;
2061 	}
2062 	reply_hdr->version = htonl(CTL_VERSION);
2063 	reply_hdr->flags = htonl(flags);
2064 
2065 	ctl_reply_size = CTL_REPLY_SIZE;
2066 	dprintf("ctlcmd reply length %lu\n", (u_long)ctl_reply_size);
2067 
2068 	/* Otherwise, set up to write out reply */
2069 	ctl_state = (ctl_cmd.cmd == CMD_READ_CONT) ?
2070 	    CTL_WRITING_CONT_REPLY : CTL_WRITING_REPLY;
2071 
2072 	event_add(&ev_ctlwrite, NULL);
2073 
2074 	/* another syslogc can kick us out */
2075 	if (ctl_state == CTL_WRITING_CONT_REPLY)
2076 		event_add(&ev_ctlaccept, NULL);
2077 }
2078 
2079 void
2080 ctlconn_writecb(int fd, short event, void *arg)
2081 {
2082 	struct event		*ev = arg;
2083 	ssize_t			 n;
2084 
2085 	if (!(ctl_state == CTL_WRITING_REPLY ||
2086 	    ctl_state == CTL_WRITING_CONT_REPLY)) {
2087 		/* Shouldn't be here! */
2088 		logerror("ctlconn_write with bad ctl_state");
2089 		ctlconn_cleanup();
2090 		return;
2091 	}
2092 
2093  retry:
2094 	n = write(fd, ctl_reply + ctl_reply_offset,
2095 	    ctl_reply_size - ctl_reply_offset);
2096 	switch (n) {
2097 	case -1:
2098 		if (errno == EINTR)
2099 			goto retry;
2100 		if (errno != EPIPE)
2101 			logerror("ctlconn write");
2102 		/* FALLTHROUGH */
2103 	case 0:
2104 		ctlconn_cleanup();
2105 		return;
2106 	default:
2107 		ctl_reply_offset += n;
2108 	}
2109 	if (ctl_reply_offset < ctl_reply_size)
2110 		return;
2111 
2112 	if (ctl_state != CTL_WRITING_CONT_REPLY) {
2113 		ctlconn_cleanup();
2114 		return;
2115 	}
2116 
2117 	/*
2118 	 * Make space in the buffer for continous writes.
2119 	 * Set offset behind reply header to skip it
2120 	 */
2121 	*reply_text = '\0';
2122 	ctl_reply_offset = ctl_reply_size = CTL_REPLY_SIZE;
2123 
2124 	/* Now is a good time to report dropped lines */
2125 	if (membuf_drop) {
2126 		strlcat(reply_text, "<ENOBUFS>\n", MAX_MEMBUF);
2127 		ctl_reply_size = CTL_REPLY_SIZE;
2128 		membuf_drop = 0;
2129 	} else {
2130 		/* Nothing left to write */
2131 		event_del(ev);
2132 	}
2133 }
2134 
2135 /* Shorten replytext to number of lines */
2136 void
2137 tailify_replytext(char *replytext, int lines)
2138 {
2139 	char *start, *nl;
2140 	int count = 0;
2141 	start = nl = replytext;
2142 
2143 	while ((nl = strchr(nl, '\n')) != NULL) {
2144 		nl++;
2145 		if (++count > lines) {
2146 			start = strchr(start, '\n');
2147 			start++;
2148 		}
2149 	}
2150 	if (start != replytext) {
2151 		int len = strlen(start);
2152 		memmove(replytext, start, len);
2153 		*(replytext + len) = '\0';
2154 	}
2155 }
2156 
2157 void
2158 ctlconn_logto(char *line)
2159 {
2160 	size_t l;
2161 
2162 	if (membuf_drop)
2163 		return;
2164 
2165 	l = strlen(line);
2166 	if (l + 2 > (CTL_REPLY_MAXSIZE - ctl_reply_size)) {
2167 		/* remember line drops for later report */
2168 		membuf_drop = 1;
2169 		return;
2170 	}
2171 	memcpy(ctl_reply + ctl_reply_size, line, l);
2172 	memcpy(ctl_reply + ctl_reply_size + l, "\n", 2);
2173 	ctl_reply_size += l + 1;
2174 	event_add(&ev_ctlwrite, NULL);
2175 }
2176