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