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