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