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