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