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