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