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