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