1 /* $NetBSD: syslogd.c,v 1.60 2003/08/07 11:25:44 agc Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1988, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993, 1994\n\ 35 The Regents of the University of California. All rights reserved.\n"); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94"; 41 #else 42 __RCSID("$NetBSD: syslogd.c,v 1.60 2003/08/07 11:25:44 agc Exp $"); 43 #endif 44 #endif /* not lint */ 45 46 /* 47 * syslogd -- log system messages 48 * 49 * This program implements a system log. It takes a series of lines. 50 * Each line may have a priority, signified as "<n>" as 51 * the first characters of the line. If this is 52 * not present, a default priority is used. 53 * 54 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will 55 * cause it to reread its configuration file. 56 * 57 * Defined Constants: 58 * 59 * MAXLINE -- the maximimum line length that can be handled. 60 * DEFUPRI -- the default priority for user messages 61 * DEFSPRI -- the default priority for kernel messages 62 * 63 * Author: Eric Allman 64 * extensive changes by Ralph Campbell 65 * more extensive changes by Eric Allman (again) 66 */ 67 68 #define MAXLINE 1024 /* maximum line length */ 69 #define MAXSVLINE 120 /* maximum saved line length */ 70 #define DEFUPRI (LOG_USER|LOG_NOTICE) 71 #define DEFSPRI (LOG_KERN|LOG_CRIT) 72 #define TIMERINTVL 30 /* interval for checking flush, mark */ 73 #define TTYMSGTIME 1 /* timeout passed to ttymsg */ 74 75 #include <sys/param.h> 76 #include <sys/socket.h> 77 #include <sys/sysctl.h> 78 #include <sys/types.h> 79 #include <sys/un.h> 80 #include <sys/wait.h> 81 82 #include <netinet/in.h> 83 84 #include <ctype.h> 85 #include <errno.h> 86 #include <fcntl.h> 87 #include <grp.h> 88 #include <locale.h> 89 #include <netdb.h> 90 #include <poll.h> 91 #include <pwd.h> 92 #include <signal.h> 93 #include <stdarg.h> 94 #include <stdio.h> 95 #include <stdlib.h> 96 #include <string.h> 97 #include <unistd.h> 98 #include <util.h> 99 100 #include "utmpentry.h" 101 #include "pathnames.h" 102 103 #define SYSLOG_NAMES 104 #include <sys/syslog.h> 105 106 #ifdef LIBWRAP 107 #include <tcpd.h> 108 109 int allow_severity = LOG_AUTH|LOG_INFO; 110 int deny_severity = LOG_AUTH|LOG_WARNING; 111 #endif 112 113 char *ConfFile = _PATH_LOGCONF; 114 char ctty[] = _PATH_CONSOLE; 115 116 #define FDMASK(fd) (1 << (fd)) 117 118 #define dprintf if (Debug) printf 119 120 #define MAXUNAMES 20 /* maximum number of user names */ 121 122 /* 123 * Flags to logmsg(). 124 */ 125 126 #define IGN_CONS 0x001 /* don't print on console */ 127 #define SYNC_FILE 0x002 /* do fsync on file after printing */ 128 #define ADDDATE 0x004 /* add a date to the message */ 129 #define MARK 0x008 /* this message is a mark */ 130 131 /* 132 * This structure represents the files that will have log 133 * copies printed. 134 */ 135 136 struct filed { 137 struct filed *f_next; /* next in linked list */ 138 short f_type; /* entry type, see below */ 139 short f_file; /* file descriptor */ 140 time_t f_time; /* time this was last written */ 141 u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ 142 union { 143 char f_uname[MAXUNAMES][UT_NAMESIZE+1]; 144 struct { 145 char f_hname[MAXHOSTNAMELEN+1]; 146 struct addrinfo *f_addr; 147 } f_forw; /* forwarding address */ 148 char f_fname[MAXPATHLEN]; 149 } f_un; 150 char f_prevline[MAXSVLINE]; /* last message logged */ 151 char f_lasttime[16]; /* time of last occurrence */ 152 char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */ 153 int f_prevpri; /* pri of f_prevline */ 154 int f_prevlen; /* length of f_prevline */ 155 int f_prevcount; /* repetition cnt of prevline */ 156 int f_repeatcount; /* number of "repeated" msgs */ 157 }; 158 159 /* 160 * Intervals at which we flush out "message repeated" messages, 161 * in seconds after previous message is logged. After each flush, 162 * we move to the next interval until we reach the largest. 163 */ 164 int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ 165 #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) 166 #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) 167 #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ 168 (f)->f_repeatcount = MAXREPEAT; \ 169 } 170 171 /* values for f_type */ 172 #define F_UNUSED 0 /* unused entry */ 173 #define F_FILE 1 /* regular file */ 174 #define F_TTY 2 /* terminal */ 175 #define F_CONSOLE 3 /* console terminal */ 176 #define F_FORW 4 /* remote machine */ 177 #define F_USERS 5 /* list of users */ 178 #define F_WALL 6 /* everyone logged on */ 179 180 char *TypeNames[7] = { 181 "UNUSED", "FILE", "TTY", "CONSOLE", 182 "FORW", "USERS", "WALL" 183 }; 184 185 struct filed *Files; 186 struct filed consfile; 187 188 int Debug; /* debug flag */ 189 int daemonized = 0; /* we are not daemonized yet */ 190 char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */ 191 char *LocalDomain; /* our local domain name */ 192 int *finet = NULL; /* Internet datagram sockets */ 193 int Initialized = 0; /* set when we have initialized ourselves */ 194 int MarkInterval = 20 * 60; /* interval between marks in seconds */ 195 int MarkSeq = 0; /* mark sequence number */ 196 int SecureMode = 0; /* listen only on unix domain socks */ 197 int UseNameService = 1; /* make domain name queries */ 198 int NumForwards = 0; /* number of forwarding actions in conf file */ 199 char **LogPaths; /* array of pathnames to read messages from */ 200 201 void cfline(char *, struct filed *); 202 char *cvthname(struct sockaddr_storage *); 203 int decode(const char *, CODE *); 204 void die(int); 205 void domark(int); 206 void fprintlog(struct filed *, int, char *); 207 int getmsgbufsize(void); 208 int* socksetup(int); 209 void init(int); 210 void logerror(const char *, ...); 211 void logmsg(int, char *, char *, int); 212 void printline(char *, char *); 213 void printsys(char *); 214 void reapchild(int); 215 void usage(void); 216 void wallmsg(struct filed *, struct iovec *); 217 int main(int, char *[]); 218 void logpath_add(char ***, int *, int *, char *); 219 void logpath_fileadd(char ***, int *, int *, char *); 220 221 int 222 main(int argc, char *argv[]) 223 { 224 int ch, *funix, i, j, fklog, len, linesize; 225 int *nfinetix, nfklogix, nfunixbaseix, nfds; 226 int funixsize = 0, funixmaxsize = 0; 227 struct sockaddr_un sunx, fromunix; 228 struct sockaddr_storage frominet; 229 char *p, *line, **pp; 230 struct pollfd *readfds; 231 uid_t uid = 0; 232 gid_t gid = 0; 233 char *user = NULL; 234 char *group = NULL; 235 char *root = "/"; 236 char *endp; 237 struct group *gr; 238 struct passwd *pw; 239 unsigned long l; 240 241 (void)setlocale(LC_ALL, ""); 242 243 while ((ch = getopt(argc, argv, "dnsf:m:p:P:u:g:t:")) != -1) 244 switch(ch) { 245 case 'd': /* debug */ 246 Debug++; 247 break; 248 case 'f': /* configuration file */ 249 ConfFile = optarg; 250 break; 251 case 'g': 252 group = optarg; 253 if (*group == '\0') 254 usage(); 255 break; 256 case 'm': /* mark interval */ 257 MarkInterval = atoi(optarg) * 60; 258 break; 259 case 'n': /* turn off DNS queries */ 260 UseNameService = 0; 261 break; 262 case 'p': /* path */ 263 logpath_add(&LogPaths, &funixsize, 264 &funixmaxsize, optarg); 265 break; 266 case 'P': /* file of paths */ 267 logpath_fileadd(&LogPaths, &funixsize, 268 &funixmaxsize, optarg); 269 break; 270 case 's': /* no network listen mode */ 271 SecureMode++; 272 break; 273 case 't': 274 root = optarg; 275 if (*root == '\0') 276 usage(); 277 break; 278 case 'u': 279 user = optarg; 280 if (*user == '\0') 281 usage(); 282 break; 283 case '?': 284 default: 285 usage(); 286 } 287 if ((argc -= optind) != 0) 288 usage(); 289 290 setlinebuf(stdout); 291 292 if (user != NULL) { 293 if (isdigit((unsigned char)*user)) { 294 errno = 0; 295 endp = NULL; 296 l = strtoul(user, &endp, 0); 297 if (errno || *endp != '\0') 298 goto getuser; 299 uid = (uid_t)l; 300 if (uid != l) { 301 errno = 0; 302 logerror("UID out of range"); 303 die(0); 304 } 305 } else { 306 getuser: 307 if ((pw = getpwnam(user)) != NULL) { 308 uid = pw->pw_uid; 309 } else { 310 errno = 0; 311 logerror("Cannot find user `%s'", user); 312 die (0); 313 } 314 } 315 } 316 317 if (group != NULL) { 318 if (isdigit((unsigned char)*group)) { 319 errno = 0; 320 endp = NULL; 321 l = strtoul(group, &endp, 0); 322 if (errno || *endp != '\0') 323 goto getgroup; 324 gid = (gid_t)l; 325 if (gid != l) { 326 errno = 0; 327 logerror("GID out of range"); 328 die(0); 329 } 330 } else { 331 getgroup: 332 if ((gr = getgrnam(group)) != NULL) { 333 gid = gr->gr_gid; 334 } else { 335 errno = 0; 336 logerror("Cannot find group `%s'", group); 337 die(0); 338 } 339 } 340 } 341 342 if (access (root, F_OK | R_OK)) { 343 logerror("Cannot access `%s'", root); 344 die (0); 345 } 346 347 consfile.f_type = F_CONSOLE; 348 (void)strlcpy(consfile.f_un.f_fname, ctty, 349 sizeof(consfile.f_un.f_fname)); 350 (void)gethostname(LocalHostName, sizeof(LocalHostName)); 351 LocalHostName[sizeof(LocalHostName) - 1] = '\0'; 352 if ((p = strchr(LocalHostName, '.')) != NULL) { 353 *p++ = '\0'; 354 LocalDomain = p; 355 } else 356 LocalDomain = ""; 357 linesize = getmsgbufsize(); 358 if (linesize < MAXLINE) 359 linesize = MAXLINE; 360 linesize++; 361 line = malloc(linesize); 362 if (line == NULL) { 363 logerror("Couldn't allocate line buffer"); 364 die(0); 365 } 366 (void)signal(SIGTERM, die); 367 (void)signal(SIGINT, Debug ? die : SIG_IGN); 368 (void)signal(SIGQUIT, Debug ? die : SIG_IGN); 369 (void)signal(SIGCHLD, reapchild); 370 (void)signal(SIGALRM, domark); 371 (void)alarm(TIMERINTVL); 372 373 #ifndef SUN_LEN 374 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 375 #endif 376 if (funixsize == 0) 377 logpath_add(&LogPaths, &funixsize, 378 &funixmaxsize, _PATH_LOG); 379 funix = (int *)malloc(sizeof(int) * funixsize); 380 if (funix == NULL) { 381 logerror("Couldn't allocate funix descriptors"); 382 die(0); 383 } 384 for (j = 0, pp = LogPaths; *pp; pp++, j++) { 385 dprintf("Making unix dgram socket `%s'\n", *pp); 386 unlink(*pp); 387 memset(&sunx, 0, sizeof(sunx)); 388 sunx.sun_family = AF_LOCAL; 389 (void)strncpy(sunx.sun_path, *pp, sizeof(sunx.sun_path)); 390 funix[j] = socket(AF_LOCAL, SOCK_DGRAM, 0); 391 if (funix[j] < 0 || bind(funix[j], 392 (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 || 393 chmod(*pp, 0666) < 0) { 394 logerror("Cannot create `%s'", *pp); 395 die(0); 396 } 397 dprintf("Listening on unix dgram socket `%s'\n", *pp); 398 } 399 400 init(0); 401 402 if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0) { 403 dprintf("Can't open `%s' (%d)\n", _PATH_KLOG, errno); 404 } else { 405 dprintf("Listening on kernel log `%s'\n", _PATH_KLOG); 406 } 407 408 dprintf("Off & running....\n"); 409 410 (void)signal(SIGHUP, init); 411 412 /* setup pollfd set. */ 413 readfds = (struct pollfd *)malloc(sizeof(struct pollfd) * 414 (funixsize + (finet ? *finet : 0) + 1)); 415 if (readfds == NULL) { 416 logerror("Couldn't allocate pollfds"); 417 die(0); 418 } 419 nfds = 0; 420 if (fklog >= 0) { 421 nfklogix = nfds++; 422 readfds[nfklogix].fd = fklog; 423 readfds[nfklogix].events = POLLIN | POLLPRI; 424 } 425 if (finet && !SecureMode) { 426 nfinetix = malloc(*finet * sizeof(*nfinetix)); 427 for (j = 0; j < *finet; j++) { 428 nfinetix[j] = nfds++; 429 readfds[nfinetix[j]].fd = finet[j+1]; 430 readfds[nfinetix[j]].events = POLLIN | POLLPRI; 431 } 432 } 433 nfunixbaseix = nfds; 434 for (j = 0, pp = LogPaths; *pp; pp++) { 435 readfds[nfds].fd = funix[j++]; 436 readfds[nfds++].events = POLLIN | POLLPRI; 437 } 438 439 /* 440 * All files are open, we can drop privileges and chroot 441 */ 442 dprintf("Attempt to chroot to `%s'\n", root); 443 if (chroot(root)) { 444 logerror("Failed to chroot to `%s'", root); 445 die(0); 446 } 447 dprintf("Attempt to set GID/EGID to `%d'\n", gid); 448 if (setgid(gid) || setegid(gid)) { 449 logerror("Failed to set gid to `%d'", gid); 450 die(0); 451 } 452 dprintf("Attempt to set UID/EUID to `%d'\n", uid); 453 if (setuid(uid) || seteuid(uid)) { 454 logerror("Failed to set uid to `%d'", uid); 455 die(0); 456 } 457 458 /* 459 * We cannot detach from the terminal before we are sure we won't 460 * have a fatal error, because error message would not go to the 461 * terminal and would not be logged because syslogd dies. 462 * All die() calls are behind us, we can call daemon() 463 */ 464 if (!Debug) { 465 (void)daemon(0, 0); 466 daemonized = 1; 467 468 /* tuck my process id away, if i'm not in debug mode */ 469 pidfile(NULL); 470 } 471 472 for (;;) { 473 int rv; 474 475 rv = poll(readfds, nfds, INFTIM); 476 if (rv == 0) 477 continue; 478 if (rv < 0) { 479 if (errno != EINTR) 480 logerror("poll() failed"); 481 continue; 482 } 483 dprintf("Got a message (%d)\n", rv); 484 if (fklog >= 0 && 485 (readfds[nfklogix].revents & (POLLIN | POLLPRI))) { 486 dprintf("Kernel log active\n"); 487 i = read(fklog, line, linesize - 1); 488 if (i > 0) { 489 line[i] = '\0'; 490 printsys(line); 491 } else if (i < 0 && errno != EINTR) { 492 logerror("klog failed"); 493 fklog = -1; 494 } 495 } 496 for (j = 0, pp = LogPaths; *pp; pp++, j++) { 497 if ((readfds[nfunixbaseix + j].revents & 498 (POLLIN | POLLPRI)) == 0) 499 continue; 500 501 dprintf("Unix socket (%s) active\n", *pp); 502 len = sizeof(fromunix); 503 i = recvfrom(funix[j], line, MAXLINE, 0, 504 (struct sockaddr *)&fromunix, &len); 505 if (i > 0) { 506 line[i] = '\0'; 507 printline(LocalHostName, line); 508 } else if (i < 0 && errno != EINTR) { 509 logerror("recvfrom() unix `%s'", *pp); 510 } 511 } 512 if (finet && !SecureMode) { 513 for (j = 0; j < *finet; j++) { 514 if (readfds[nfinetix[j]].revents & 515 (POLLIN | POLLPRI)) { 516 #ifdef LIBWRAP 517 struct request_info req; 518 #endif 519 int reject = 0; 520 521 dprintf("inet socket active\n"); 522 523 #ifdef LIBWRAP 524 request_init(&req, RQ_DAEMON, "syslogd", 525 RQ_FILE, finet[j + 1], NULL); 526 fromhost(&req); 527 reject = !hosts_access(&req); 528 if (reject) 529 dprintf("access denied\n"); 530 #endif 531 532 len = sizeof(frominet); 533 i = recvfrom(finet[j+1], line, MAXLINE, 534 0, (struct sockaddr *)&frominet, 535 &len); 536 if (i == 0 || (i < 0 && errno == EINTR)) 537 continue; 538 else if (i < 0) { 539 logerror("recvfrom inet"); 540 continue; 541 } 542 543 line[i] = '\0'; 544 if (!reject) 545 printline(cvthname(&frominet), 546 line); 547 } 548 } 549 } 550 } 551 } 552 553 void 554 usage(void) 555 { 556 557 (void)fprintf(stderr, 558 "usage: %s [-dns] [-f config_file] [-g group] [-m mark_interval]\n" 559 "\t[-P file_list] [-p log_socket [-p log_socket2 ...]]\n" 560 "\t[-t chroot_dir] [-u user]\n", getprogname()); 561 exit(1); 562 } 563 564 /* 565 * given a pointer to an array of char *'s, a pointer to it's current 566 * size and current allocated max size, and a new char * to add, add 567 * it, update everything as necessary, possibly allocating a new array 568 */ 569 void 570 logpath_add(char ***lp, int *szp, int *maxszp, char *new) 571 { 572 573 dprintf("Adding `%s' to the %p logpath list\n", new, *lp); 574 if (*szp == *maxszp) { 575 if (*maxszp == 0) { 576 *maxszp = 4; /* start of with enough for now */ 577 *lp = NULL; 578 } else 579 *maxszp *= 2; 580 *lp = realloc(*lp, sizeof(char *) * (*maxszp + 1)); 581 if (*lp == NULL) { 582 logerror("Couldn't allocate line buffer"); 583 die(0); 584 } 585 } 586 if (((*lp)[(*szp)++] = strdup(new)) == NULL) { 587 logerror("Couldn't allocate logpath"); 588 die(0); 589 } 590 (*lp)[(*szp)] = NULL; /* always keep it NULL terminated */ 591 } 592 593 /* do a file of log sockets */ 594 void 595 logpath_fileadd(char ***lp, int *szp, int *maxszp, char *file) 596 { 597 FILE *fp; 598 char *line; 599 size_t len; 600 601 fp = fopen(file, "r"); 602 if (fp == NULL) { 603 logerror("Could not open socket file list `%s'", file); 604 die(0); 605 } 606 607 while ((line = fgetln(fp, &len))) { 608 line[len - 1] = 0; 609 logpath_add(lp, szp, maxszp, line); 610 } 611 fclose(fp); 612 } 613 614 /* 615 * Take a raw input line, decode the message, and print the message 616 * on the appropriate log files. 617 */ 618 void 619 printline(char *hname, char *msg) 620 { 621 int c, pri; 622 char *p, *q, line[MAXLINE + 1]; 623 624 /* test for special codes */ 625 pri = DEFUPRI; 626 p = msg; 627 if (*p == '<') { 628 pri = 0; 629 while (isdigit(*++p)) 630 pri = 10 * pri + (*p - '0'); 631 if (*p == '>') 632 ++p; 633 } 634 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 635 pri = DEFUPRI; 636 637 /* don't allow users to log kernel messages */ 638 if (LOG_FAC(pri) == LOG_KERN) 639 pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri)); 640 641 q = line; 642 643 while ((c = *p++) != '\0' && 644 q < &line[sizeof(line) - 2]) { 645 c &= 0177; 646 if (iscntrl(c)) 647 if (c == '\n') 648 *q++ = ' '; 649 else if (c == '\t') 650 *q++ = '\t'; 651 else { 652 *q++ = '^'; 653 *q++ = c ^ 0100; 654 } 655 else 656 *q++ = c; 657 } 658 *q = '\0'; 659 660 logmsg(pri, line, hname, 0); 661 } 662 663 /* 664 * Take a raw input line from /dev/klog, split and format similar to syslog(). 665 */ 666 void 667 printsys(char *msg) 668 { 669 int c, pri, flags; 670 char *lp, *p, *q, line[MAXLINE + 1]; 671 672 (void)strlcpy(line, _PATH_UNIX, sizeof(line)); 673 (void)strlcat(line, ": ", sizeof(line)); 674 lp = line + strlen(line); 675 for (p = msg; *p != '\0'; ) { 676 flags = SYNC_FILE | ADDDATE; /* fsync file after write */ 677 pri = DEFSPRI; 678 if (*p == '<') { 679 pri = 0; 680 while (isdigit(*++p)) 681 pri = 10 * pri + (*p - '0'); 682 if (*p == '>') 683 ++p; 684 } else { 685 /* kernel printf's come out on console */ 686 flags |= IGN_CONS; 687 } 688 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 689 pri = DEFSPRI; 690 q = lp; 691 while (*p != '\0' && (c = *p++) != '\n' && 692 q < &line[MAXLINE]) 693 *q++ = c; 694 *q = '\0'; 695 logmsg(pri, line, LocalHostName, flags); 696 } 697 } 698 699 time_t now; 700 701 /* 702 * Log a message to the appropriate log files, users, etc. based on 703 * the priority. 704 */ 705 void 706 logmsg(int pri, char *msg, char *from, int flags) 707 { 708 struct filed *f; 709 int fac, msglen, omask, prilev; 710 char *timestamp; 711 712 dprintf("logmsg: pri 0%o, flags 0x%x, from %s, msg %s\n", 713 pri, flags, from, msg); 714 715 omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); 716 717 /* 718 * Check to see if msg looks non-standard. 719 */ 720 msglen = strlen(msg); 721 if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || 722 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') 723 flags |= ADDDATE; 724 725 (void)time(&now); 726 if (flags & ADDDATE) 727 timestamp = ctime(&now) + 4; 728 else { 729 timestamp = msg; 730 msg += 16; 731 msglen -= 16; 732 } 733 734 /* extract facility and priority level */ 735 if (flags & MARK) 736 fac = LOG_NFACILITIES; 737 else 738 fac = LOG_FAC(pri); 739 prilev = LOG_PRI(pri); 740 741 /* log the message to the particular outputs */ 742 if (!Initialized) { 743 f = &consfile; 744 f->f_file = open(ctty, O_WRONLY, 0); 745 746 if (f->f_file >= 0) { 747 fprintlog(f, flags, msg); 748 (void)close(f->f_file); 749 } 750 (void)sigsetmask(omask); 751 return; 752 } 753 for (f = Files; f; f = f->f_next) { 754 /* skip messages that are incorrect priority */ 755 if (f->f_pmask[fac] < prilev || 756 f->f_pmask[fac] == INTERNAL_NOPRI) 757 continue; 758 759 if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) 760 continue; 761 762 /* don't output marks to recently written files */ 763 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) 764 continue; 765 766 /* 767 * suppress duplicate lines to this file 768 */ 769 if ((flags & MARK) == 0 && msglen == f->f_prevlen && 770 !strcmp(msg, f->f_prevline) && 771 !strcmp(from, f->f_prevhost)) { 772 (void)strncpy(f->f_lasttime, timestamp, 15); 773 f->f_prevcount++; 774 dprintf("Msg repeated %d times, %ld sec of %d\n", 775 f->f_prevcount, (long)(now - f->f_time), 776 repeatinterval[f->f_repeatcount]); 777 /* 778 * If domark would have logged this by now, 779 * flush it now (so we don't hold isolated messages), 780 * but back off so we'll flush less often 781 * in the future. 782 */ 783 if (now > REPEATTIME(f)) { 784 fprintlog(f, flags, (char *)NULL); 785 BACKOFF(f); 786 } 787 } else { 788 /* new line, save it */ 789 if (f->f_prevcount) 790 fprintlog(f, 0, (char *)NULL); 791 f->f_repeatcount = 0; 792 f->f_prevpri = pri; 793 (void)strncpy(f->f_lasttime, timestamp, 15); 794 (void)strncpy(f->f_prevhost, from, 795 sizeof(f->f_prevhost)); 796 if (msglen < MAXSVLINE) { 797 f->f_prevlen = msglen; 798 (void)strlcpy(f->f_prevline, msg, 799 sizeof(f->f_prevline)); 800 fprintlog(f, flags, (char *)NULL); 801 } else { 802 f->f_prevline[0] = 0; 803 f->f_prevlen = 0; 804 fprintlog(f, flags, msg); 805 } 806 } 807 } 808 (void)sigsetmask(omask); 809 } 810 811 void 812 fprintlog(struct filed *f, int flags, char *msg) 813 { 814 struct iovec iov[6]; 815 struct iovec *v; 816 struct addrinfo *r; 817 int j, l, lsent; 818 char line[MAXLINE + 1], repbuf[80], greetings[200]; 819 820 v = iov; 821 if (f->f_type == F_WALL) { 822 v->iov_base = greetings; 823 v->iov_len = snprintf(greetings, sizeof greetings, 824 "\r\n\7Message from syslogd@%s at %.24s ...\r\n", 825 f->f_prevhost, ctime(&now)); 826 v++; 827 v->iov_base = ""; 828 v->iov_len = 0; 829 v++; 830 } else { 831 v->iov_base = f->f_lasttime; 832 v->iov_len = 15; 833 v++; 834 v->iov_base = " "; 835 v->iov_len = 1; 836 v++; 837 } 838 v->iov_base = f->f_prevhost; 839 v->iov_len = strlen(v->iov_base); 840 v++; 841 v->iov_base = " "; 842 v->iov_len = 1; 843 v++; 844 845 if (msg) { 846 v->iov_base = msg; 847 v->iov_len = strlen(msg); 848 } else if (f->f_prevcount > 1) { 849 v->iov_base = repbuf; 850 v->iov_len = snprintf(repbuf, sizeof repbuf, 851 "last message repeated %d times", f->f_prevcount); 852 } else { 853 v->iov_base = f->f_prevline; 854 v->iov_len = f->f_prevlen; 855 } 856 v++; 857 858 dprintf("Logging to %s", TypeNames[f->f_type]); 859 f->f_time = now; 860 861 switch (f->f_type) { 862 case F_UNUSED: 863 dprintf("\n"); 864 break; 865 866 case F_FORW: 867 dprintf(" %s\n", f->f_un.f_forw.f_hname); 868 /* 869 * check for local vs remote messages 870 * (from FreeBSD PR#bin/7055) 871 */ 872 if (strcmp(f->f_prevhost, LocalHostName)) { 873 l = snprintf(line, sizeof(line) - 1, 874 "<%d>%.15s [%s]: %s", 875 f->f_prevpri, (char *) iov[0].iov_base, 876 f->f_prevhost, (char *) iov[4].iov_base); 877 } else { 878 l = snprintf(line, sizeof(line) - 1, "<%d>%.15s %s", 879 f->f_prevpri, (char *) iov[0].iov_base, 880 (char *) iov[4].iov_base); 881 } 882 if (l > MAXLINE) 883 l = MAXLINE; 884 if (finet) { 885 for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) { 886 for (j = 0; j < *finet; j++) { 887 #if 0 888 /* 889 * should we check AF first, or just 890 * trial and error? FWD 891 */ 892 if (r->ai_family == 893 address_family_of(finet[j+1])) 894 #endif 895 lsent = sendto(finet[j+1], line, l, 0, 896 r->ai_addr, r->ai_addrlen); 897 if (lsent == l) 898 break; 899 } 900 } 901 if (lsent != l) { 902 f->f_type = F_UNUSED; 903 logerror("sendto() failed"); 904 } 905 } 906 break; 907 908 case F_CONSOLE: 909 if (flags & IGN_CONS) { 910 dprintf(" (ignored)\n"); 911 break; 912 } 913 /* FALLTHROUGH */ 914 915 case F_TTY: 916 case F_FILE: 917 dprintf(" %s\n", f->f_un.f_fname); 918 if (f->f_type != F_FILE) { 919 v->iov_base = "\r\n"; 920 v->iov_len = 2; 921 } else { 922 v->iov_base = "\n"; 923 v->iov_len = 1; 924 } 925 again: 926 if (writev(f->f_file, iov, 6) < 0) { 927 int e = errno; 928 (void)close(f->f_file); 929 /* 930 * Check for errors on TTY's due to loss of tty 931 */ 932 if ((e == EIO || e == EBADF) && f->f_type != F_FILE) { 933 f->f_file = open(f->f_un.f_fname, 934 O_WRONLY|O_APPEND, 0); 935 if (f->f_file < 0) { 936 f->f_type = F_UNUSED; 937 logerror(f->f_un.f_fname); 938 } else 939 goto again; 940 } else { 941 f->f_type = F_UNUSED; 942 errno = e; 943 logerror(f->f_un.f_fname); 944 } 945 } else if (flags & SYNC_FILE) 946 (void)fsync(f->f_file); 947 break; 948 949 case F_USERS: 950 case F_WALL: 951 dprintf("\n"); 952 v->iov_base = "\r\n"; 953 v->iov_len = 2; 954 wallmsg(f, iov); 955 break; 956 } 957 f->f_prevcount = 0; 958 } 959 960 /* 961 * WALLMSG -- Write a message to the world at large 962 * 963 * Write the specified message to either the entire 964 * world, or a list of approved users. 965 */ 966 void 967 wallmsg(struct filed *f, struct iovec *iov) 968 { 969 static int reenter; /* avoid calling ourselves */ 970 int i; 971 char *p; 972 static struct utmpentry *ohead = NULL; 973 struct utmpentry *ep; 974 975 if (reenter++) 976 return; 977 978 (void)getutentries(NULL, &ep); 979 if (ep != ohead) { 980 freeutentries(ohead); 981 ohead = ep; 982 } 983 /* NOSTRICT */ 984 for (; ep; ep = ep->next) { 985 if (f->f_type == F_WALL) { 986 if ((p = ttymsg(iov, 6, ep->line, TTYMSGTIME)) 987 != NULL) { 988 errno = 0; /* already in msg */ 989 logerror(p); 990 } 991 continue; 992 } 993 /* should we send the message to this user? */ 994 for (i = 0; i < MAXUNAMES; i++) { 995 if (!f->f_un.f_uname[i][0]) 996 break; 997 if (strcmp(f->f_un.f_uname[i], ep->name) == 0) { 998 if ((p = ttymsg(iov, 6, ep->line, TTYMSGTIME)) 999 != NULL) { 1000 errno = 0; /* already in msg */ 1001 logerror(p); 1002 } 1003 break; 1004 } 1005 } 1006 } 1007 reenter = 0; 1008 } 1009 1010 void 1011 reapchild(int signo) 1012 { 1013 union wait status; 1014 1015 while (wait3((int *)&status, WNOHANG, (struct rusage *)NULL) > 0) 1016 ; 1017 } 1018 1019 /* 1020 * Return a printable representation of a host address. 1021 */ 1022 char * 1023 cvthname(struct sockaddr_storage *f) 1024 { 1025 int error; 1026 char *p; 1027 const int niflag = NI_DGRAM; 1028 static char host[NI_MAXHOST], ip[NI_MAXHOST]; 1029 1030 error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len, 1031 ip, sizeof ip, NULL, 0, NI_NUMERICHOST|niflag); 1032 1033 dprintf("cvthname(%s)\n", ip); 1034 1035 if (error) { 1036 dprintf("Malformed from address %s\n", gai_strerror(error)); 1037 return ("???"); 1038 } 1039 1040 if (!UseNameService) 1041 return (ip); 1042 1043 error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len, 1044 host, sizeof host, NULL, 0, niflag); 1045 if (error) { 1046 dprintf("Host name for your address (%s) unknown\n", ip); 1047 return (ip); 1048 } 1049 if ((p = strchr(host, '.')) && strcmp(p + 1, LocalDomain) == 0) 1050 *p = '\0'; 1051 return (host); 1052 } 1053 1054 void 1055 domark(int signo) 1056 { 1057 struct filed *f; 1058 1059 now = time((time_t *)NULL); 1060 MarkSeq += TIMERINTVL; 1061 if (MarkSeq >= MarkInterval) { 1062 logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK); 1063 MarkSeq = 0; 1064 } 1065 1066 for (f = Files; f; f = f->f_next) { 1067 if (f->f_prevcount && now >= REPEATTIME(f)) { 1068 dprintf("Flush %s: repeated %d times, %d sec.\n", 1069 TypeNames[f->f_type], f->f_prevcount, 1070 repeatinterval[f->f_repeatcount]); 1071 fprintlog(f, 0, (char *)NULL); 1072 BACKOFF(f); 1073 } 1074 } 1075 (void)alarm(TIMERINTVL); 1076 } 1077 1078 /* 1079 * Print syslogd errors some place. 1080 */ 1081 void 1082 logerror(const char *fmt, ...) 1083 { 1084 va_list ap; 1085 char tmpbuf[BUFSIZ]; 1086 char buf[BUFSIZ]; 1087 1088 va_start(ap, fmt); 1089 1090 (void)vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap); 1091 1092 va_end(ap); 1093 1094 if (errno) 1095 (void)snprintf(buf, sizeof(buf), "syslogd: %s: %s", 1096 tmpbuf, strerror(errno)); 1097 else 1098 (void)snprintf(buf, sizeof(buf), "syslogd: %s", tmpbuf); 1099 1100 if (daemonized) 1101 logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); 1102 if (!daemonized && Debug) 1103 dprintf("%s\n", buf); 1104 if (!daemonized && !Debug) 1105 printf("%s\n", buf); 1106 1107 return; 1108 } 1109 1110 void 1111 die(int signo) 1112 { 1113 struct filed *f; 1114 char **p; 1115 1116 for (f = Files; f != NULL; f = f->f_next) { 1117 /* flush any pending output */ 1118 if (f->f_prevcount) 1119 fprintlog(f, 0, (char *)NULL); 1120 } 1121 errno = 0; 1122 if (signo) 1123 logerror("Exiting on signal %d", signo); 1124 else 1125 logerror("Fatal error, exiting"); 1126 for (p = LogPaths; p && *p; p++) 1127 unlink(*p); 1128 exit(0); 1129 } 1130 1131 /* 1132 * INIT -- Initialize syslogd from configuration table 1133 */ 1134 void 1135 init(int signo) 1136 { 1137 int i; 1138 FILE *cf; 1139 struct filed *f, *next, **nextp; 1140 char *p; 1141 char cline[LINE_MAX]; 1142 1143 dprintf("init\n"); 1144 1145 /* 1146 * Close all open log files. 1147 */ 1148 Initialized = 0; 1149 for (f = Files; f != NULL; f = next) { 1150 /* flush any pending output */ 1151 if (f->f_prevcount) 1152 fprintlog(f, 0, (char *)NULL); 1153 1154 switch (f->f_type) { 1155 case F_FILE: 1156 case F_TTY: 1157 case F_CONSOLE: 1158 (void)close(f->f_file); 1159 break; 1160 case F_FORW: 1161 if (f->f_un.f_forw.f_addr) 1162 freeaddrinfo(f->f_un.f_forw.f_addr); 1163 break; 1164 } 1165 next = f->f_next; 1166 free((char *)f); 1167 } 1168 Files = NULL; 1169 nextp = &Files; 1170 1171 /* 1172 * Close all open sockets 1173 */ 1174 1175 if (finet) { 1176 for (i = 0; i < *finet; i++) { 1177 if (close(finet[i+1]) < 0) { 1178 logerror("close() failed"); 1179 die(0); 1180 } 1181 } 1182 } 1183 1184 /* 1185 * Reset counter of forwarding actions 1186 */ 1187 1188 NumForwards=0; 1189 1190 /* open the configuration file */ 1191 if ((cf = fopen(ConfFile, "r")) == NULL) { 1192 dprintf("Cannot open `%s'\n", ConfFile); 1193 *nextp = (struct filed *)calloc(1, sizeof(*f)); 1194 cfline("*.ERR\t/dev/console", *nextp); 1195 (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); 1196 cfline("*.PANIC\t*", (*nextp)->f_next); 1197 Initialized = 1; 1198 return; 1199 } 1200 1201 /* 1202 * Foreach line in the conf table, open that file. 1203 */ 1204 f = NULL; 1205 while (fgets(cline, sizeof(cline), cf) != NULL) { 1206 /* 1207 * check for end-of-section, comments, strip off trailing 1208 * spaces and newline character. 1209 */ 1210 for (p = cline; isspace(*p); ++p) 1211 continue; 1212 if (*p == '\0' || *p == '#') 1213 continue; 1214 for (p = strchr(cline, '\0'); isspace(*--p);) 1215 continue; 1216 *++p = '\0'; 1217 f = (struct filed *)calloc(1, sizeof(*f)); 1218 *nextp = f; 1219 nextp = &f->f_next; 1220 cfline(cline, f); 1221 } 1222 1223 /* close the configuration file */ 1224 (void)fclose(cf); 1225 1226 Initialized = 1; 1227 1228 if (Debug) { 1229 for (f = Files; f; f = f->f_next) { 1230 for (i = 0; i <= LOG_NFACILITIES; i++) 1231 if (f->f_pmask[i] == INTERNAL_NOPRI) 1232 printf("X "); 1233 else 1234 printf("%d ", f->f_pmask[i]); 1235 printf("%s: ", TypeNames[f->f_type]); 1236 switch (f->f_type) { 1237 case F_FILE: 1238 case F_TTY: 1239 case F_CONSOLE: 1240 printf("%s", f->f_un.f_fname); 1241 break; 1242 1243 case F_FORW: 1244 printf("%s", f->f_un.f_forw.f_hname); 1245 break; 1246 1247 case F_USERS: 1248 for (i = 0; 1249 i < MAXUNAMES && *f->f_un.f_uname[i]; i++) 1250 printf("%s, ", f->f_un.f_uname[i]); 1251 break; 1252 } 1253 printf("\n"); 1254 } 1255 } 1256 1257 finet = socksetup(PF_UNSPEC); 1258 if (finet) { 1259 if (SecureMode) { 1260 for (i = 0; i < *finet; i++) { 1261 if (shutdown(finet[i+1], SHUT_RD) < 0) { 1262 logerror("shutdown() failed"); 1263 die(0); 1264 } 1265 } 1266 } else 1267 dprintf("Listening on inet and/or inet6 socket\n"); 1268 dprintf("Sending on inet and/or inet6 socket\n"); 1269 } 1270 1271 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); 1272 dprintf("syslogd: restarted\n"); 1273 } 1274 1275 /* 1276 * Crack a configuration file line 1277 */ 1278 void 1279 cfline(char *line, struct filed *f) 1280 { 1281 struct addrinfo hints, *res; 1282 int error, i, pri; 1283 char *bp, *p, *q; 1284 char buf[MAXLINE]; 1285 int sp_err; 1286 1287 dprintf("cfline(%s)\n", line); 1288 1289 errno = 0; /* keep strerror() stuff out of logerror messages */ 1290 1291 /* clear out file entry */ 1292 memset(f, 0, sizeof(*f)); 1293 for (i = 0; i <= LOG_NFACILITIES; i++) 1294 f->f_pmask[i] = INTERNAL_NOPRI; 1295 1296 /* 1297 * There should not be any space before the log facility. 1298 * Check this is okay, complain and fix if it is not. 1299 */ 1300 q = line; 1301 if (isblank((unsigned char)*line)) { 1302 errno = 0; 1303 logerror( 1304 "Warning: `%s' space or tab before the log facility", 1305 line); 1306 /* Fix: strip all spaces/tabs before the log facility */ 1307 while (*q++ && isblank((unsigned char)*q)); 1308 line = q; 1309 } 1310 1311 /* 1312 * q is now at the first char of the log facility 1313 * There should be at least one tab after the log facility 1314 * Check this is okay, and complain and fix if it is not. 1315 */ 1316 q = line + strlen(line); 1317 while (!isblank((unsigned char)*q) && (q != line)) 1318 q--; 1319 if ((q == line) && strlen(line)) { 1320 /* No tabs or space in a non empty line: complain */ 1321 errno = 0; 1322 logerror( 1323 "Error: `%s' log facility or log target missing", 1324 line); 1325 } 1326 1327 /* q is at the end of the blank between the two fields */ 1328 sp_err = 0; 1329 while (isblank((unsigned char)*q) && (q != line)) 1330 if (*q-- == ' ') 1331 sp_err = 1; 1332 1333 if (sp_err) { 1334 /* 1335 * A space somewhere between the log facility 1336 * and the log target: complain 1337 */ 1338 errno = 0; 1339 logerror( 1340 "Warning: `%s' space found where tab is expected", 1341 line); 1342 /* ... and fix the problem: replace all spaces by tabs */ 1343 while (*++q && isblank((unsigned char)*q)) 1344 if (*q == ' ') 1345 *q='\t'; 1346 } 1347 1348 /* scan through the list of selectors */ 1349 for (p = line; *p && *p != '\t';) { 1350 1351 /* find the end of this facility name list */ 1352 for (q = p; *q && *q != '\t' && *q++ != '.'; ) 1353 continue; 1354 1355 /* collect priority name */ 1356 for (bp = buf; *q && !strchr("\t,;", *q); ) 1357 *bp++ = *q++; 1358 *bp = '\0'; 1359 1360 /* skip cruft */ 1361 while (strchr(", ;", *q)) 1362 q++; 1363 1364 /* decode priority name */ 1365 if (*buf == '*') 1366 pri = LOG_PRIMASK + 1; 1367 else { 1368 pri = decode(buf, prioritynames); 1369 if (pri < 0) { 1370 errno = 0; 1371 logerror("Unknown priority name `%s'", buf); 1372 return; 1373 } 1374 } 1375 1376 /* scan facilities */ 1377 while (*p && !strchr("\t.;", *p)) { 1378 for (bp = buf; *p && !strchr("\t,;.", *p); ) 1379 *bp++ = *p++; 1380 *bp = '\0'; 1381 if (*buf == '*') 1382 for (i = 0; i < LOG_NFACILITIES; i++) 1383 f->f_pmask[i] = pri; 1384 else { 1385 i = decode(buf, facilitynames); 1386 if (i < 0) { 1387 errno = 0; 1388 logerror("Unknown facility name `%s'", 1389 buf); 1390 return; 1391 } 1392 f->f_pmask[i >> 3] = pri; 1393 } 1394 while (*p == ',' || *p == ' ') 1395 p++; 1396 } 1397 1398 p = q; 1399 } 1400 1401 /* skip to action part */ 1402 sp_err = 0; 1403 while ((*p == '\t') || (*p == ' ')) 1404 p++; 1405 1406 switch (*p) 1407 { 1408 case '@': 1409 (void)strlcpy(f->f_un.f_forw.f_hname, ++p, 1410 sizeof(f->f_un.f_forw.f_hname)); 1411 memset(&hints, 0, sizeof(hints)); 1412 hints.ai_family = AF_UNSPEC; 1413 hints.ai_socktype = SOCK_DGRAM; 1414 hints.ai_protocol = 0; 1415 error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints, 1416 &res); 1417 if (error) { 1418 logerror(gai_strerror(error)); 1419 break; 1420 } 1421 f->f_un.f_forw.f_addr = res; 1422 f->f_type = F_FORW; 1423 NumForwards++; 1424 break; 1425 1426 case '/': 1427 (void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname)); 1428 if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) { 1429 f->f_type = F_UNUSED; 1430 logerror(p); 1431 break; 1432 } 1433 if (isatty(f->f_file)) 1434 f->f_type = F_TTY; 1435 else 1436 f->f_type = F_FILE; 1437 if (strcmp(p, ctty) == 0) 1438 f->f_type = F_CONSOLE; 1439 break; 1440 1441 case '*': 1442 f->f_type = F_WALL; 1443 break; 1444 1445 default: 1446 for (i = 0; i < MAXUNAMES && *p; i++) { 1447 for (q = p; *q && *q != ','; ) 1448 q++; 1449 (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); 1450 if ((q - p) > UT_NAMESIZE) 1451 f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; 1452 else 1453 f->f_un.f_uname[i][q - p] = '\0'; 1454 while (*q == ',' || *q == ' ') 1455 q++; 1456 p = q; 1457 } 1458 f->f_type = F_USERS; 1459 break; 1460 } 1461 } 1462 1463 1464 /* 1465 * Decode a symbolic name to a numeric value 1466 */ 1467 int 1468 decode(const char *name, CODE *codetab) 1469 { 1470 CODE *c; 1471 char *p, buf[40]; 1472 1473 if (isdigit(*name)) 1474 return (atoi(name)); 1475 1476 for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) { 1477 if (isupper(*name)) 1478 *p = tolower(*name); 1479 else 1480 *p = *name; 1481 } 1482 *p = '\0'; 1483 for (c = codetab; c->c_name; c++) 1484 if (!strcmp(buf, c->c_name)) 1485 return (c->c_val); 1486 1487 return (-1); 1488 } 1489 1490 /* 1491 * Retrieve the size of the kernel message buffer, via sysctl. 1492 */ 1493 int 1494 getmsgbufsize(void) 1495 { 1496 int msgbufsize, mib[2]; 1497 size_t size; 1498 1499 mib[0] = CTL_KERN; 1500 mib[1] = KERN_MSGBUFSIZE; 1501 size = sizeof msgbufsize; 1502 if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) { 1503 dprintf("Couldn't get kern.msgbufsize\n"); 1504 return (0); 1505 } 1506 return (msgbufsize); 1507 } 1508 1509 int * 1510 socksetup(int af) 1511 { 1512 struct addrinfo hints, *res, *r; 1513 int error, maxs, *s, *socks; 1514 const int on = 1; 1515 1516 if(SecureMode && !NumForwards) 1517 return(NULL); 1518 1519 memset(&hints, 0, sizeof(hints)); 1520 hints.ai_flags = AI_PASSIVE; 1521 hints.ai_family = af; 1522 hints.ai_socktype = SOCK_DGRAM; 1523 error = getaddrinfo(NULL, "syslog", &hints, &res); 1524 if (error) { 1525 logerror(gai_strerror(error)); 1526 errno = 0; 1527 die(0); 1528 } 1529 1530 /* Count max number of sockets we may open */ 1531 for (maxs = 0, r = res; r; r = r->ai_next, maxs++) 1532 continue; 1533 socks = malloc((maxs+1) * sizeof(int)); 1534 if (!socks) { 1535 logerror("Couldn't allocate memory for sockets"); 1536 die(0); 1537 } 1538 1539 *socks = 0; /* num of sockets counter at start of array */ 1540 s = socks + 1; 1541 for (r = res; r; r = r->ai_next) { 1542 *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); 1543 if (*s < 0) { 1544 logerror("socket() failed"); 1545 continue; 1546 } 1547 if (r->ai_family == AF_INET6 && setsockopt(*s, IPPROTO_IPV6, 1548 IPV6_V6ONLY, &on, sizeof(on)) < 0) { 1549 logerror("setsockopt(IPV6_V6ONLY) failed"); 1550 close(*s); 1551 continue; 1552 } 1553 if (!SecureMode && bind(*s, r->ai_addr, r->ai_addrlen) < 0) { 1554 logerror("bind() failed"); 1555 close (*s); 1556 continue; 1557 } 1558 1559 *socks = *socks + 1; 1560 s++; 1561 } 1562 1563 if (*socks == 0) { 1564 free (socks); 1565 if(Debug) 1566 return(NULL); 1567 else 1568 die(0); 1569 } 1570 if (res) 1571 freeaddrinfo(res); 1572 1573 return(socks); 1574 } 1575