1 /* $OpenBSD: syslogd.c,v 1.102 2008/09/29 18:42:54 deraadt 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 #ifndef lint 33 static const char copyright[] = 34 "@(#) 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 const char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94"; 41 #else 42 static const char rcsid[] = "$OpenBSD: syslogd.c,v 1.102 2008/09/29 18:42:54 deraadt 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 maximum 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 * memory buffer logging by Damien Miller 67 */ 68 69 #define MAXLINE 1024 /* maximum line length */ 70 #define MIN_MEMBUF (MAXLINE * 4) /* Minimum memory buffer size */ 71 #define MAX_MEMBUF (256 * 1024) /* Maximum memory buffer size */ 72 #define MAX_MEMBUF_NAME 64 /* Max length of membuf log name */ 73 #define MAXSVLINE 120 /* maximum saved line length */ 74 #define DEFUPRI (LOG_USER|LOG_NOTICE) 75 #define DEFSPRI (LOG_KERN|LOG_CRIT) 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/ioctl.h> 81 #include <sys/stat.h> 82 #include <sys/wait.h> 83 #include <sys/socket.h> 84 #include <sys/msgbuf.h> 85 #include <sys/uio.h> 86 #include <sys/sysctl.h> 87 #include <sys/un.h> 88 #include <sys/time.h> 89 #include <sys/resource.h> 90 91 #include <netinet/in.h> 92 #include <netdb.h> 93 #include <arpa/inet.h> 94 95 #include <ctype.h> 96 #include <errno.h> 97 #include <err.h> 98 #include <fcntl.h> 99 #include <paths.h> 100 #include <poll.h> 101 #include <signal.h> 102 #include <stdio.h> 103 #include <stdlib.h> 104 #include <string.h> 105 #include <unistd.h> 106 #include <utmp.h> 107 #include <vis.h> 108 109 #define SYSLOG_NAMES 110 #include <sys/syslog.h> 111 112 #include "syslogd.h" 113 114 char *ConfFile = _PATH_LOGCONF; 115 const char ctty[] = _PATH_CONSOLE; 116 117 #define MAXUNAMES 20 /* maximum number of user names */ 118 119 120 /* 121 * Flags to logmsg(). 122 */ 123 124 #define IGN_CONS 0x001 /* don't print on console */ 125 #define SYNC_FILE 0x002 /* do fsync on file after printing */ 126 #define ADDDATE 0x004 /* add a date to the message */ 127 #define MARK 0x008 /* this message is a mark */ 128 129 /* 130 * This structure represents the files that will have log 131 * copies printed. 132 */ 133 134 struct filed { 135 struct filed *f_next; /* next in linked list */ 136 short f_type; /* entry type, see below */ 137 short f_file; /* file descriptor */ 138 time_t f_time; /* time this was last written */ 139 u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ 140 char *f_program; /* program this applies to */ 141 union { 142 char f_uname[MAXUNAMES][UT_NAMESIZE+1]; 143 struct { 144 char f_hname[MAXHOSTNAMELEN]; 145 struct sockaddr_storage f_addr; 146 } f_forw; /* forwarding address */ 147 char f_fname[MAXPATHLEN]; 148 struct { 149 char f_mname[MAX_MEMBUF_NAME]; 150 struct ringbuf *f_rb; 151 int f_overflow; 152 int f_attached; 153 size_t f_len; 154 } f_mb; /* Memory buffer */ 155 } f_un; 156 char f_prevline[MAXSVLINE]; /* last message logged */ 157 char f_lasttime[16]; /* time of last occurrence */ 158 char f_prevhost[MAXHOSTNAMELEN]; /* host from which recd. */ 159 int f_prevpri; /* pri of f_prevline */ 160 int f_prevlen; /* length of f_prevline */ 161 int f_prevcount; /* repetition cnt of prevline */ 162 unsigned int f_repeatcount; /* number of "repeated" msgs */ 163 int f_quick; /* abort when matched */ 164 time_t f_lasterrtime; /* last error was reported */ 165 }; 166 167 /* 168 * Intervals at which we flush out "message repeated" messages, 169 * in seconds after previous message is logged. After each flush, 170 * we move to the next interval until we reach the largest. 171 */ 172 int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ 173 #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) 174 #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) 175 #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ 176 (f)->f_repeatcount = MAXREPEAT; \ 177 } 178 179 /* values for f_type */ 180 #define F_UNUSED 0 /* unused entry */ 181 #define F_FILE 1 /* regular file */ 182 #define F_TTY 2 /* terminal */ 183 #define F_CONSOLE 3 /* console terminal */ 184 #define F_FORW 4 /* remote machine */ 185 #define F_USERS 5 /* list of users */ 186 #define F_WALL 6 /* everyone logged on */ 187 #define F_MEMBUF 7 /* memory buffer */ 188 #define F_PIPE 8 /* pipe to external program */ 189 190 char *TypeNames[9] = { 191 "UNUSED", "FILE", "TTY", "CONSOLE", 192 "FORW", "USERS", "WALL", "MEMBUF", 193 "PIPE" 194 }; 195 196 struct filed *Files; 197 struct filed consfile; 198 199 int nfunix = 1; /* Number of Unix domain sockets requested */ 200 char *funixn[MAXFUNIX] = { _PATH_LOG }; /* Paths to Unix domain sockets */ 201 int Debug; /* debug flag */ 202 int Startup = 1; /* startup flag */ 203 char LocalHostName[MAXHOSTNAMELEN]; /* our hostname */ 204 char *LocalDomain; /* our local domain name */ 205 int InetInuse = 0; /* non-zero if INET sockets are being used */ 206 int Initialized = 0; /* set when we have initialized ourselves */ 207 208 int MarkInterval = 20 * 60; /* interval between marks in seconds */ 209 int MarkSeq = 0; /* mark sequence number */ 210 int SecureMode = 1; /* when true, speak only unix domain socks */ 211 int NoDNS = 0; /* when true, will refrain from doing DNS lookups */ 212 213 char *ctlsock_path = NULL; /* Path to control socket */ 214 215 #define CTL_READING_CMD 1 216 #define CTL_WRITING_REPLY 2 217 #define CTL_WRITING_CONT_REPLY 3 218 int ctl_state = 0; /* What the control socket is up to */ 219 int membuf_drop = 0; /* logs were dropped in continuous membuf read */ 220 221 /* 222 * Client protocol NB. all numeric fields in network byte order 223 */ 224 #define CTL_VERSION 1 225 226 /* Request */ 227 struct { 228 u_int32_t version; 229 #define CMD_READ 1 /* Read out log */ 230 #define CMD_READ_CLEAR 2 /* Read and clear log */ 231 #define CMD_CLEAR 3 /* Clear log */ 232 #define CMD_LIST 4 /* List available logs */ 233 #define CMD_FLAGS 5 /* Query flags only */ 234 #define CMD_READ_CONT 6 /* Read out log continuously */ 235 u_int32_t cmd; 236 char logname[MAX_MEMBUF_NAME]; 237 } ctl_cmd; 238 239 size_t ctl_cmd_bytes = 0; /* number of bytes of ctl_cmd read */ 240 241 /* Reply */ 242 struct ctl_reply_hdr { 243 u_int32_t version; 244 #define CTL_HDR_FLAG_OVERFLOW 0x01 245 u_int32_t flags; 246 /* Reply text follows, up to MAX_MEMBUF long */ 247 }; 248 249 #define CTL_HDR_LEN (sizeof(struct ctl_reply_hdr)) 250 #define CTL_REPLY_MAXSIZE (CTL_HDR_LEN + MAX_MEMBUF) 251 #define CTL_REPLY_SIZE (strlen(reply_text) + CTL_HDR_LEN) 252 253 char *ctl_reply = NULL; /* Buffer for control connection reply */ 254 char *reply_text; /* Start of reply text in buffer */ 255 size_t ctl_reply_size = 0; /* Number of bytes used in reply */ 256 size_t ctl_reply_offset = 0; /* Number of bytes of reply written so far */ 257 258 struct pollfd pfd[N_PFD]; 259 260 volatile sig_atomic_t MarkSet; 261 volatile sig_atomic_t WantDie; 262 volatile sig_atomic_t DoInit; 263 264 struct filed *cfline(char *, char *); 265 void cvthname(struct sockaddr_in *, char *, size_t); 266 int decode(const char *, const CODE *); 267 void dodie(int); 268 void doinit(int); 269 void die(int); 270 void domark(int); 271 void markit(void); 272 void fprintlog(struct filed *, int, char *); 273 void init(void); 274 void logerror(const char *); 275 void logmsg(int, char *, char *, int); 276 struct filed *find_dup(struct filed *); 277 void printline(char *, char *); 278 void printsys(char *); 279 void reapchild(int); 280 char *ttymsg(struct iovec *, int, char *, int); 281 void usage(void); 282 void wallmsg(struct filed *, struct iovec *); 283 int getmsgbufsize(void); 284 int unix_socket(char *, int, mode_t); 285 void double_rbuf(int); 286 void ctlsock_accept_handler(void); 287 void ctlconn_read_handler(void); 288 void ctlconn_write_handler(void); 289 void tailify_replytext(char *, int); 290 void logto_ctlconn(char *); 291 292 int 293 main(int argc, char *argv[]) 294 { 295 int ch, i, linesize, fd; 296 struct sockaddr_un fromunix; 297 struct sockaddr_in frominet; 298 socklen_t len; 299 char *p, *line; 300 char resolve[MAXHOSTNAMELEN]; 301 int lockpipe[2] = { -1, -1}, nullfd; 302 struct addrinfo hints, *res, *res0; 303 FILE *fp; 304 305 while ((ch = getopt(argc, argv, "dnuf:m:p:a:s:")) != -1) 306 switch (ch) { 307 case 'd': /* debug */ 308 Debug++; 309 break; 310 case 'f': /* configuration file */ 311 ConfFile = optarg; 312 break; 313 case 'm': /* mark interval */ 314 MarkInterval = atoi(optarg) * 60; 315 break; 316 case 'n': /* don't do DNS lookups */ 317 NoDNS = 1; 318 break; 319 case 'p': /* path */ 320 funixn[0] = optarg; 321 break; 322 case 'u': /* allow udp input port */ 323 SecureMode = 0; 324 break; 325 case 'a': 326 if (nfunix >= MAXFUNIX) 327 fprintf(stderr, "syslogd: " 328 "out of descriptors, ignoring %s\n", 329 optarg); 330 else 331 funixn[nfunix++] = optarg; 332 break; 333 case 's': 334 ctlsock_path = optarg; 335 break; 336 default: 337 usage(); 338 } 339 if ((argc -= optind) != 0) 340 usage(); 341 342 if (Debug) 343 setlinebuf(stdout); 344 345 if ((fd = nullfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 346 logerror("Couldn't open /dev/null"); 347 die(0); 348 } 349 while (fd++ <= 2) { 350 if (fcntl(fd, F_GETFL, 0) == -1) 351 if (dup2(nullfd, fd) == -1) 352 logerror("dup2"); 353 } 354 355 consfile.f_type = F_CONSOLE; 356 (void)strlcpy(consfile.f_un.f_fname, ctty, 357 sizeof(consfile.f_un.f_fname)); 358 (void)gethostname(LocalHostName, sizeof(LocalHostName)); 359 if ((p = strchr(LocalHostName, '.')) != NULL) { 360 *p++ = '\0'; 361 LocalDomain = p; 362 } else 363 LocalDomain = ""; 364 365 linesize = getmsgbufsize(); 366 if (linesize < MAXLINE) 367 linesize = MAXLINE; 368 linesize++; 369 if ((line = malloc(linesize)) == NULL) { 370 logerror("Couldn't allocate line buffer"); 371 die(0); 372 } 373 374 /* Clear poll array, set all fds to ignore */ 375 for (i = 0; i < N_PFD; i++) { 376 pfd[i].fd = -1; 377 pfd[i].events = 0; 378 } 379 380 memset(&hints, 0, sizeof(hints)); 381 hints.ai_family = AF_INET; 382 hints.ai_socktype = SOCK_DGRAM; 383 hints.ai_protocol = IPPROTO_UDP; 384 hints.ai_flags = AI_PASSIVE; 385 386 i = getaddrinfo(NULL, "syslog", &hints, &res0); 387 if (i) { 388 errno = 0; 389 logerror("syslog/udp: unknown service"); 390 die(0); 391 } 392 393 for (res = res0; res; res = res->ai_next) { 394 struct pollfd *pfdp; 395 396 if (res->ai_family == AF_INET) 397 pfdp = &pfd[PFD_INET]; 398 else { 399 /* 400 * XXX AF_INET6 is skipped on purpose, need to 401 * fix '@' handling first. 402 */ 403 continue; 404 } 405 406 if (pfdp->fd >= 0) 407 continue; 408 409 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 410 if (fd < 0) 411 continue; 412 413 if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) { 414 logerror("bind"); 415 close(fd); 416 if (!Debug) 417 die(0); 418 fd = -1; 419 continue; 420 } 421 422 InetInuse = 1; 423 pfdp->fd = fd; 424 if (SecureMode) 425 shutdown(pfdp->fd, SHUT_RD); 426 else { 427 double_rbuf(pfdp->fd); 428 pfdp->events = POLLIN; 429 } 430 } 431 432 freeaddrinfo(res0); 433 434 #ifndef SUN_LEN 435 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 436 #endif 437 for (i = 0; i < nfunix; i++) { 438 if ((fd = unix_socket(funixn[i], SOCK_DGRAM, 0666)) == -1) { 439 if (i == 0 && !Debug) 440 die(0); 441 continue; 442 } 443 double_rbuf(fd); 444 pfd[PFD_UNIX_0 + i].fd = fd; 445 pfd[PFD_UNIX_0 + i].events = POLLIN; 446 } 447 448 if (ctlsock_path != NULL) { 449 fd = unix_socket(ctlsock_path, SOCK_STREAM, 0600); 450 if (fd != -1) { 451 if (listen(fd, 16) == -1) { 452 logerror("ctlsock listen"); 453 die(0); 454 } 455 pfd[PFD_CTLSOCK].fd = fd; 456 pfd[PFD_CTLSOCK].events = POLLIN; 457 } else if (!Debug) 458 die(0); 459 } 460 461 if ((fd = open(_PATH_KLOG, O_RDONLY, 0)) == -1) { 462 dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); 463 } else { 464 pfd[PFD_KLOG].fd = fd; 465 pfd[PFD_KLOG].events = POLLIN; 466 } 467 468 dprintf("off & running....\n"); 469 470 chdir("/"); 471 472 tzset(); 473 474 if (!Debug) { 475 char c; 476 477 pipe(lockpipe); 478 479 switch(fork()) { 480 case -1: 481 exit(1); 482 case 0: 483 setsid(); 484 close(lockpipe[0]); 485 break; 486 default: 487 close(lockpipe[1]); 488 read(lockpipe[0], &c, 1); 489 _exit(0); 490 } 491 } 492 493 /* tuck my process id away */ 494 if (!Debug) { 495 fp = fopen(_PATH_LOGPID, "w"); 496 if (fp != NULL) { 497 fprintf(fp, "%ld\n", (long)getpid()); 498 (void) fclose(fp); 499 } 500 } 501 502 /* Privilege separation begins here */ 503 if (priv_init(ConfFile, NoDNS, lockpipe[1], nullfd, argv) < 0) 504 errx(1, "unable to privsep"); 505 506 /* Process is now unprivileged and inside a chroot */ 507 init(); 508 509 Startup = 0; 510 511 /* Allocate ctl socket reply buffer if we have a ctl socket */ 512 if (pfd[PFD_CTLSOCK].fd != -1 && 513 (ctl_reply = malloc(CTL_REPLY_MAXSIZE)) == NULL) { 514 logerror("Couldn't allocate ctlsock reply buffer"); 515 die(0); 516 } 517 reply_text = ctl_reply + CTL_HDR_LEN; 518 519 if (!Debug) { 520 dup2(nullfd, STDIN_FILENO); 521 dup2(nullfd, STDOUT_FILENO); 522 dup2(nullfd, STDERR_FILENO); 523 if (nullfd > 2) 524 close(nullfd); 525 close(lockpipe[1]); 526 } 527 528 /* 529 * Signal to the priv process that the initial config parsing is done 530 * so that it will reject any future attempts to open more files 531 */ 532 priv_config_parse_done(); 533 534 (void)signal(SIGHUP, doinit); 535 (void)signal(SIGTERM, dodie); 536 (void)signal(SIGINT, Debug ? dodie : SIG_IGN); 537 (void)signal(SIGQUIT, Debug ? dodie : SIG_IGN); 538 (void)signal(SIGCHLD, reapchild); 539 (void)signal(SIGALRM, domark); 540 (void)signal(SIGPIPE, SIG_IGN); 541 (void)alarm(TIMERINTVL); 542 543 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: start", LocalHostName, ADDDATE); 544 dprintf("syslogd: started\n"); 545 546 for (;;) { 547 if (MarkSet) 548 markit(); 549 if (WantDie) 550 die(WantDie); 551 552 if (DoInit) { 553 init(); 554 DoInit = 0; 555 556 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", 557 LocalHostName, ADDDATE); 558 dprintf("syslogd: restarted\n"); 559 } 560 561 switch (poll(pfd, PFD_UNIX_0 + nfunix, -1)) { 562 case 0: 563 continue; 564 case -1: 565 if (errno != EINTR) 566 logerror("poll"); 567 continue; 568 } 569 570 if ((pfd[PFD_KLOG].revents & POLLIN) != 0) { 571 i = read(pfd[PFD_KLOG].fd, line, linesize - 1); 572 if (i > 0) { 573 line[i] = '\0'; 574 printsys(line); 575 } else if (i < 0 && errno != EINTR) { 576 logerror("klog"); 577 pfd[PFD_KLOG].fd = -1; 578 pfd[PFD_KLOG].events = 0; 579 } 580 } 581 if ((pfd[PFD_INET].revents & POLLIN) != 0) { 582 len = sizeof(frominet); 583 i = recvfrom(pfd[PFD_INET].fd, line, MAXLINE, 0, 584 (struct sockaddr *)&frominet, &len); 585 if (i > 0) { 586 line[i] = '\0'; 587 cvthname(&frominet, resolve, 588 sizeof resolve); 589 dprintf("cvthname res: %s\n", resolve); 590 printline(resolve, line); 591 } else if (i < 0 && errno != EINTR) 592 logerror("recvfrom inet"); 593 } 594 if ((pfd[PFD_CTLSOCK].revents & POLLIN) != 0) 595 ctlsock_accept_handler(); 596 if ((pfd[PFD_CTLCONN].revents & POLLIN) != 0) 597 ctlconn_read_handler(); 598 if ((pfd[PFD_CTLCONN].revents & POLLOUT) != 0) 599 ctlconn_write_handler(); 600 601 for (i = 0; i < nfunix; i++) { 602 if ((pfd[PFD_UNIX_0 + i].revents & POLLIN) != 0) { 603 ssize_t rlen; 604 605 len = sizeof(fromunix); 606 rlen = recvfrom(pfd[PFD_UNIX_0 + i].fd, line, 607 MAXLINE, 0, (struct sockaddr *)&fromunix, 608 &len); 609 if (rlen > 0) { 610 line[rlen] = '\0'; 611 printline(LocalHostName, line); 612 } else if (rlen == -1 && errno != EINTR) 613 logerror("recvfrom unix"); 614 } 615 } 616 } 617 /* NOTREACHED */ 618 free(pfd); 619 return (0); 620 } 621 622 void 623 usage(void) 624 { 625 626 (void)fprintf(stderr, 627 "usage: syslogd [-dnu] [-a path] [-f config_file] [-m mark_interval]\n" 628 " [-p log_socket] [-s reporting_socket]\n"); 629 exit(1); 630 } 631 632 /* 633 * Take a raw input line, decode the message, and print the message 634 * on the appropriate log files. 635 */ 636 void 637 printline(char *hname, char *msg) 638 { 639 int pri; 640 char *p, *q, line[MAXLINE + 1]; 641 642 /* test for special codes */ 643 pri = DEFUPRI; 644 p = msg; 645 if (*p == '<') { 646 pri = 0; 647 while (isdigit(*++p)) 648 pri = 10 * pri + (*p - '0'); 649 if (*p == '>') 650 ++p; 651 } 652 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 653 pri = DEFUPRI; 654 655 /* 656 * Don't allow users to log kernel messages. 657 * NOTE: since LOG_KERN == 0 this will also match 658 * messages with no facility specified. 659 */ 660 if (LOG_FAC(pri) == LOG_KERN) 661 pri = LOG_USER | LOG_PRI(pri); 662 663 for (q = line; *p && q < &line[sizeof(line) - 4]; p++) { 664 if (*p == '\n') 665 *q++ = ' '; 666 else 667 q = vis(q, *p, 0, 0); 668 } 669 *q = '\0'; 670 671 logmsg(pri, line, hname, 0); 672 } 673 674 /* 675 * Take a raw input line from /dev/klog, split and format similar to syslog(). 676 */ 677 void 678 printsys(char *msg) 679 { 680 int c, pri, flags; 681 char *lp, *p, *q, line[MAXLINE + 1]; 682 683 (void)snprintf(line, sizeof line, "%s: ", _PATH_UNIX); 684 lp = line + strlen(line); 685 for (p = msg; *p != '\0'; ) { 686 flags = SYNC_FILE | ADDDATE; /* fsync file after write */ 687 pri = DEFSPRI; 688 if (*p == '<') { 689 pri = 0; 690 while (isdigit(*++p)) 691 pri = 10 * pri + (*p - '0'); 692 if (*p == '>') 693 ++p; 694 } else { 695 /* kernel printf's come out on console */ 696 flags |= IGN_CONS; 697 } 698 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 699 pri = DEFSPRI; 700 701 q = lp; 702 while (*p && (c = *p++) != '\n' && q < &line[sizeof(line) - 4]) 703 q = vis(q, c, 0, 0); 704 705 logmsg(pri, line, LocalHostName, flags); 706 } 707 } 708 709 time_t now; 710 711 /* 712 * Log a message to the appropriate log files, users, etc. based on 713 * the priority. 714 */ 715 void 716 logmsg(int pri, char *msg, char *from, int flags) 717 { 718 struct filed *f; 719 int fac, msglen, prilev, i; 720 sigset_t mask, omask; 721 char *timestamp; 722 char prog[NAME_MAX+1]; 723 724 dprintf("logmsg: pri 0%o, flags 0x%x, from %s, msg %s\n", 725 pri, flags, from, msg); 726 727 sigemptyset(&mask); 728 sigaddset(&mask, SIGALRM); 729 sigaddset(&mask, SIGHUP); 730 sigprocmask(SIG_BLOCK, &mask, &omask); 731 732 /* 733 * Check to see if msg looks non-standard. 734 */ 735 msglen = strlen(msg); 736 if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || 737 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') 738 flags |= ADDDATE; 739 740 (void)time(&now); 741 if (flags & ADDDATE) 742 timestamp = ctime(&now) + 4; 743 else { 744 timestamp = msg; 745 msg += 16; 746 msglen -= 16; 747 } 748 749 /* extract facility and priority level */ 750 if (flags & MARK) 751 fac = LOG_NFACILITIES; 752 else 753 fac = LOG_FAC(pri); 754 prilev = LOG_PRI(pri); 755 756 /* extract program name */ 757 for(i = 0; i < NAME_MAX; i++) { 758 if (!isalnum(msg[i]) && msg[i] != '-') 759 break; 760 prog[i] = msg[i]; 761 } 762 prog[i] = 0; 763 764 /* log the message to the particular outputs */ 765 if (!Initialized) { 766 f = &consfile; 767 f->f_file = priv_open_tty(ctty); 768 769 if (f->f_file >= 0) { 770 fprintlog(f, flags, msg); 771 (void)close(f->f_file); 772 f->f_file = -1; 773 } 774 (void)sigprocmask(SIG_SETMASK, &omask, NULL); 775 return; 776 } 777 for (f = Files; f; f = f->f_next) { 778 /* skip messages that are incorrect priority */ 779 if (f->f_pmask[fac] < prilev || 780 f->f_pmask[fac] == INTERNAL_NOPRI) 781 continue; 782 783 /* skip messages with the incorrect program name */ 784 if (f->f_program) 785 if (strcmp(prog, f->f_program) != 0) 786 continue; 787 788 if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) 789 continue; 790 791 /* don't output marks to recently written files */ 792 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) 793 continue; 794 795 /* 796 * suppress duplicate lines to this file 797 */ 798 if ((flags & MARK) == 0 && msglen == f->f_prevlen && 799 !strcmp(msg, f->f_prevline) && 800 !strcmp(from, f->f_prevhost)) { 801 strlcpy(f->f_lasttime, timestamp, 16); 802 f->f_prevcount++; 803 dprintf("msg repeated %d times, %ld sec of %d\n", 804 f->f_prevcount, (long)(now - f->f_time), 805 repeatinterval[f->f_repeatcount]); 806 /* 807 * If domark would have logged this by now, 808 * flush it now (so we don't hold isolated messages), 809 * but back off so we'll flush less often 810 * in the future. 811 */ 812 if (now > REPEATTIME(f)) { 813 fprintlog(f, flags, (char *)NULL); 814 BACKOFF(f); 815 } 816 } else { 817 /* new line, save it */ 818 if (f->f_prevcount) 819 fprintlog(f, 0, (char *)NULL); 820 f->f_repeatcount = 0; 821 f->f_prevpri = pri; 822 strlcpy(f->f_lasttime, timestamp, 16); 823 strlcpy(f->f_prevhost, from, 824 sizeof(f->f_prevhost)); 825 if (msglen < MAXSVLINE) { 826 f->f_prevlen = msglen; 827 strlcpy(f->f_prevline, msg, sizeof(f->f_prevline)); 828 fprintlog(f, flags, (char *)NULL); 829 } else { 830 f->f_prevline[0] = 0; 831 f->f_prevlen = 0; 832 fprintlog(f, flags, msg); 833 } 834 } 835 836 if (f->f_quick) 837 break; 838 } 839 (void)sigprocmask(SIG_SETMASK, &omask, NULL); 840 } 841 842 void 843 fprintlog(struct filed *f, int flags, char *msg) 844 { 845 struct iovec iov[6]; 846 struct iovec *v; 847 int l, retryonce; 848 char line[MAXLINE + 1], repbuf[80], greetings[500]; 849 850 v = iov; 851 if (f->f_type == F_WALL) { 852 if ((l = snprintf(greetings, sizeof(greetings), 853 "\r\n\7Message from syslogd@%s at %.24s ...\r\n", 854 f->f_prevhost, ctime(&now))) >= sizeof(greetings) || 855 l == -1) 856 l = strlen(greetings); 857 v->iov_base = greetings; 858 v->iov_len = l; 859 v++; 860 v->iov_base = ""; 861 v->iov_len = 0; 862 v++; 863 } else { 864 v->iov_base = f->f_lasttime; 865 v->iov_len = 15; 866 v++; 867 v->iov_base = " "; 868 v->iov_len = 1; 869 v++; 870 } 871 v->iov_base = f->f_prevhost; 872 v->iov_len = strlen(v->iov_base); 873 v++; 874 v->iov_base = " "; 875 v->iov_len = 1; 876 v++; 877 878 if (msg) { 879 v->iov_base = msg; 880 v->iov_len = strlen(msg); 881 } else if (f->f_prevcount > 1) { 882 if ((l = snprintf(repbuf, sizeof(repbuf), 883 "last message repeated %d times", f->f_prevcount)) >= 884 sizeof(repbuf) || l == -1) 885 l = strlen(repbuf); 886 v->iov_base = repbuf; 887 v->iov_len = l; 888 } else { 889 v->iov_base = f->f_prevline; 890 v->iov_len = f->f_prevlen; 891 } 892 v++; 893 894 dprintf("Logging to %s", TypeNames[f->f_type]); 895 f->f_time = now; 896 897 switch (f->f_type) { 898 case F_UNUSED: 899 dprintf("\n"); 900 break; 901 902 case F_FORW: 903 dprintf(" %s\n", f->f_un.f_forw.f_hname); 904 if ((l = snprintf(line, sizeof(line), "<%d>%.15s %s", 905 f->f_prevpri, (char *)iov[0].iov_base, 906 (char *)iov[4].iov_base)) >= sizeof(line) || l == -1) 907 l = strlen(line); 908 if (sendto(pfd[PFD_INET].fd, line, l, 0, 909 (struct sockaddr *)&f->f_un.f_forw.f_addr, 910 f->f_un.f_forw.f_addr.ss_len) != l) { 911 switch (errno) { 912 case EHOSTDOWN: 913 case EHOSTUNREACH: 914 case ENETDOWN: 915 case ENOBUFS: 916 /* silently dropped */ 917 break; 918 default: 919 f->f_type = F_UNUSED; 920 logerror("sendto"); 921 break; 922 } 923 } 924 break; 925 926 case F_CONSOLE: 927 if (flags & IGN_CONS) { 928 dprintf(" (ignored)\n"); 929 break; 930 } 931 /* FALLTHROUGH */ 932 933 case F_TTY: 934 case F_FILE: 935 case F_PIPE: 936 dprintf(" %s\n", f->f_un.f_fname); 937 if (f->f_type != F_FILE && f->f_type != F_PIPE) { 938 v->iov_base = "\r\n"; 939 v->iov_len = 2; 940 } else { 941 v->iov_base = "\n"; 942 v->iov_len = 1; 943 } 944 retryonce = 0; 945 again: 946 if (writev(f->f_file, iov, 6) < 0) { 947 int e = errno; 948 949 /* pipe is non-blocking. log and drop message if full */ 950 if (e == EAGAIN && f->f_type == F_PIPE) { 951 if (now - f->f_lasterrtime > 120) { 952 f->f_lasterrtime = now; 953 logerror(f->f_un.f_fname); 954 } 955 break; 956 } 957 958 (void)close(f->f_file); 959 /* 960 * Check for errors on TTY's or program pipes. 961 * Errors happen due to loss of tty or died programs. 962 */ 963 if (e == EAGAIN) { 964 /* 965 * Silently drop messages on blocked write. 966 * This can happen when logging to a locked tty. 967 */ 968 break; 969 } else if ((e == EIO || e == EBADF) && 970 f->f_type != F_FILE && f->f_type != F_PIPE && 971 !retryonce) { 972 f->f_file = priv_open_tty(f->f_un.f_fname); 973 retryonce = 1; 974 if (f->f_file < 0) { 975 f->f_type = F_UNUSED; 976 logerror(f->f_un.f_fname); 977 } else 978 goto again; 979 } else if ((e == EPIPE || e == EBADF) && 980 f->f_type == F_PIPE && !retryonce) { 981 f->f_file = priv_open_log(f->f_un.f_fname); 982 retryonce = 1; 983 if (f->f_file < 0) { 984 f->f_type = F_UNUSED; 985 logerror(f->f_un.f_fname); 986 } else 987 goto again; 988 } else { 989 f->f_type = F_UNUSED; 990 f->f_file = -1; 991 errno = e; 992 logerror(f->f_un.f_fname); 993 } 994 } else if (flags & SYNC_FILE) 995 (void)fsync(f->f_file); 996 break; 997 998 case F_USERS: 999 case F_WALL: 1000 dprintf("\n"); 1001 v->iov_base = "\r\n"; 1002 v->iov_len = 2; 1003 wallmsg(f, iov); 1004 break; 1005 1006 case F_MEMBUF: 1007 dprintf("\n"); 1008 snprintf(line, sizeof(line), "%.15s %s %s", 1009 (char *)iov[0].iov_base, (char *)iov[2].iov_base, 1010 (char *)iov[4].iov_base); 1011 if (ringbuf_append_line(f->f_un.f_mb.f_rb, line) == 1) 1012 f->f_un.f_mb.f_overflow = 1; 1013 if (f->f_un.f_mb.f_attached) 1014 logto_ctlconn(line); 1015 break; 1016 } 1017 f->f_prevcount = 0; 1018 } 1019 1020 /* 1021 * WALLMSG -- Write a message to the world at large 1022 * 1023 * Write the specified message to either the entire 1024 * world, or a list of approved users. 1025 */ 1026 void 1027 wallmsg(struct filed *f, struct iovec *iov) 1028 { 1029 struct utmp ut; 1030 char line[sizeof(ut.ut_line) + 1], *p; 1031 static int reenter; /* avoid calling ourselves */ 1032 FILE *uf; 1033 int i; 1034 1035 if (reenter++) 1036 return; 1037 if ((uf = priv_open_utmp()) == NULL) { 1038 logerror(_PATH_UTMP); 1039 reenter = 0; 1040 return; 1041 } 1042 /* NOSTRICT */ 1043 while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) { 1044 if (ut.ut_name[0] == '\0') 1045 continue; 1046 /* must use strncpy since ut_* may not be NUL terminated */ 1047 strncpy(line, ut.ut_line, sizeof(line) - 1); 1048 line[sizeof(line) - 1] = '\0'; 1049 if (f->f_type == F_WALL) { 1050 if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) != NULL) { 1051 errno = 0; /* already in msg */ 1052 logerror(p); 1053 } 1054 continue; 1055 } 1056 /* should we send the message to this user? */ 1057 for (i = 0; i < MAXUNAMES; i++) { 1058 if (!f->f_un.f_uname[i][0]) 1059 break; 1060 if (!strncmp(f->f_un.f_uname[i], ut.ut_name, 1061 UT_NAMESIZE)) { 1062 if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) 1063 != NULL) { 1064 errno = 0; /* already in msg */ 1065 logerror(p); 1066 } 1067 break; 1068 } 1069 } 1070 } 1071 (void)fclose(uf); 1072 reenter = 0; 1073 } 1074 1075 /* ARGSUSED */ 1076 void 1077 reapchild(int signo) 1078 { 1079 int save_errno = errno; 1080 int status; 1081 1082 while (waitpid(-1, &status, WNOHANG) > 0) 1083 ; 1084 errno = save_errno; 1085 } 1086 1087 /* 1088 * Return a printable representation of a host address. 1089 */ 1090 void 1091 cvthname(struct sockaddr_in *f, char *result, size_t res_len) 1092 { 1093 sigset_t omask, nmask; 1094 char *p, *ip; 1095 int ret_len; 1096 1097 if (f->sin_family != AF_INET) { 1098 dprintf("Malformed from address\n"); 1099 strlcpy(result, "???", res_len); 1100 return; 1101 } 1102 1103 ip = inet_ntoa(f->sin_addr); 1104 dprintf("cvthname(%s)\n", ip); 1105 if (NoDNS) { 1106 strlcpy(result, ip, res_len); 1107 return; 1108 } 1109 1110 sigemptyset(&nmask); 1111 sigaddset(&nmask, SIGHUP); 1112 sigprocmask(SIG_BLOCK, &nmask, &omask); 1113 1114 ret_len = priv_gethostbyaddr((char *)&f->sin_addr, 1115 sizeof(struct in_addr), f->sin_family, result, res_len); 1116 1117 sigprocmask(SIG_SETMASK, &omask, NULL); 1118 if (ret_len == 0) { 1119 dprintf("Host name for your address (%s) unknown\n", ip); 1120 strlcpy(result, ip, res_len); 1121 } else if ((p = strchr(result, '.')) && strcmp(p + 1, LocalDomain) == 0) 1122 *p = '\0'; 1123 } 1124 1125 void 1126 dodie(int signo) 1127 { 1128 WantDie = signo; 1129 } 1130 1131 /* ARGSUSED */ 1132 void 1133 domark(int signo) 1134 { 1135 MarkSet = 1; 1136 } 1137 1138 /* ARGSUSED */ 1139 void 1140 doinit(int signo) 1141 { 1142 DoInit = 1; 1143 } 1144 1145 /* 1146 * Print syslogd errors some place. 1147 */ 1148 void 1149 logerror(const char *type) 1150 { 1151 char buf[100]; 1152 1153 if (errno) 1154 (void)snprintf(buf, sizeof(buf), "syslogd: %s: %s", 1155 type, strerror(errno)); 1156 else 1157 (void)snprintf(buf, sizeof(buf), "syslogd: %s", type); 1158 errno = 0; 1159 dprintf("%s\n", buf); 1160 if (Startup) 1161 fprintf(stderr, "%s\n", buf); 1162 else 1163 logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); 1164 } 1165 1166 void 1167 die(int signo) 1168 { 1169 struct filed *f; 1170 int was_initialized = Initialized; 1171 char buf[100]; 1172 1173 Initialized = 0; /* Don't log SIGCHLDs */ 1174 alarm(0); 1175 for (f = Files; f != NULL; f = f->f_next) { 1176 /* flush any pending output */ 1177 if (f->f_prevcount) 1178 fprintlog(f, 0, (char *)NULL); 1179 } 1180 Initialized = was_initialized; 1181 if (signo) { 1182 dprintf("syslogd: exiting on signal %d\n", signo); 1183 (void)snprintf(buf, sizeof buf, "exiting on signal %d", signo); 1184 errno = 0; 1185 logerror(buf); 1186 } 1187 dprintf("[unpriv] syslogd child about to exit\n"); 1188 exit(0); 1189 } 1190 1191 /* 1192 * INIT -- Initialize syslogd from configuration table 1193 */ 1194 void 1195 init(void) 1196 { 1197 char cline[LINE_MAX], prog[NAME_MAX+1], *p; 1198 struct filed *f, *next, **nextp, *mb, *m; 1199 FILE *cf; 1200 int i; 1201 1202 dprintf("init\n"); 1203 1204 /* If config file has been modified, then just die to restart */ 1205 if (priv_config_modified()) { 1206 dprintf("config file changed: dying\n"); 1207 die(0); 1208 } 1209 1210 /* 1211 * Close all open log files. 1212 */ 1213 Initialized = 0; 1214 mb = NULL; 1215 for (f = Files; f != NULL; f = next) { 1216 /* flush any pending output */ 1217 if (f->f_prevcount) 1218 fprintlog(f, 0, (char *)NULL); 1219 1220 switch (f->f_type) { 1221 case F_FILE: 1222 case F_TTY: 1223 case F_CONSOLE: 1224 case F_PIPE: 1225 (void)close(f->f_file); 1226 break; 1227 case F_FORW: 1228 break; 1229 } 1230 next = f->f_next; 1231 if (f->f_program) 1232 free(f->f_program); 1233 if (f->f_type == F_MEMBUF) { 1234 f->f_next = mb; 1235 f->f_program = NULL; 1236 dprintf("add %p to mb: %p\n", f, mb); 1237 mb = f; 1238 } else 1239 free((char *)f); 1240 } 1241 Files = NULL; 1242 nextp = &Files; 1243 1244 /* open the configuration file */ 1245 if ((cf = priv_open_config()) == NULL) { 1246 dprintf("cannot open %s\n", ConfFile); 1247 *nextp = cfline("*.ERR\t/dev/console", "*"); 1248 (*nextp)->f_next = cfline("*.PANIC\t*", "*"); 1249 Initialized = 1; 1250 return; 1251 } 1252 1253 /* 1254 * Foreach line in the conf table, open that file. 1255 */ 1256 f = NULL; 1257 strlcpy(prog, "*", sizeof(prog)); 1258 while (fgets(cline, sizeof(cline), cf) != NULL) { 1259 /* 1260 * check for end-of-section, comments, strip off trailing 1261 * spaces and newline character. !prog is treated 1262 * specially: the following lines apply only to that program. 1263 */ 1264 for (p = cline; isspace(*p); ++p) 1265 continue; 1266 if (*p == '\0' || *p == '#') 1267 continue; 1268 if (*p == '!') { 1269 p++; 1270 while (isspace(*p)) 1271 p++; 1272 if (!*p || (*p == '*' && (!p[1] || isspace(p[1])))) { 1273 strlcpy(prog, "*", sizeof(prog)); 1274 continue; 1275 } 1276 for (i = 0; i < NAME_MAX; i++) { 1277 if (!isalnum(p[i]) && p[i] != '-' && p[i] != '!') 1278 break; 1279 prog[i] = p[i]; 1280 } 1281 prog[i] = 0; 1282 continue; 1283 } 1284 p = cline + strlen(cline); 1285 while (p > cline) 1286 if (!isspace(*--p)) { 1287 p++; 1288 break; 1289 } 1290 *p = '\0'; 1291 f = cfline(cline, prog); 1292 if (f != NULL) { 1293 *nextp = f; 1294 nextp = &f->f_next; 1295 } 1296 } 1297 1298 /* Match and initialize the memory buffers */ 1299 for (f = Files; f != NULL; f = f->f_next) { 1300 if (f->f_type != F_MEMBUF) 1301 continue; 1302 dprintf("Initialize membuf %s at %p\n", f->f_un.f_mb.f_mname, f); 1303 1304 for (m = mb; m != NULL; m = m->f_next) { 1305 if (m->f_un.f_mb.f_rb == NULL) 1306 continue; 1307 if (strcmp(m->f_un.f_mb.f_mname, 1308 f->f_un.f_mb.f_mname) == 0) 1309 break; 1310 } 1311 if (m == NULL) { 1312 dprintf("Membuf no match\n"); 1313 f->f_un.f_mb.f_rb = ringbuf_init(f->f_un.f_mb.f_len); 1314 if (f->f_un.f_mb.f_rb == NULL) { 1315 f->f_type = F_UNUSED; 1316 logerror("Failed to allocate membuf"); 1317 } 1318 } else { 1319 dprintf("Membuf match f:%p, m:%p\n", f, m); 1320 f->f_un = m->f_un; 1321 m->f_un.f_mb.f_rb = NULL; 1322 } 1323 } 1324 1325 /* make sure remaining buffers are freed */ 1326 while (mb != NULL) { 1327 m = mb; 1328 if (m->f_un.f_mb.f_rb != NULL) { 1329 logerror("Mismatched membuf"); 1330 ringbuf_free(m->f_un.f_mb.f_rb); 1331 } 1332 dprintf("Freeing membuf %p\n", m); 1333 1334 mb = m->f_next; 1335 free(m); 1336 } 1337 1338 /* close the configuration file */ 1339 (void)fclose(cf); 1340 1341 Initialized = 1; 1342 1343 if (Debug) { 1344 for (f = Files; f; f = f->f_next) { 1345 for (i = 0; i <= LOG_NFACILITIES; i++) 1346 if (f->f_pmask[i] == INTERNAL_NOPRI) 1347 printf("X "); 1348 else 1349 printf("%d ", f->f_pmask[i]); 1350 printf("%s: ", TypeNames[f->f_type]); 1351 switch (f->f_type) { 1352 case F_FILE: 1353 case F_TTY: 1354 case F_CONSOLE: 1355 case F_PIPE: 1356 printf("%s", f->f_un.f_fname); 1357 break; 1358 1359 case F_FORW: 1360 printf("%s", f->f_un.f_forw.f_hname); 1361 break; 1362 1363 case F_USERS: 1364 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++) 1365 printf("%s, ", f->f_un.f_uname[i]); 1366 break; 1367 1368 case F_MEMBUF: 1369 printf("%s", f->f_un.f_mb.f_mname); 1370 break; 1371 1372 } 1373 if (f->f_program) 1374 printf(" (%s)", f->f_program); 1375 printf("\n"); 1376 } 1377 } 1378 } 1379 1380 #define progmatches(p1, p2) \ 1381 (p1 == p2 || (p1 != NULL && p2 != NULL && strcmp(p1, p2) == 0)) 1382 1383 /* 1384 * Spot a line with a duplicate file, pipe, console, tty, or membuf target. 1385 */ 1386 struct filed * 1387 find_dup(struct filed *f) 1388 { 1389 struct filed *list; 1390 1391 for (list = Files; list; list = list->f_next) { 1392 if (list->f_quick || f->f_quick) 1393 continue; 1394 switch (list->f_type) { 1395 case F_FILE: 1396 case F_TTY: 1397 case F_CONSOLE: 1398 case F_PIPE: 1399 if (strcmp(list->f_un.f_fname, f->f_un.f_fname) == 0 && 1400 progmatches(list->f_program, f->f_program)) 1401 return (list); 1402 break; 1403 case F_MEMBUF: 1404 if (strcmp(list->f_un.f_mb.f_mname, 1405 f->f_un.f_mb.f_mname) == 0 && 1406 progmatches(list->f_program, f->f_program)) 1407 return (list); 1408 break; 1409 } 1410 } 1411 return (NULL); 1412 } 1413 1414 /* 1415 * Crack a configuration file line 1416 */ 1417 struct filed * 1418 cfline(char *line, char *prog) 1419 { 1420 int i, pri, addr_len; 1421 size_t rb_len; 1422 char *bp, *p, *q, *cp; 1423 char buf[MAXLINE], ebuf[100]; 1424 struct filed *xf, *f, *d; 1425 1426 dprintf("cfline(\"%s\", f, \"%s\")\n", line, prog); 1427 1428 errno = 0; /* keep strerror() stuff out of logerror messages */ 1429 1430 if ((f = calloc(1, sizeof(*f))) == NULL) { 1431 logerror("Couldn't allocate struct filed"); 1432 die(0); 1433 } 1434 for (i = 0; i <= LOG_NFACILITIES; i++) 1435 f->f_pmask[i] = INTERNAL_NOPRI; 1436 1437 /* save program name if any */ 1438 if (*prog == '!') { 1439 f->f_quick = 1; 1440 prog++; 1441 } else 1442 f->f_quick = 0; 1443 if (!strcmp(prog, "*")) 1444 prog = NULL; 1445 else { 1446 f->f_program = calloc(1, strlen(prog)+1); 1447 if (f->f_program) 1448 strlcpy(f->f_program, prog, strlen(prog)+1); 1449 } 1450 1451 /* scan through the list of selectors */ 1452 for (p = line; *p && *p != '\t';) { 1453 1454 /* find the end of this facility name list */ 1455 for (q = p; *q && *q != '\t' && *q++ != '.'; ) 1456 continue; 1457 1458 /* collect priority name */ 1459 for (bp = buf; *q && !strchr("\t,;", *q); ) 1460 *bp++ = *q++; 1461 *bp = '\0'; 1462 1463 /* skip cruft */ 1464 while (*q && strchr(", ;", *q)) 1465 q++; 1466 1467 /* decode priority name */ 1468 if (*buf == '*') 1469 pri = LOG_PRIMASK + 1; 1470 else { 1471 /* ignore trailing spaces */ 1472 for (i=strlen(buf)-1; i >= 0 && buf[i] == ' '; i--) { 1473 buf[i]='\0'; 1474 } 1475 1476 pri = decode(buf, prioritynames); 1477 if (pri < 0) { 1478 (void)snprintf(ebuf, sizeof ebuf, 1479 "unknown priority name \"%s\"", buf); 1480 logerror(ebuf); 1481 free(f); 1482 return (NULL); 1483 } 1484 } 1485 1486 /* scan facilities */ 1487 while (*p && !strchr("\t.;", *p)) { 1488 for (bp = buf; *p && !strchr("\t,;.", *p); ) 1489 *bp++ = *p++; 1490 *bp = '\0'; 1491 if (*buf == '*') 1492 for (i = 0; i < LOG_NFACILITIES; i++) 1493 f->f_pmask[i] = pri; 1494 else { 1495 i = decode(buf, facilitynames); 1496 if (i < 0) { 1497 (void)snprintf(ebuf, sizeof(ebuf), 1498 "unknown facility name \"%s\"", 1499 buf); 1500 logerror(ebuf); 1501 free(f); 1502 return (NULL); 1503 } 1504 f->f_pmask[i >> 3] = pri; 1505 } 1506 while (*p == ',' || *p == ' ') 1507 p++; 1508 } 1509 1510 p = q; 1511 } 1512 1513 /* skip to action part */ 1514 while (*p == '\t') 1515 p++; 1516 1517 switch (*p) { 1518 case '@': 1519 if (!InetInuse) 1520 break; 1521 if ((cp = strrchr(++p, ':')) != NULL) 1522 *cp++ = '\0'; 1523 if ((strlcpy(f->f_un.f_forw.f_hname, p, 1524 sizeof(f->f_un.f_forw.f_hname)) >= 1525 sizeof(f->f_un.f_forw.f_hname))) { 1526 snprintf(ebuf, sizeof(ebuf), "hostname too long \"%s\"", 1527 p); 1528 logerror(ebuf); 1529 break; 1530 } 1531 addr_len = priv_gethostserv(f->f_un.f_forw.f_hname, 1532 cp == NULL ? "syslog" : cp, 1533 (struct sockaddr*)&f->f_un.f_forw.f_addr, 1534 sizeof(f->f_un.f_forw.f_addr)); 1535 if (addr_len < 1) { 1536 snprintf(ebuf, sizeof(ebuf), "bad hostname \"%s\"", p); 1537 logerror(ebuf); 1538 break; 1539 } 1540 f->f_type = F_FORW; 1541 break; 1542 1543 case '/': 1544 case '|': 1545 (void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname)); 1546 d = find_dup(f); 1547 if (d != NULL) { 1548 for (i = 0; i <= LOG_NFACILITIES; i++) 1549 if (f->f_pmask[i] != INTERNAL_NOPRI) 1550 d->f_pmask[i] = f->f_pmask[i]; 1551 free(f); 1552 return (NULL); 1553 } 1554 if (strcmp(p, ctty) == 0) 1555 f->f_file = priv_open_tty(p); 1556 else 1557 f->f_file = priv_open_log(p); 1558 if (f->f_file < 0) { 1559 f->f_type = F_UNUSED; 1560 logerror(p); 1561 break; 1562 } 1563 if (isatty(f->f_file)) { 1564 if (strcmp(p, ctty) == 0) 1565 f->f_type = F_CONSOLE; 1566 else 1567 f->f_type = F_TTY; 1568 } else { 1569 if (*p == '|') 1570 f->f_type = F_PIPE; 1571 else { 1572 f->f_type = F_FILE; 1573 1574 /* Clear O_NONBLOCK flag on f->f_file */ 1575 if ((i = fcntl(f->f_file, F_GETFL, 0)) != -1) { 1576 i &= ~O_NONBLOCK; 1577 fcntl(f->f_file, F_SETFL, i); 1578 } 1579 } 1580 } 1581 break; 1582 1583 case '*': 1584 f->f_type = F_WALL; 1585 break; 1586 1587 case ':': 1588 f->f_type = F_MEMBUF; 1589 1590 /* Parse buffer size (in kb) */ 1591 errno = 0; 1592 rb_len = strtoul(++p, &q, 0); 1593 if (*p == '\0' || (errno == ERANGE && rb_len == ULONG_MAX) || 1594 *q != ':' || rb_len == 0) { 1595 f->f_type = F_UNUSED; 1596 logerror(p); 1597 break; 1598 } 1599 q++; 1600 rb_len *= 1024; 1601 1602 /* Copy buffer name */ 1603 for(i = 0; i < sizeof(f->f_un.f_mb.f_mname) - 1; i++) { 1604 if (!isalnum(q[i])) 1605 break; 1606 f->f_un.f_mb.f_mname[i] = q[i]; 1607 } 1608 1609 /* Make sure buffer name is unique */ 1610 xf = find_dup(f); 1611 1612 /* Error on missing or non-unique name, or bad buffer length */ 1613 if (i == 0 || rb_len > MAX_MEMBUF || xf != NULL) { 1614 f->f_type = F_UNUSED; 1615 logerror(p); 1616 break; 1617 } 1618 1619 /* Set buffer length */ 1620 rb_len = MAX(rb_len, MIN_MEMBUF); 1621 f->f_un.f_mb.f_len = rb_len; 1622 f->f_un.f_mb.f_overflow = 0; 1623 f->f_un.f_mb.f_attached = 0; 1624 break; 1625 1626 default: 1627 for (i = 0; i < MAXUNAMES && *p; i++) { 1628 for (q = p; *q && *q != ','; ) 1629 q++; 1630 (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); 1631 if ((q - p) > UT_NAMESIZE) 1632 f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; 1633 else 1634 f->f_un.f_uname[i][q - p] = '\0'; 1635 while (*q == ',' || *q == ' ') 1636 q++; 1637 p = q; 1638 } 1639 f->f_type = F_USERS; 1640 break; 1641 } 1642 return (f); 1643 } 1644 1645 1646 /* 1647 * Retrieve the size of the kernel message buffer, via sysctl. 1648 */ 1649 int 1650 getmsgbufsize(void) 1651 { 1652 int msgbufsize, mib[2]; 1653 size_t size; 1654 1655 mib[0] = CTL_KERN; 1656 mib[1] = KERN_MSGBUFSIZE; 1657 size = sizeof msgbufsize; 1658 if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) { 1659 dprintf("couldn't get kern.msgbufsize\n"); 1660 return (0); 1661 } 1662 return (msgbufsize); 1663 } 1664 1665 /* 1666 * Decode a symbolic name to a numeric value 1667 */ 1668 int 1669 decode(const char *name, const CODE *codetab) 1670 { 1671 const CODE *c; 1672 char *p, buf[40]; 1673 1674 if (isdigit(*name)) 1675 return (atoi(name)); 1676 1677 for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) { 1678 if (isupper(*name)) 1679 *p = tolower(*name); 1680 else 1681 *p = *name; 1682 } 1683 *p = '\0'; 1684 for (c = codetab; c->c_name; c++) 1685 if (!strcmp(buf, c->c_name)) 1686 return (c->c_val); 1687 1688 return (-1); 1689 } 1690 1691 void 1692 markit(void) 1693 { 1694 struct filed *f; 1695 1696 now = time((time_t *)NULL); 1697 MarkSeq += TIMERINTVL; 1698 if (MarkSeq >= MarkInterval) { 1699 logmsg(LOG_INFO, "-- MARK --", 1700 LocalHostName, ADDDATE|MARK); 1701 MarkSeq = 0; 1702 } 1703 1704 for (f = Files; f; f = f->f_next) { 1705 if (f->f_prevcount && now >= REPEATTIME(f)) { 1706 dprintf("flush %s: repeated %d times, %d sec.\n", 1707 TypeNames[f->f_type], f->f_prevcount, 1708 repeatinterval[f->f_repeatcount]); 1709 fprintlog(f, 0, (char *)NULL); 1710 BACKOFF(f); 1711 } 1712 } 1713 MarkSet = 0; 1714 (void)alarm(TIMERINTVL); 1715 } 1716 1717 int 1718 unix_socket(char *path, int type, mode_t mode) 1719 { 1720 struct sockaddr_un s_un; 1721 char errbuf[512]; 1722 int fd; 1723 mode_t old_umask; 1724 1725 memset(&s_un, 0, sizeof(s_un)); 1726 s_un.sun_family = AF_UNIX; 1727 if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) > 1728 sizeof(s_un.sun_path)) { 1729 snprintf(errbuf, sizeof(errbuf), "socket path too long: %s", 1730 path); 1731 logerror(errbuf); 1732 die(0); 1733 } 1734 1735 if ((fd = socket(AF_UNIX, type, 0)) == -1) { 1736 logerror("socket"); 1737 return (-1); 1738 } 1739 1740 if (Debug) { 1741 if (connect(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == 0 || 1742 errno == EPROTOTYPE) { 1743 close(fd); 1744 errno = EISCONN; 1745 logerror("connect"); 1746 return (-1); 1747 } 1748 } 1749 1750 old_umask = umask(0177); 1751 1752 unlink(path); 1753 if (bind(fd, (struct sockaddr *)&s_un, SUN_LEN(&s_un)) == -1) { 1754 snprintf(errbuf, sizeof(errbuf), "cannot bind %s", path); 1755 logerror(errbuf); 1756 umask(old_umask); 1757 close(fd); 1758 return (-1); 1759 } 1760 1761 umask(old_umask); 1762 1763 if (chmod(path, mode) == -1) { 1764 snprintf(errbuf, sizeof(errbuf), "cannot chmod %s", path); 1765 logerror(errbuf); 1766 close(fd); 1767 unlink(path); 1768 return (-1); 1769 } 1770 1771 return (fd); 1772 } 1773 1774 void 1775 double_rbuf(int fd) 1776 { 1777 socklen_t slen, len; 1778 1779 slen = sizeof(len); 1780 if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &slen) == 0) { 1781 len *= 2; 1782 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, slen); 1783 } 1784 } 1785 1786 static void 1787 ctlconn_cleanup(void) 1788 { 1789 struct filed *f; 1790 1791 if (pfd[PFD_CTLCONN].fd != -1) 1792 close(pfd[PFD_CTLCONN].fd); 1793 1794 pfd[PFD_CTLCONN].fd = -1; 1795 pfd[PFD_CTLCONN].events = pfd[PFD_CTLCONN].revents = 0; 1796 1797 pfd[PFD_CTLSOCK].events = POLLIN; 1798 1799 if (ctl_state == CTL_WRITING_CONT_REPLY) 1800 for (f = Files; f != NULL; f = f->f_next) 1801 if (f->f_type == F_MEMBUF) 1802 f->f_un.f_mb.f_attached = 0; 1803 1804 ctl_state = ctl_cmd_bytes = ctl_reply_offset = ctl_reply_size = 0; 1805 } 1806 1807 void 1808 ctlsock_accept_handler(void) 1809 { 1810 int fd, flags; 1811 1812 dprintf("Accepting control connection\n"); 1813 fd = accept(pfd[PFD_CTLSOCK].fd, NULL, NULL); 1814 if (fd == -1) { 1815 if (errno != EINTR && errno != ECONNABORTED) 1816 logerror("accept ctlsock"); 1817 return; 1818 } 1819 1820 ctlconn_cleanup(); 1821 1822 /* Only one connection at a time */ 1823 pfd[PFD_CTLSOCK].events = pfd[PFD_CTLSOCK].revents = 0; 1824 1825 if ((flags = fcntl(fd, F_GETFL)) == -1 || 1826 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { 1827 logerror("fcntl ctlconn"); 1828 close(fd); 1829 return; 1830 } 1831 1832 pfd[PFD_CTLCONN].fd = fd; 1833 pfd[PFD_CTLCONN].events = POLLIN; 1834 ctl_state = CTL_READING_CMD; 1835 ctl_cmd_bytes = 0; 1836 } 1837 1838 static struct filed 1839 *find_membuf_log(const char *name) 1840 { 1841 struct filed *f; 1842 1843 for (f = Files; f != NULL; f = f->f_next) { 1844 if (f->f_type == F_MEMBUF && 1845 strcmp(f->f_un.f_mb.f_mname, name) == 0) 1846 break; 1847 } 1848 return (f); 1849 } 1850 1851 void 1852 ctlconn_read_handler(void) 1853 { 1854 ssize_t n; 1855 struct filed *f; 1856 u_int32_t flags = 0; 1857 struct ctl_reply_hdr *reply_hdr = (struct ctl_reply_hdr *)ctl_reply; 1858 1859 if (ctl_state == CTL_WRITING_REPLY || 1860 ctl_state == CTL_WRITING_CONT_REPLY) { 1861 /* client has closed the connection */ 1862 ctlconn_cleanup(); 1863 return; 1864 } 1865 1866 retry: 1867 n = read(pfd[PFD_CTLCONN].fd, (char*)&ctl_cmd + ctl_cmd_bytes, 1868 sizeof(ctl_cmd) - ctl_cmd_bytes); 1869 switch (n) { 1870 case -1: 1871 if (errno == EINTR) 1872 goto retry; 1873 logerror("ctlconn read"); 1874 /* FALLTHROUGH */ 1875 case 0: 1876 ctlconn_cleanup(); 1877 return; 1878 default: 1879 ctl_cmd_bytes += n; 1880 } 1881 1882 if (ctl_cmd_bytes < sizeof(ctl_cmd)) 1883 return; 1884 1885 if (ntohl(ctl_cmd.version) != CTL_VERSION) { 1886 logerror("Unknown client protocol version"); 1887 ctlconn_cleanup(); 1888 return; 1889 } 1890 1891 /* Ensure that logname is \0 terminated */ 1892 if (memchr(ctl_cmd.logname, '\0', sizeof(ctl_cmd.logname)) == NULL) { 1893 logerror("Corrupt ctlsock command"); 1894 ctlconn_cleanup(); 1895 return; 1896 } 1897 1898 *reply_text = '\0'; 1899 1900 ctl_reply_size = ctl_reply_offset = 0; 1901 memset(reply_hdr, '\0', sizeof(*reply_hdr)); 1902 1903 ctl_cmd.cmd = ntohl(ctl_cmd.cmd); 1904 dprintf("ctlcmd %x logname \"%s\"\n", ctl_cmd.cmd, ctl_cmd.logname); 1905 1906 switch (ctl_cmd.cmd) { 1907 case CMD_READ: 1908 case CMD_READ_CLEAR: 1909 case CMD_READ_CONT: 1910 case CMD_FLAGS: 1911 f = find_membuf_log(ctl_cmd.logname); 1912 if (f == NULL) { 1913 strlcpy(reply_text, "No such log\n", MAX_MEMBUF); 1914 } else { 1915 if (ctl_cmd.cmd != CMD_FLAGS) { 1916 ringbuf_to_string(reply_text, MAX_MEMBUF, 1917 f->f_un.f_mb.f_rb); 1918 } 1919 if (f->f_un.f_mb.f_overflow) 1920 flags |= CTL_HDR_FLAG_OVERFLOW; 1921 if (ctl_cmd.cmd == CMD_READ_CLEAR) { 1922 ringbuf_clear(f->f_un.f_mb.f_rb); 1923 f->f_un.f_mb.f_overflow = 0; 1924 } 1925 if (ctl_cmd.cmd == CMD_READ_CONT) { 1926 f->f_un.f_mb.f_attached = 1; 1927 tailify_replytext(reply_text, 10); 1928 } 1929 } 1930 break; 1931 case CMD_CLEAR: 1932 f = find_membuf_log(ctl_cmd.logname); 1933 if (f == NULL) { 1934 strlcpy(reply_text, "No such log\n", MAX_MEMBUF); 1935 } else { 1936 ringbuf_clear(f->f_un.f_mb.f_rb); 1937 if (f->f_un.f_mb.f_overflow) 1938 flags |= CTL_HDR_FLAG_OVERFLOW; 1939 f->f_un.f_mb.f_overflow = 0; 1940 strlcpy(reply_text, "Log cleared\n", MAX_MEMBUF); 1941 } 1942 break; 1943 case CMD_LIST: 1944 for (f = Files; f != NULL; f = f->f_next) { 1945 if (f->f_type == F_MEMBUF) { 1946 strlcat(reply_text, f->f_un.f_mb.f_mname, 1947 MAX_MEMBUF); 1948 if (f->f_un.f_mb.f_overflow) { 1949 strlcat(reply_text, "*", MAX_MEMBUF); 1950 flags |= CTL_HDR_FLAG_OVERFLOW; 1951 } 1952 strlcat(reply_text, " ", MAX_MEMBUF); 1953 } 1954 } 1955 strlcat(reply_text, "\n", MAX_MEMBUF); 1956 break; 1957 default: 1958 logerror("Unsupported ctlsock command"); 1959 ctlconn_cleanup(); 1960 return; 1961 } 1962 reply_hdr->version = htonl(CTL_VERSION); 1963 reply_hdr->flags = htonl(flags); 1964 1965 ctl_reply_size = CTL_REPLY_SIZE; 1966 dprintf("ctlcmd reply length %lu\n", (u_long)ctl_reply_size); 1967 1968 /* Otherwise, set up to write out reply */ 1969 ctl_state = (ctl_cmd.cmd == CMD_READ_CONT) ? 1970 CTL_WRITING_CONT_REPLY : CTL_WRITING_REPLY; 1971 1972 pfd[PFD_CTLCONN].events = POLLOUT; 1973 1974 /* monitor terminating syslogc */ 1975 pfd[PFD_CTLCONN].events |= POLLIN; 1976 1977 /* another syslogc can kick us out */ 1978 if (ctl_state == CTL_WRITING_CONT_REPLY) 1979 pfd[PFD_CTLSOCK].events = POLLIN; 1980 1981 } 1982 1983 void 1984 ctlconn_write_handler(void) 1985 { 1986 ssize_t n; 1987 1988 if (!(ctl_state == CTL_WRITING_REPLY || 1989 ctl_state == CTL_WRITING_CONT_REPLY)) { 1990 /* Shouldn't be here! */ 1991 logerror("ctlconn_write with bad ctl_state"); 1992 ctlconn_cleanup(); 1993 return; 1994 } 1995 retry: 1996 n = write(pfd[PFD_CTLCONN].fd, ctl_reply + ctl_reply_offset, 1997 ctl_reply_size - ctl_reply_offset); 1998 switch (n) { 1999 case -1: 2000 if (errno == EINTR) 2001 goto retry; 2002 if (errno != EPIPE) 2003 logerror("ctlconn write"); 2004 /* FALLTHROUGH */ 2005 case 0: 2006 ctlconn_cleanup(); 2007 return; 2008 default: 2009 ctl_reply_offset += n; 2010 } 2011 if (ctl_reply_offset >= ctl_reply_size) { 2012 /* 2013 * Make space in the buffer for continous writes. 2014 * Set offset behind reply header to skip it 2015 */ 2016 if (ctl_state == CTL_WRITING_CONT_REPLY) { 2017 *reply_text = '\0'; 2018 ctl_reply_offset = ctl_reply_size = CTL_REPLY_SIZE; 2019 2020 /* Now is a good time to report dropped lines */ 2021 if (membuf_drop) { 2022 strlcat(reply_text, "<ENOBUFS>\n", MAX_MEMBUF); 2023 ctl_reply_size = CTL_REPLY_SIZE; 2024 membuf_drop = 0; 2025 } else { 2026 /* Nothing left to write */ 2027 pfd[PFD_CTLCONN].events = POLLIN; 2028 } 2029 } else 2030 ctlconn_cleanup(); 2031 } 2032 } 2033 2034 /* Shorten replytext to number of lines */ 2035 void 2036 tailify_replytext(char *replytext, int lines) 2037 { 2038 char *start, *nl; 2039 int count = 0; 2040 start = nl = replytext; 2041 2042 while ((nl = strchr(nl, '\n')) != NULL) { 2043 nl++; 2044 if (++count > lines) { 2045 start = strchr(start, '\n'); 2046 start++; 2047 } 2048 } 2049 if (start != replytext) { 2050 int len = strlen(start); 2051 memmove(replytext, start, len); 2052 *(replytext + len) = '\0'; 2053 } 2054 } 2055 2056 void 2057 logto_ctlconn(char *line) 2058 { 2059 size_t l; 2060 2061 if (membuf_drop) 2062 return; 2063 2064 l = strlen(line); 2065 if (l + 2 > (CTL_REPLY_MAXSIZE - ctl_reply_size)) { 2066 /* remember line drops for later report */ 2067 membuf_drop = 1; 2068 return; 2069 } 2070 memcpy(ctl_reply + ctl_reply_size, line, l); 2071 memcpy(ctl_reply + ctl_reply_size + l, "\n", 2); 2072 ctl_reply_size += l + 1; 2073 pfd[PFD_CTLCONN].events |= POLLOUT; 2074 } 2075