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