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