11553Srgrimes/* 21553Srgrimes * Copyright (c) 1983, 1988, 1993, 1994 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 131553Srgrimes * 4. Neither the name of the University nor the names of its contributors 141553Srgrimes * may be used to endorse or promote products derived from this software 151553Srgrimes * without specific prior written permission. 161553Srgrimes * 171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271553Srgrimes * SUCH DAMAGE. 281553Srgrimes */ 291553Srgrimes 301553Srgrimes#ifndef lint 3111448Swollmanstatic const char copyright[] = 321553Srgrimes"@(#) Copyright (c) 1983, 1988, 1993, 1994\n\ 331553Srgrimes The Regents of the University of California. All rights reserved.\n"; 3430603Scharnier#endif /* not lint */ 3530603Scharnier 3630603Scharnier#ifndef lint 3730603Scharnier#if 0 381553Srgrimesstatic char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94"; 3930603Scharnier#endif 401553Srgrimes#endif /* not lint */ 411553Srgrimes 4293078Sdes#include <sys/cdefs.h> 4393078Sdes__FBSDID("$FreeBSD$"); 4493078Sdes 451553Srgrimes/* 461553Srgrimes * syslogd -- log system messages 471553Srgrimes * 481553Srgrimes * This program implements a system log. It takes a series of lines. 491553Srgrimes * Each line may have a priority, signified as "<n>" as 501553Srgrimes * the first characters of the line. If this is 511553Srgrimes * not present, a default priority is used. 521553Srgrimes * 531553Srgrimes * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will 541553Srgrimes * cause it to reread its configuration file. 551553Srgrimes * 561553Srgrimes * Defined Constants: 571553Srgrimes * 58129851Sdwmalone * MAXLINE -- the maximum line length that can be handled. 591553Srgrimes * DEFUPRI -- the default priority for user messages 601553Srgrimes * DEFSPRI -- the default priority for kernel messages 611553Srgrimes * 621553Srgrimes * Author: Eric Allman 631553Srgrimes * extensive changes by Ralph Campbell 641553Srgrimes * more extensive changes by Eric Allman (again) 655278Swollman * Extension to log by program name as well as facility and priority 665278Swollman * by Peter da Silva. 6737820Sphk * -u and -v by Harlan Stenn. 6837820Sphk * Priority comparison code by Harlan Stenn. 691553Srgrimes */ 701553Srgrimes 711553Srgrimes#define MAXLINE 1024 /* maximum line length */ 721553Srgrimes#define MAXSVLINE 120 /* maximum saved line length */ 73174316Sobrien#define DEFUPRI (LOG_USER|LOG_NOTICE) 74174316Sobrien#define DEFSPRI (LOG_KERN|LOG_CRIT) 75174316Sobrien#define TIMERINTVL 30 /* interval for checking flush, mark */ 76174316Sobrien#define TTYMSGTIME 1 /* timeout passed to ttymsg */ 771553Srgrimes 781553Srgrimes#include <sys/param.h> 791553Srgrimes#include <sys/ioctl.h> 80199804Sattilio#include <sys/mman.h> 811553Srgrimes#include <sys/stat.h> 821553Srgrimes#include <sys/wait.h> 831553Srgrimes#include <sys/socket.h> 8422984Sjoerg#include <sys/queue.h> 851553Srgrimes#include <sys/uio.h> 861553Srgrimes#include <sys/un.h> 871553Srgrimes#include <sys/time.h> 881553Srgrimes#include <sys/resource.h> 895278Swollman#include <sys/syslimits.h> 90115108Sgshapiro#include <sys/types.h> 911553Srgrimes 921553Srgrimes#include <netinet/in.h> 931553Srgrimes#include <netdb.h> 941553Srgrimes#include <arpa/inet.h> 951553Srgrimes 961553Srgrimes#include <ctype.h> 9730603Scharnier#include <err.h> 981553Srgrimes#include <errno.h> 991553Srgrimes#include <fcntl.h> 100115108Sgshapiro#include <libutil.h> 101106054Swollman#include <limits.h> 10293078Sdes#include <paths.h> 1031553Srgrimes#include <signal.h> 1041553Srgrimes#include <stdio.h> 1051553Srgrimes#include <stdlib.h> 1061553Srgrimes#include <string.h> 10725437Sjoerg#include <sysexits.h> 1081553Srgrimes#include <unistd.h> 109202206Sed#include <utmpx.h> 11083243Sdd 1111553Srgrimes#include "pathnames.h" 11283243Sdd#include "ttymsg.h" 1131553Srgrimes 1141553Srgrimes#define SYSLOG_NAMES 1151553Srgrimes#include <sys/syslog.h> 11619224Sjoerg 11711448Swollmanconst char *ConfFile = _PATH_LOGCONF; 11811448Swollmanconst char *PidFile = _PATH_LOGPID; 11911448Swollmanconst char ctty[] = _PATH_CONSOLE; 1201553Srgrimes 1211553Srgrimes#define dprintf if (Debug) printf 1221553Srgrimes 123174316Sobrien#define MAXUNAMES 20 /* maximum number of user names */ 1241553Srgrimes 125137232Sglebius/* 126137232Sglebius * Unix sockets. 127137233Sglebius * We have two default sockets, one with 666 permissions, 128137857Skeramida * and one for privileged programs. 129137232Sglebius */ 130137232Sglebiusstruct funix { 131137232Sglebius int s; 132186331Sdelphij const char *name; 133137232Sglebius mode_t mode; 134137232Sglebius STAILQ_ENTRY(funix) next; 135137232Sglebius}; 136137233Sglebiusstruct funix funix_secure = { -1, _PATH_LOG_PRIV, S_IRUSR | S_IWUSR, 137137233Sglebius { NULL } }; 138137232Sglebiusstruct funix funix_default = { -1, _PATH_LOG, DEFFILEMODE, 139137233Sglebius { &funix_secure } }; 14037156Sguido 141137232SglebiusSTAILQ_HEAD(, funix) funixes = { &funix_default, 142137233Sglebius &(funix_secure.next.stqe_next) }; 14337156Sguido 1441553Srgrimes/* 1451553Srgrimes * Flags to logmsg(). 1461553Srgrimes */ 1471553Srgrimes 148174316Sobrien#define IGN_CONS 0x001 /* don't print on console */ 149174316Sobrien#define SYNC_FILE 0x002 /* do fsync on file after printing */ 150174316Sobrien#define ADDDATE 0x004 /* add a date to the message */ 151174316Sobrien#define MARK 0x008 /* this message is a mark */ 152174316Sobrien#define ISKERNEL 0x010 /* kernel generated message */ 1531553Srgrimes 1541553Srgrimes/* 1551553Srgrimes * This structure represents the files that will have log 1561553Srgrimes * copies printed. 157129855Sdwmalone * We require f_file to be valid if f_type is F_FILE, F_CONSOLE, F_TTY 158129855Sdwmalone * or if f_type if F_PIPE and f_pid > 0. 1591553Srgrimes */ 1601553Srgrimes 1611553Srgrimesstruct filed { 1621553Srgrimes struct filed *f_next; /* next in linked list */ 1631553Srgrimes short f_type; /* entry type, see below */ 1641553Srgrimes short f_file; /* file descriptor */ 1651553Srgrimes time_t f_time; /* time this was last written */ 16663795Sdwmalone char *f_host; /* host from which to recd. */ 1671553Srgrimes u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ 16837820Sphk u_char f_pcmp[LOG_NFACILITIES+1]; /* compare priority */ 16937820Sphk#define PRI_LT 0x1 17037820Sphk#define PRI_EQ 0x2 17137820Sphk#define PRI_GT 0x4 1725278Swollman char *f_program; /* program this applies to */ 1731553Srgrimes union { 174200954Sed char f_uname[MAXUNAMES][MAXLOGNAME]; 1751553Srgrimes struct { 17674053Sbrian char f_hname[MAXHOSTNAMELEN]; 17770099Sume struct addrinfo *f_addr; 17870099Sume 1791553Srgrimes } f_forw; /* forwarding address */ 1801553Srgrimes char f_fname[MAXPATHLEN]; 18122984Sjoerg struct { 18222984Sjoerg char f_pname[MAXPATHLEN]; 18322984Sjoerg pid_t f_pid; 18422984Sjoerg } f_pipe; 1851553Srgrimes } f_un; 1861553Srgrimes char f_prevline[MAXSVLINE]; /* last message logged */ 1871553Srgrimes char f_lasttime[16]; /* time of last occurrence */ 18874053Sbrian char f_prevhost[MAXHOSTNAMELEN]; /* host from which recd. */ 1891553Srgrimes int f_prevpri; /* pri of f_prevline */ 1901553Srgrimes int f_prevlen; /* length of f_prevline */ 1911553Srgrimes int f_prevcount; /* repetition cnt of prevline */ 19283243Sdd u_int f_repeatcount; /* number of "repeated" msgs */ 193129865Sdwmalone int f_flags; /* file-specific flags */ 194174316Sobrien#define FFLAG_SYNC 0x01 195174316Sobrien#define FFLAG_NEEDSYNC 0x02 1961553Srgrimes}; 1971553Srgrimes 1981553Srgrimes/* 19922984Sjoerg * Queue of about-to-be dead processes we should watch out for. 20022984Sjoerg */ 20122984Sjoerg 20260938SjakeTAILQ_HEAD(stailhead, deadq_entry) deadq_head; 20322984Sjoergstruct stailhead *deadq_headp; 20422984Sjoerg 20522984Sjoergstruct deadq_entry { 20622984Sjoerg pid_t dq_pid; 20722984Sjoerg int dq_timeout; 20860938Sjake TAILQ_ENTRY(deadq_entry) dq_entries; 20922984Sjoerg}; 21022984Sjoerg 21122984Sjoerg/* 21222984Sjoerg * The timeout to apply to processes waiting on the dead queue. Unit 21322984Sjoerg * of measure is `mark intervals', i.e. 20 minutes by default. 21422984Sjoerg * Processes on the dead queue will be terminated after that time. 21522984Sjoerg */ 21622984Sjoerg 217174316Sobrien#define DQ_TIMO_INIT 2 21822984Sjoerg 21922984Sjoergtypedef struct deadq_entry *dq_t; 22022984Sjoerg 22122984Sjoerg 22222984Sjoerg/* 22325437Sjoerg * Struct to hold records of network addresses that are allowed to log 22425437Sjoerg * to us. 22525437Sjoerg */ 22625437Sjoergstruct allowedpeer { 22725437Sjoerg int isnumeric; 22825437Sjoerg u_short port; 22925437Sjoerg union { 23025437Sjoerg struct { 23170099Sume struct sockaddr_storage addr; 23270099Sume struct sockaddr_storage mask; 23325437Sjoerg } numeric; 23425437Sjoerg char *name; 23525437Sjoerg } u; 23625437Sjoerg#define a_addr u.numeric.addr 23725437Sjoerg#define a_mask u.numeric.mask 23825437Sjoerg#define a_name u.name 23925437Sjoerg}; 24025437Sjoerg 24125437Sjoerg 24225437Sjoerg/* 2431553Srgrimes * Intervals at which we flush out "message repeated" messages, 2441553Srgrimes * in seconds after previous message is logged. After each flush, 2451553Srgrimes * we move to the next interval until we reach the largest. 2461553Srgrimes */ 2471553Srgrimesint repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ 2481553Srgrimes#define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) 2491553Srgrimes#define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) 2501553Srgrimes#define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ 2511553Srgrimes (f)->f_repeatcount = MAXREPEAT; \ 2521553Srgrimes } 2531553Srgrimes 2541553Srgrimes/* values for f_type */ 2551553Srgrimes#define F_UNUSED 0 /* unused entry */ 2561553Srgrimes#define F_FILE 1 /* regular file */ 2571553Srgrimes#define F_TTY 2 /* terminal */ 2581553Srgrimes#define F_CONSOLE 3 /* console terminal */ 2591553Srgrimes#define F_FORW 4 /* remote machine */ 2601553Srgrimes#define F_USERS 5 /* list of users */ 2611553Srgrimes#define F_WALL 6 /* everyone logged on */ 26222984Sjoerg#define F_PIPE 7 /* pipe to program */ 2631553Srgrimes 26483243Sddconst char *TypeNames[8] = { 2651553Srgrimes "UNUSED", "FILE", "TTY", "CONSOLE", 26622984Sjoerg "FORW", "USERS", "WALL", "PIPE" 2671553Srgrimes}; 2681553Srgrimes 26993078Sdesstatic struct filed *Files; /* Log files that we write to */ 27093078Sdesstatic struct filed consfile; /* Console */ 2711553Srgrimes 27293078Sdesstatic int Debug; /* debug flag */ 27393078Sdesstatic int resolve = 1; /* resolve hostname */ 27493078Sdesstatic char LocalHostName[MAXHOSTNAMELEN]; /* our hostname */ 275129756Sdwmalonestatic const char *LocalDomain; /* our local domain name */ 27693078Sdesstatic int *finet; /* Internet datagram socket */ 27793078Sdesstatic int fklog = -1; /* /dev/klog */ 27893078Sdesstatic int Initialized; /* set when we have initialized ourselves */ 27993078Sdesstatic int MarkInterval = 20 * 60; /* interval between marks in seconds */ 28093078Sdesstatic int MarkSeq; /* mark sequence number */ 281224002Sdelphijstatic int NoBind; /* don't bind() as suggested by RFC 3164 */ 28293078Sdesstatic int SecureMode; /* when true, receive only unix domain socks */ 28370099Sume#ifdef INET6 28493078Sdesstatic int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */ 28570099Sume#else 28693078Sdesstatic int family = PF_INET; /* protocol family (IPv4 only) */ 28770099Sume#endif 288178986Sbrianstatic int mask_C1 = 1; /* mask characters from 0x80 - 0x9F */ 28993078Sdesstatic int send_to_all; /* send message to all IPv4/IPv6 addresses */ 29093078Sdesstatic int use_bootfile; /* log entire bootfile for every kern msg */ 29193078Sdesstatic int no_compress; /* don't compress messages (1=pipes, 2=all) */ 292156339Spjdstatic int logflags = O_WRONLY|O_APPEND; /* flags used to open log files */ 29317245Spst 29493078Sdesstatic char bootfile[MAXLINE+1]; /* booted kernel file */ 2951553Srgrimes 29693078Sdesstruct allowedpeer *AllowedPeers; /* List of allowed peers */ 29793078Sdesstatic int NumAllowed; /* Number of entries in AllowedPeers */ 298183347Sdwmalonestatic int RemoteAddDate; /* Always set the date on remote messages */ 29925437Sjoerg 30093078Sdesstatic int UniquePriority; /* Only log specified priority? */ 30193078Sdesstatic int LogFacPri; /* Put facility and priority in log message: */ 30237820Sphk /* 0=no, 1=numeric, 2=names */ 30393078Sdesstatic int KeepKernFac; /* Keep remotely logged kernel facility */ 304131589Scpercivastatic int needdofsync = 0; /* Are any file(s) waiting to be fsynced? */ 305149425Spjdstatic struct pidfh *pfh; 30637820Sphk 30782724Skrisvolatile sig_atomic_t MarkSet, WantDie; 30882724Skris 30993078Sdesstatic int allowaddr(char *); 31093078Sdesstatic void cfline(const char *, struct filed *, 31193078Sdes const char *, const char *); 31293078Sdesstatic const char *cvthname(struct sockaddr *); 31393078Sdesstatic void deadq_enter(pid_t, const char *); 31493078Sdesstatic int deadq_remove(pid_t); 31593078Sdesstatic int decode(const char *, CODE *); 31693078Sdesstatic void die(int); 31793078Sdesstatic void dodie(int); 318131591Scpercivastatic void dofsync(void); 31993078Sdesstatic void domark(int); 32093078Sdesstatic void fprintlog(struct filed *, int, const char *); 321211023Sollistatic int *socksetup(int, char *); 32293078Sdesstatic void init(int); 32393078Sdesstatic void logerror(const char *); 32493078Sdesstatic void logmsg(int, const char *, const char *, int); 32593078Sdesstatic void log_deadchild(pid_t, int, const char *); 32693078Sdesstatic void markit(void); 327114676Sgshapirostatic int skip_message(const char *, const char *, int); 328183347Sdwmalonestatic void printline(const char *, char *, int); 32993078Sdesstatic void printsys(char *); 33093078Sdesstatic int p_open(const char *, pid_t *); 33193078Sdesstatic void readklog(void); 33293078Sdesstatic void reapchild(int); 33393077Sdesstatic void usage(void); 33493078Sdesstatic int validate(struct sockaddr *, const char *); 33593077Sdesstatic void unmapped(struct sockaddr *); 336186234Sobrienstatic void wallmsg(struct filed *, struct iovec *, const int iovlen); 33793078Sdesstatic int waitdaemon(int, int, int); 33893078Sdesstatic void timedout(int); 339137568Sglebiusstatic void double_rbuf(int); 3401553Srgrimes 3411553Srgrimesint 34293078Sdesmain(int argc, char *argv[]) 3431553Srgrimes{ 34482724Skris int ch, i, fdsrmax = 0, l; 3451553Srgrimes struct sockaddr_un sunx, fromunix; 34670099Sume struct sockaddr_storage frominet; 34782724Skris fd_set *fdsr = NULL; 34883243Sdd char line[MAXLINE + 1]; 349211023Solli char *bindhostname; 350211023Solli const char *hname; 35118710Speter struct timeval tv, *tvp; 35257558Sjoerg struct sigaction sact; 353137232Sglebius struct funix *fx, *fx1; 35457558Sjoerg sigset_t mask; 355149425Spjd pid_t ppid = 1, spid; 35655971Sdes socklen_t len; 3571553Srgrimes 358199804Sattilio if (madvise(NULL, 0, MADV_PROTECT) != 0) 359199804Sattilio dprintf("madvise() failed: %s\n", strerror(errno)); 360199804Sattilio 36182728Sdd bindhostname = NULL; 362224002Sdelphij while ((ch = getopt(argc, argv, "468Aa:b:cCdf:kl:m:nNop:P:sS:Tuv")) 363183347Sdwmalone != -1) 36464195Sdwmalone switch (ch) { 36570099Sume case '4': 36670099Sume family = PF_INET; 36770099Sume break; 36870099Sume#ifdef INET6 36970099Sume case '6': 37070099Sume family = PF_INET6; 37170099Sume break; 37270099Sume#endif 373178986Sbrian case '8': 374178986Sbrian mask_C1 = 0; 375178986Sbrian break; 37670099Sume case 'A': 37770099Sume send_to_all++; 37870099Sume break; 37925437Sjoerg case 'a': /* allow specific network addresses only */ 38025437Sjoerg if (allowaddr(optarg) == -1) 38125437Sjoerg usage(); 38225437Sjoerg break; 38382728Sdd case 'b': 38482728Sdd bindhostname = optarg; 38582728Sdd break; 38688897Sarchie case 'c': 38788897Sarchie no_compress++; 38888897Sarchie break; 389156339Spjd case 'C': 390156339Spjd logflags |= O_CREAT; 391156339Spjd break; 39264195Sdwmalone case 'd': /* debug */ 39364195Sdwmalone Debug++; 39464195Sdwmalone break; 3951553Srgrimes case 'f': /* configuration file */ 3961553Srgrimes ConfFile = optarg; 3971553Srgrimes break; 39867249Sdwmalone case 'k': /* keep remote kern fac */ 39967249Sdwmalone KeepKernFac = 1; 40067249Sdwmalone break; 40164195Sdwmalone case 'l': 402137232Sglebius { 403137232Sglebius long perml; 404137232Sglebius mode_t mode; 405137232Sglebius char *name, *ep; 406137232Sglebius 407137232Sglebius if (optarg[0] == '/') { 408137232Sglebius mode = DEFFILEMODE; 409137232Sglebius name = optarg; 410137232Sglebius } else if ((name = strchr(optarg, ':')) != NULL) { 411137232Sglebius *name++ = '\0'; 412137232Sglebius if (name[0] != '/') 413137232Sglebius errx(1, "socket name must be absolute " 414137232Sglebius "path"); 415137232Sglebius if (isdigit(*optarg)) { 416137232Sglebius perml = strtol(optarg, &ep, 8); 417137232Sglebius if (*ep || perml < 0 || 418137232Sglebius perml & ~(S_IRWXU|S_IRWXG|S_IRWXO)) 419137232Sglebius errx(1, "invalid mode %s, exiting", 420137232Sglebius optarg); 421137232Sglebius mode = (mode_t )perml; 422137232Sglebius } else 423137232Sglebius errx(1, "invalid mode %s, exiting", 424137232Sglebius optarg); 425137232Sglebius } else /* doesn't begin with '/', and no ':' */ 426137232Sglebius errx(1, "can't parse path %s", optarg); 427137232Sglebius 428137232Sglebius if (strlen(name) >= sizeof(sunx.sun_path)) 429137232Sglebius errx(1, "%s path too long, exiting", name); 430137232Sglebius if ((fx = malloc(sizeof(struct funix))) == NULL) 431137232Sglebius errx(1, "malloc failed"); 432137232Sglebius fx->s = -1; 433137232Sglebius fx->name = name; 434137232Sglebius fx->mode = mode; 435137232Sglebius STAILQ_INSERT_TAIL(&funixes, fx, next); 43664195Sdwmalone break; 437137232Sglebius } 4381553Srgrimes case 'm': /* mark interval */ 4391553Srgrimes MarkInterval = atoi(optarg) * 60; 4401553Srgrimes break; 441224002Sdelphij case 'N': 442224002Sdelphij NoBind = 1; 443224002Sdelphij SecureMode = 1; 444224002Sdelphij break; 44563997Sps case 'n': 44663997Sps resolve = 0; 44763997Sps break; 44887000Sdd case 'o': 44987000Sdd use_bootfile = 1; 45087000Sdd break; 4511553Srgrimes case 'p': /* path */ 452129853Sdwmalone if (strlen(optarg) >= sizeof(sunx.sun_path)) 453129853Sdwmalone errx(1, "%s path too long, exiting", optarg); 454137232Sglebius funix_default.name = optarg; 4551553Srgrimes break; 45676431Sdwmalone case 'P': /* path for alt. PID */ 45776431Sdwmalone PidFile = optarg; 45876431Sdwmalone break; 45917245Spst case 's': /* no network mode */ 46017245Spst SecureMode++; 46117245Spst break; 462144984Shrs case 'S': /* path for privileged originator */ 463144984Shrs if (strlen(optarg) >= sizeof(sunx.sun_path)) 464144984Shrs errx(1, "%s path too long, exiting", optarg); 465144984Shrs funix_secure.name = optarg; 466144984Shrs break; 467183347Sdwmalone case 'T': 468183347Sdwmalone RemoteAddDate = 1; 469183347Sdwmalone break; 47037820Sphk case 'u': /* only log specified priority */ 471137569Sglebius UniquePriority++; 47237820Sphk break; 47337820Sphk case 'v': /* log facility and priority */ 47437820Sphk LogFacPri++; 47537820Sphk break; 4761553Srgrimes default: 4771553Srgrimes usage(); 4781553Srgrimes } 4791553Srgrimes if ((argc -= optind) != 0) 4801553Srgrimes usage(); 4811553Srgrimes 482149425Spjd pfh = pidfile_open(PidFile, 0600, &spid); 483149425Spjd if (pfh == NULL) { 484149425Spjd if (errno == EEXIST) 485149425Spjd errx(1, "syslogd already running, pid: %d", spid); 486149425Spjd warn("cannot open pid file"); 487149425Spjd } 488149425Spjd 48918710Speter if (!Debug) { 49018710Speter ppid = waitdaemon(0, 0, 30); 491149425Spjd if (ppid < 0) { 492149425Spjd warn("could not become daemon"); 493149425Spjd pidfile_remove(pfh); 494149425Spjd exit(1); 495149425Spjd } 49693080Sdes } else { 4971553Srgrimes setlinebuf(stdout); 49893080Sdes } 4991553Srgrimes 50025437Sjoerg if (NumAllowed) 50125437Sjoerg endservent(); 50225437Sjoerg 5031553Srgrimes consfile.f_type = F_CONSOLE; 50482724Skris (void)strlcpy(consfile.f_un.f_fname, ctty + sizeof _PATH_DEV - 1, 50582724Skris sizeof(consfile.f_un.f_fname)); 50682724Skris (void)strlcpy(bootfile, getbootfile(), sizeof(bootfile)); 50782724Skris (void)signal(SIGTERM, dodie); 50882724Skris (void)signal(SIGINT, Debug ? dodie : SIG_IGN); 50982724Skris (void)signal(SIGQUIT, Debug ? dodie : SIG_IGN); 51057558Sjoerg /* 51157558Sjoerg * We don't want the SIGCHLD and SIGHUP handlers to interfere 51257558Sjoerg * with each other; they are likely candidates for being called 51357558Sjoerg * simultaneously (SIGHUP closes pipe descriptor, process dies, 51457558Sjoerg * SIGCHLD happens). 51557558Sjoerg */ 51657558Sjoerg sigemptyset(&mask); 51757558Sjoerg sigaddset(&mask, SIGHUP); 51857558Sjoerg sact.sa_handler = reapchild; 51957558Sjoerg sact.sa_mask = mask; 52057609Sjoerg sact.sa_flags = SA_RESTART; 52157558Sjoerg (void)sigaction(SIGCHLD, &sact, NULL); 5221553Srgrimes (void)signal(SIGALRM, domark); 52322984Sjoerg (void)signal(SIGPIPE, SIG_IGN); /* We'll catch EPIPE instead. */ 5241553Srgrimes (void)alarm(TIMERINTVL); 5251553Srgrimes 52625154Spst TAILQ_INIT(&deadq_head); 52725154Spst 5281553Srgrimes#ifndef SUN_LEN 5291553Srgrimes#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 5301553Srgrimes#endif 531137232Sglebius STAILQ_FOREACH_SAFE(fx, &funixes, next, fx1) { 532137232Sglebius (void)unlink(fx->name); 53337156Sguido memset(&sunx, 0, sizeof(sunx)); 534176427Sdwmalone sunx.sun_family = AF_LOCAL; 535137232Sglebius (void)strlcpy(sunx.sun_path, fx->name, sizeof(sunx.sun_path)); 536176427Sdwmalone fx->s = socket(PF_LOCAL, SOCK_DGRAM, 0); 537137232Sglebius if (fx->s < 0 || 538137232Sglebius bind(fx->s, (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 || 539137232Sglebius chmod(fx->name, fx->mode) < 0) { 54093080Sdes (void)snprintf(line, sizeof line, 541137232Sglebius "cannot create %s", fx->name); 54237156Sguido logerror(line); 543137232Sglebius dprintf("cannot create %s (%d)\n", fx->name, errno); 544137233Sglebius if (fx == &funix_default || fx == &funix_secure) 54537156Sguido die(0); 546137568Sglebius else { 547137232Sglebius STAILQ_REMOVE(&funixes, fx, funix, next); 548137568Sglebius continue; 549137568Sglebius } 550137568Sglebius double_rbuf(fx->s); 55137156Sguido } 55237156Sguido } 55346428Sdes if (SecureMode <= 1) 55482728Sdd finet = socksetup(family, bindhostname); 5551553Srgrimes 55670099Sume if (finet) { 55770099Sume if (SecureMode) { 55870099Sume for (i = 0; i < *finet; i++) { 55970099Sume if (shutdown(finet[i+1], SHUT_RD) < 0) { 56070099Sume logerror("shutdown"); 56170099Sume if (!Debug) 56270099Sume die(0); 56370099Sume } 56470099Sume } 56593080Sdes } else { 56670099Sume dprintf("listening on inet and/or inet6 socket\n"); 56793080Sdes } 56870099Sume dprintf("sending on inet and/or inet6 socket\n"); 5691553Srgrimes } 57035428Sphk 57146299Sdt if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0) 57246299Sdt if (fcntl(fklog, F_SETFL, O_NONBLOCK) < 0) 57346299Sdt fklog = -1; 57446299Sdt if (fklog < 0) 5751553Srgrimes dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); 5761553Srgrimes 5771553Srgrimes /* tuck my process id away */ 578149425Spjd pidfile_write(pfh); 5791553Srgrimes 5801553Srgrimes dprintf("off & running....\n"); 5811553Srgrimes 5821553Srgrimes init(0); 58357558Sjoerg /* prevent SIGHUP and SIGCHLD handlers from running in parallel */ 58457558Sjoerg sigemptyset(&mask); 58557558Sjoerg sigaddset(&mask, SIGCHLD); 58657558Sjoerg sact.sa_handler = init; 58757558Sjoerg sact.sa_mask = mask; 58857609Sjoerg sact.sa_flags = SA_RESTART; 58957558Sjoerg (void)sigaction(SIGHUP, &sact, NULL); 5901553Srgrimes 59118710Speter tvp = &tv; 59218710Speter tv.tv_sec = tv.tv_usec = 0; 59318710Speter 59482724Skris if (fklog != -1 && fklog > fdsrmax) 59582724Skris fdsrmax = fklog; 59682724Skris if (finet && !SecureMode) { 59782724Skris for (i = 0; i < *finet; i++) { 59882724Skris if (finet[i+1] != -1 && finet[i+1] > fdsrmax) 59982724Skris fdsrmax = finet[i+1]; 60082724Skris } 60182724Skris } 602137232Sglebius STAILQ_FOREACH(fx, &funixes, next) 603137232Sglebius if (fx->s > fdsrmax) 604137232Sglebius fdsrmax = fx->s; 60582724Skris 60682724Skris fdsr = (fd_set *)calloc(howmany(fdsrmax+1, NFDBITS), 60782724Skris sizeof(fd_mask)); 60882724Skris if (fdsr == NULL) 60982724Skris errx(1, "calloc fd_set"); 61082724Skris 6111553Srgrimes for (;;) { 61282724Skris if (MarkSet) 61382724Skris markit(); 61482724Skris if (WantDie) 61582724Skris die(WantDie); 6161553Srgrimes 61782724Skris bzero(fdsr, howmany(fdsrmax+1, NFDBITS) * 61882724Skris sizeof(fd_mask)); 61982724Skris 62082724Skris if (fklog != -1) 62182724Skris FD_SET(fklog, fdsr); 62270099Sume if (finet && !SecureMode) { 62370099Sume for (i = 0; i < *finet; i++) { 62482724Skris if (finet[i+1] != -1) 62582724Skris FD_SET(finet[i+1], fdsr); 62670099Sume } 62737156Sguido } 628137232Sglebius STAILQ_FOREACH(fx, &funixes, next) 629137232Sglebius FD_SET(fx->s, fdsr); 63037156Sguido 631131589Scperciva i = select(fdsrmax+1, fdsr, NULL, NULL, 632131589Scperciva needdofsync ? &tv : tvp); 63382724Skris switch (i) { 63482724Skris case 0: 635131589Scperciva dofsync(); 636131589Scperciva needdofsync = 0; 63718710Speter if (tvp) { 63818710Speter tvp = NULL; 63918710Speter if (ppid != 1) 64018710Speter kill(ppid, SIGALRM); 64118710Speter } 6421553Srgrimes continue; 64382724Skris case -1: 6441553Srgrimes if (errno != EINTR) 6451553Srgrimes logerror("select"); 6461553Srgrimes continue; 6471553Srgrimes } 64882724Skris if (fklog != -1 && FD_ISSET(fklog, fdsr)) 64946299Sdt readklog(); 65070099Sume if (finet && !SecureMode) { 65170099Sume for (i = 0; i < *finet; i++) { 65282724Skris if (FD_ISSET(finet[i+1], fdsr)) { 65370099Sume len = sizeof(frominet); 65470099Sume l = recvfrom(finet[i+1], line, MAXLINE, 65570099Sume 0, (struct sockaddr *)&frominet, 65670099Sume &len); 65770099Sume if (l > 0) { 65870099Sume line[l] = '\0'; 65970099Sume hname = cvthname((struct sockaddr *)&frominet); 66070099Sume unmapped((struct sockaddr *)&frominet); 66170099Sume if (validate((struct sockaddr *)&frominet, hname)) 662183347Sdwmalone printline(hname, line, RemoteAddDate ? ADDDATE : 0); 66370099Sume } else if (l < 0 && errno != EINTR) 66470099Sume logerror("recvfrom inet"); 66570099Sume } 66670099Sume } 6678857Srgrimes } 668137232Sglebius STAILQ_FOREACH(fx, &funixes, next) { 669137232Sglebius if (FD_ISSET(fx->s, fdsr)) { 67037156Sguido len = sizeof(fromunix); 671137232Sglebius l = recvfrom(fx->s, line, MAXLINE, 0, 67237156Sguido (struct sockaddr *)&fromunix, &len); 67337156Sguido if (l > 0) { 67437156Sguido line[l] = '\0'; 675183347Sdwmalone printline(LocalHostName, line, 0); 67637156Sguido } else if (l < 0 && errno != EINTR) 67737156Sguido logerror("recvfrom unix"); 67837156Sguido } 67937156Sguido } 6801553Srgrimes } 68182724Skris if (fdsr) 68282724Skris free(fdsr); 6831553Srgrimes} 6841553Srgrimes 68530603Scharnierstatic void 68693078Sdesunmapped(struct sockaddr *sa) 68770099Sume{ 68870099Sume struct sockaddr_in6 *sin6; 68983243Sdd struct sockaddr_in sin4; 69070099Sume 69170099Sume if (sa->sa_family != AF_INET6) 69270099Sume return; 69370099Sume if (sa->sa_len != sizeof(struct sockaddr_in6) || 69483243Sdd sizeof(sin4) > sa->sa_len) 69570099Sume return; 69670099Sume sin6 = (struct sockaddr_in6 *)sa; 69770099Sume if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 69870099Sume return; 69970099Sume 70083243Sdd memset(&sin4, 0, sizeof(sin4)); 70183243Sdd sin4.sin_family = AF_INET; 70283243Sdd sin4.sin_len = sizeof(struct sockaddr_in); 70383243Sdd memcpy(&sin4.sin_addr, &sin6->sin6_addr.s6_addr[12], 70483243Sdd sizeof(sin4.sin_addr)); 70583243Sdd sin4.sin_port = sin6->sin6_port; 70670099Sume 70783243Sdd memcpy(sa, &sin4, sin4.sin_len); 70870099Sume} 70970099Sume 71070099Sumestatic void 71193078Sdesusage(void) 7121553Srgrimes{ 7131553Srgrimes 714105393Stjr fprintf(stderr, "%s\n%s\n%s\n%s\n", 715183347Sdwmalone "usage: syslogd [-468ACcdknosTuv] [-a allowed_peer]", 716162805Sru " [-b bind_address] [-f config_file]", 717162805Sru " [-l [mode:]path] [-m mark_interval]", 718137580Sru " [-P pid_file] [-p log_socket]"); 7191553Srgrimes exit(1); 7201553Srgrimes} 7211553Srgrimes 7221553Srgrimes/* 7231553Srgrimes * Take a raw input line, decode the message, and print the message 7241553Srgrimes * on the appropriate log files. 7251553Srgrimes */ 72693078Sdesstatic void 727183347Sdwmaloneprintline(const char *hname, char *msg, int flags) 7281553Srgrimes{ 729125271Siedowse char *p, *q; 730125271Siedowse long n; 7311553Srgrimes int c, pri; 732125271Siedowse char line[MAXLINE + 1]; 7331553Srgrimes 7341553Srgrimes /* test for special codes */ 735125271Siedowse p = msg; 7361553Srgrimes pri = DEFUPRI; 7371553Srgrimes if (*p == '<') { 738125271Siedowse errno = 0; 739125271Siedowse n = strtol(p + 1, &q, 10); 740125271Siedowse if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) { 741125271Siedowse p = q + 1; 742125271Siedowse pri = n; 743125271Siedowse } 7441553Srgrimes } 7451553Srgrimes if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 7461553Srgrimes pri = DEFUPRI; 7471553Srgrimes 748129852Sdwmalone /* 749129852Sdwmalone * Don't allow users to log kernel messages. 750129852Sdwmalone * NOTE: since LOG_KERN == 0 this will also match 751129852Sdwmalone * messages with no facility specified. 752129852Sdwmalone */ 753129852Sdwmalone if ((pri & LOG_FACMASK) == LOG_KERN && !KeepKernFac) 7541553Srgrimes pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri)); 7551553Srgrimes 7561553Srgrimes q = line; 7571553Srgrimes 75859341Sache while ((c = (unsigned char)*p++) != '\0' && 75966080Simp q < &line[sizeof(line) - 4]) { 760178986Sbrian if (mask_C1 && (c & 0x80) && c < 0xA0) { 76159341Sache c &= 0x7F; 76259341Sache *q++ = 'M'; 76359341Sache *q++ = '-'; 76459341Sache } 76559341Sache if (isascii(c) && iscntrl(c)) { 76693080Sdes if (c == '\n') { 7671553Srgrimes *q++ = ' '; 76893080Sdes } else if (c == '\t') { 7691553Srgrimes *q++ = '\t'; 77093080Sdes } else { 7711553Srgrimes *q++ = '^'; 7721553Srgrimes *q++ = c ^ 0100; 7731553Srgrimes } 77493080Sdes } else { 7751553Srgrimes *q++ = c; 77693080Sdes } 77759341Sache } 7781553Srgrimes *q = '\0'; 7791553Srgrimes 780183347Sdwmalone logmsg(pri, line, hname, flags); 7811553Srgrimes} 7821553Srgrimes 7831553Srgrimes/* 78446299Sdt * Read /dev/klog while data are available, split into lines. 7851553Srgrimes */ 78693078Sdesstatic void 78793078Sdesreadklog(void) 7881553Srgrimes{ 78946299Sdt char *p, *q, line[MAXLINE + 1]; 79046559Sdt int len, i; 7911553Srgrimes 79246559Sdt len = 0; 79346299Sdt for (;;) { 79446559Sdt i = read(fklog, line + len, MAXLINE - 1 - len); 79593080Sdes if (i > 0) { 79646559Sdt line[i + len] = '\0'; 79793080Sdes } else { 79893080Sdes if (i < 0 && errno != EINTR && errno != EAGAIN) { 79993080Sdes logerror("klog"); 80093080Sdes fklog = -1; 80193080Sdes } 80246299Sdt break; 80393080Sdes } 80446299Sdt 80546299Sdt for (p = line; (q = strchr(p, '\n')) != NULL; p = q + 1) { 80646299Sdt *q = '\0'; 80746299Sdt printsys(p); 8081553Srgrimes } 80946559Sdt len = strlen(p); 81046559Sdt if (len >= MAXLINE - 1) { 81146299Sdt printsys(p); 81246559Sdt len = 0; 81346299Sdt } 814137569Sglebius if (len > 0) 81546559Sdt memmove(line, p, len + 1); 8161553Srgrimes } 81746559Sdt if (len > 0) 81846299Sdt printsys(line); 8191553Srgrimes} 8201553Srgrimes 82146299Sdt/* 82246299Sdt * Take a raw input line from /dev/klog, format similar to syslog(). 82346299Sdt */ 82493078Sdesstatic void 825124992Siedowseprintsys(char *msg) 82646299Sdt{ 827125271Siedowse char *p, *q; 828125271Siedowse long n; 829125271Siedowse int flags, isprintf, pri; 83046299Sdt 83146299Sdt flags = ISKERNEL | SYNC_FILE | ADDDATE; /* fsync after write */ 832125271Siedowse p = msg; 83346299Sdt pri = DEFSPRI; 834124992Siedowse isprintf = 1; 83546299Sdt if (*p == '<') { 836125271Siedowse errno = 0; 837125271Siedowse n = strtol(p + 1, &q, 10); 838125271Siedowse if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) { 839125271Siedowse p = q + 1; 840124992Siedowse pri = n; 841124992Siedowse isprintf = 0; 842124992Siedowse } 843124992Siedowse } 844124992Siedowse /* 845124992Siedowse * Kernel printf's and LOG_CONSOLE messages have been displayed 846124992Siedowse * on the console already. 847124992Siedowse */ 848124992Siedowse if (isprintf || (pri & LOG_FACMASK) == LOG_CONSOLE) 84946299Sdt flags |= IGN_CONS; 85046299Sdt if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 85146299Sdt pri = DEFSPRI; 85246299Sdt logmsg(pri, p, LocalHostName, flags); 85346299Sdt} 85446299Sdt 85593078Sdesstatic time_t now; 8561553Srgrimes 8571553Srgrimes/* 858106571Sthomas * Match a program or host name against a specification. 859106571Sthomas * Return a non-0 value if the message must be ignored 860106571Sthomas * based on the specification. 861106571Sthomas */ 862106571Sthomasstatic int 863151420Simpskip_message(const char *name, const char *spec, int checkcase) 864151420Simp{ 865110776Sthomas const char *s; 866110776Sthomas char prev, next; 867110776Sthomas int exclude = 0; 868110776Sthomas /* Behaviour on explicit match */ 869110776Sthomas 870106571Sthomas if (spec == NULL) 871106571Sthomas return 0; 872110776Sthomas switch (*spec) { 873110776Sthomas case '-': 874110776Sthomas exclude = 1; 875110776Sthomas /*FALLTHROUGH*/ 876106571Sthomas case '+': 877110776Sthomas spec++; 878110776Sthomas break; 879106571Sthomas default: 880110776Sthomas break; 881106571Sthomas } 882114676Sgshapiro if (checkcase) 883114676Sgshapiro s = strstr (spec, name); 884114676Sgshapiro else 885114676Sgshapiro s = strcasestr (spec, name); 886110776Sthomas 887110776Sthomas if (s != NULL) { 888110776Sthomas prev = (s == spec ? ',' : *(s - 1)); 889110776Sthomas next = *(s + strlen (name)); 890110776Sthomas 891110776Sthomas if (prev == ',' && (next == '\0' || next == ',')) 892110776Sthomas /* Explicit match: skip iff the spec is an 893110776Sthomas exclusive one. */ 894110776Sthomas return exclude; 895110776Sthomas } 896110776Sthomas 897110776Sthomas /* No explicit match for this name: skip the message iff 898110776Sthomas the spec is an inclusive one. */ 899110776Sthomas return !exclude; 900106571Sthomas} 901106571Sthomas 902106571Sthomas/* 9031553Srgrimes * Log a message to the appropriate log files, users, etc. based on 9041553Srgrimes * the priority. 9051553Srgrimes */ 90693078Sdesstatic void 90793078Sdeslogmsg(int pri, const char *msg, const char *from, int flags) 9081553Srgrimes{ 9091553Srgrimes struct filed *f; 91037145Sjulian int i, fac, msglen, omask, prilev; 91183243Sdd const char *timestamp; 9125278Swollman char prog[NAME_MAX+1]; 91337145Sjulian char buf[MAXLINE+1]; 9141553Srgrimes 9151553Srgrimes dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", 9161553Srgrimes pri, flags, from, msg); 9171553Srgrimes 9181553Srgrimes omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); 9191553Srgrimes 9201553Srgrimes /* 9211553Srgrimes * Check to see if msg looks non-standard. 9221553Srgrimes */ 9231553Srgrimes msglen = strlen(msg); 9241553Srgrimes if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || 9251553Srgrimes msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') 9261553Srgrimes flags |= ADDDATE; 9271553Srgrimes 9281553Srgrimes (void)time(&now); 92993080Sdes if (flags & ADDDATE) { 9301553Srgrimes timestamp = ctime(&now) + 4; 93193080Sdes } else { 9321553Srgrimes timestamp = msg; 9331553Srgrimes msg += 16; 9341553Srgrimes msglen -= 16; 9351553Srgrimes } 9361553Srgrimes 9375278Swollman /* skip leading blanks */ 93864195Sdwmalone while (isspace(*msg)) { 9395278Swollman msg++; 9405278Swollman msglen--; 9415278Swollman } 9425278Swollman 9431553Srgrimes /* extract facility and priority level */ 9441553Srgrimes if (flags & MARK) 9451553Srgrimes fac = LOG_NFACILITIES; 9461553Srgrimes else 9471553Srgrimes fac = LOG_FAC(pri); 948144218Sglebius 949144218Sglebius /* Check maximum facility number. */ 950144218Sglebius if (fac > LOG_NFACILITIES) { 951144218Sglebius (void)sigsetmask(omask); 952144218Sglebius return; 953144218Sglebius } 954144218Sglebius 9551553Srgrimes prilev = LOG_PRI(pri); 9561553Srgrimes 9575278Swollman /* extract program name */ 95864195Sdwmalone for (i = 0; i < NAME_MAX; i++) { 959129867Sdwmalone if (!isprint(msg[i]) || msg[i] == ':' || msg[i] == '[' || 960139381Sdwmalone msg[i] == '/' || isspace(msg[i])) 9615278Swollman break; 9625278Swollman prog[i] = msg[i]; 9635278Swollman } 9645278Swollman prog[i] = 0; 9655278Swollman 96637145Sjulian /* add kernel prefix for kernel messages */ 96737145Sjulian if (flags & ISKERNEL) { 96887000Sdd snprintf(buf, sizeof(buf), "%s: %s", 96987000Sdd use_bootfile ? bootfile : "kernel", msg); 97037145Sjulian msg = buf; 97137145Sjulian msglen = strlen(buf); 97237145Sjulian } 97337145Sjulian 9741553Srgrimes /* log the message to the particular outputs */ 9751553Srgrimes if (!Initialized) { 9761553Srgrimes f = &consfile; 977174533Sobrien /* 978174533Sobrien * Open in non-blocking mode to avoid hangs during open 979174533Sobrien * and close(waiting for the port to drain). 980174533Sobrien */ 981174533Sobrien f->f_file = open(ctty, O_WRONLY | O_NONBLOCK, 0); 9821553Srgrimes 9831553Srgrimes if (f->f_file >= 0) { 984115109Sgshapiro (void)strlcpy(f->f_lasttime, timestamp, 985115109Sgshapiro sizeof(f->f_lasttime)); 9861553Srgrimes fprintlog(f, flags, msg); 9871553Srgrimes (void)close(f->f_file); 9881553Srgrimes } 9891553Srgrimes (void)sigsetmask(omask); 9901553Srgrimes return; 9911553Srgrimes } 9921553Srgrimes for (f = Files; f; f = f->f_next) { 9931553Srgrimes /* skip messages that are incorrect priority */ 99437820Sphk if (!(((f->f_pcmp[fac] & PRI_EQ) && (f->f_pmask[fac] == prilev)) 99537820Sphk ||((f->f_pcmp[fac] & PRI_LT) && (f->f_pmask[fac] < prilev)) 99637820Sphk ||((f->f_pcmp[fac] & PRI_GT) && (f->f_pmask[fac] > prilev)) 99737820Sphk ) 99837820Sphk || f->f_pmask[fac] == INTERNAL_NOPRI) 9991553Srgrimes continue; 1000106571Sthomas 100163795Sdwmalone /* skip messages with the incorrect hostname */ 1002114676Sgshapiro if (skip_message(from, f->f_host, 0)) 1003106571Sthomas continue; 100463795Sdwmalone 10055278Swollman /* skip messages with the incorrect program name */ 1006114676Sgshapiro if (skip_message(prog, f->f_program, 1)) 1007106571Sthomas continue; 10081553Srgrimes 1009106571Sthomas /* skip message to console if it has already been printed */ 10101553Srgrimes if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) 10111553Srgrimes continue; 10121553Srgrimes 10131553Srgrimes /* don't output marks to recently written files */ 10141553Srgrimes if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) 10151553Srgrimes continue; 10161553Srgrimes 10171553Srgrimes /* 10181553Srgrimes * suppress duplicate lines to this file 10191553Srgrimes */ 102088897Sarchie if (no_compress - (f->f_type != F_PIPE) < 1 && 102188897Sarchie (flags & MARK) == 0 && msglen == f->f_prevlen && 1022174533Sobrien f->f_prevline && !strcmp(msg, f->f_prevline) && 102349940Sbrian !strcasecmp(from, f->f_prevhost)) { 1024115109Sgshapiro (void)strlcpy(f->f_lasttime, timestamp, 1025115109Sgshapiro sizeof(f->f_lasttime)); 10261553Srgrimes f->f_prevcount++; 10271553Srgrimes dprintf("msg repeated %d times, %ld sec of %d\n", 102837450Sbde f->f_prevcount, (long)(now - f->f_time), 10291553Srgrimes repeatinterval[f->f_repeatcount]); 10301553Srgrimes /* 10311553Srgrimes * If domark would have logged this by now, 10321553Srgrimes * flush it now (so we don't hold isolated messages), 10331553Srgrimes * but back off so we'll flush less often 10341553Srgrimes * in the future. 10351553Srgrimes */ 10361553Srgrimes if (now > REPEATTIME(f)) { 10371553Srgrimes fprintlog(f, flags, (char *)NULL); 10381553Srgrimes BACKOFF(f); 10391553Srgrimes } 10401553Srgrimes } else { 10411553Srgrimes /* new line, save it */ 10421553Srgrimes if (f->f_prevcount) 10431553Srgrimes fprintlog(f, 0, (char *)NULL); 10441553Srgrimes f->f_repeatcount = 0; 104517245Spst f->f_prevpri = pri; 1046115109Sgshapiro (void)strlcpy(f->f_lasttime, timestamp, 1047115109Sgshapiro sizeof(f->f_lasttime)); 104882724Skris (void)strlcpy(f->f_prevhost, from, 104982724Skris sizeof(f->f_prevhost)); 10501553Srgrimes if (msglen < MAXSVLINE) { 10511553Srgrimes f->f_prevlen = msglen; 105282724Skris (void)strlcpy(f->f_prevline, msg, sizeof(f->f_prevline)); 10531553Srgrimes fprintlog(f, flags, (char *)NULL); 10541553Srgrimes } else { 10551553Srgrimes f->f_prevline[0] = 0; 10561553Srgrimes f->f_prevlen = 0; 10571553Srgrimes fprintlog(f, flags, msg); 10581553Srgrimes } 10591553Srgrimes } 10601553Srgrimes } 10611553Srgrimes (void)sigsetmask(omask); 10621553Srgrimes} 10631553Srgrimes 106493078Sdesstatic void 1065131589Scpercivadofsync(void) 1066131589Scperciva{ 1067131589Scperciva struct filed *f; 1068131589Scperciva 1069131589Scperciva for (f = Files; f; f = f->f_next) { 1070131589Scperciva if ((f->f_type == F_FILE) && 1071131589Scperciva (f->f_flags & FFLAG_NEEDSYNC)) { 1072131589Scperciva f->f_flags &= ~FFLAG_NEEDSYNC; 1073131589Scperciva (void)fsync(f->f_file); 1074131589Scperciva } 1075131589Scperciva } 1076131589Scperciva} 1077131589Scperciva 1078186234Sobrien#define IOV_SIZE 7 1079131589Scpercivastatic void 108093078Sdesfprintlog(struct filed *f, int flags, const char *msg) 10811553Srgrimes{ 1082186234Sobrien struct iovec iov[IOV_SIZE]; 10831553Srgrimes struct iovec *v; 108470099Sume struct addrinfo *r; 108570099Sume int i, l, lsent = 0; 108689162Sdeischen char line[MAXLINE + 1], repbuf[80], greetings[200], *wmsg = NULL; 1087129756Sdwmalone char nul[] = "", space[] = " ", lf[] = "\n", crlf[] = "\r\n"; 108883243Sdd const char *msgret; 10891553Srgrimes 10901553Srgrimes v = iov; 10911553Srgrimes if (f->f_type == F_WALL) { 10921553Srgrimes v->iov_base = greetings; 1093174533Sobrien /* The time displayed is not synchornized with the other log 1094174533Sobrien * destinations (like messages). Following fragment was using 1095174533Sobrien * ctime(&now), which was updating the time every 30 sec. 1096174533Sobrien * With f_lasttime, time is synchronized correctly. 1097174533Sobrien */ 109829623Sbrian v->iov_len = snprintf(greetings, sizeof greetings, 10991553Srgrimes "\r\n\7Message from syslogd@%s at %.24s ...\r\n", 1100174533Sobrien f->f_prevhost, f->f_lasttime); 1101217589Sdwmalone if (v->iov_len >= sizeof greetings) 1102217589Sdwmalone v->iov_len = sizeof greetings - 1; 1103217589Sdwmalone v++; 1104129756Sdwmalone v->iov_base = nul; 11051553Srgrimes v->iov_len = 0; 11061553Srgrimes v++; 11071553Srgrimes } else { 11081553Srgrimes v->iov_base = f->f_lasttime; 1109174533Sobrien v->iov_len = strlen(f->f_lasttime); 11101553Srgrimes v++; 1111129756Sdwmalone v->iov_base = space; 11121553Srgrimes v->iov_len = 1; 11131553Srgrimes v++; 11141553Srgrimes } 111537820Sphk 111637820Sphk if (LogFacPri) { 111737820Sphk static char fp_buf[30]; /* Hollow laugh */ 111837820Sphk int fac = f->f_prevpri & LOG_FACMASK; 111937820Sphk int pri = LOG_PRI(f->f_prevpri); 112076944Sdwmalone const char *f_s = NULL; 112137820Sphk char f_n[5]; /* Hollow laugh */ 112276944Sdwmalone const char *p_s = NULL; 112337820Sphk char p_n[5]; /* Hollow laugh */ 112437820Sphk 112537820Sphk if (LogFacPri > 1) { 112637820Sphk CODE *c; 112737820Sphk 112855906Sru for (c = facilitynames; c->c_name; c++) { 112937820Sphk if (c->c_val == fac) { 113037820Sphk f_s = c->c_name; 113137820Sphk break; 113237820Sphk } 113337820Sphk } 113455906Sru for (c = prioritynames; c->c_name; c++) { 113537820Sphk if (c->c_val == pri) { 113637820Sphk p_s = c->c_name; 113737820Sphk break; 113837820Sphk } 113937820Sphk } 114037820Sphk } 114137820Sphk if (!f_s) { 114237820Sphk snprintf(f_n, sizeof f_n, "%d", LOG_FAC(fac)); 114337820Sphk f_s = f_n; 114437820Sphk } 114537820Sphk if (!p_s) { 114637820Sphk snprintf(p_n, sizeof p_n, "%d", pri); 114737820Sphk p_s = p_n; 114837820Sphk } 114937820Sphk snprintf(fp_buf, sizeof fp_buf, "<%s.%s> ", f_s, p_s); 115037820Sphk v->iov_base = fp_buf; 115137820Sphk v->iov_len = strlen(fp_buf); 115237820Sphk } else { 1153137569Sglebius v->iov_base = nul; 115437820Sphk v->iov_len = 0; 115537820Sphk } 115637820Sphk v++; 115737820Sphk 11581553Srgrimes v->iov_base = f->f_prevhost; 11591553Srgrimes v->iov_len = strlen(v->iov_base); 11601553Srgrimes v++; 1161129756Sdwmalone v->iov_base = space; 11621553Srgrimes v->iov_len = 1; 11631553Srgrimes v++; 11641553Srgrimes 11651553Srgrimes if (msg) { 116683243Sdd wmsg = strdup(msg); /* XXX iov_base needs a `const' sibling. */ 116784168Sdes if (wmsg == NULL) { 116884168Sdes logerror("strdup"); 116984168Sdes exit(1); 117084168Sdes } 117183243Sdd v->iov_base = wmsg; 11721553Srgrimes v->iov_len = strlen(msg); 11731553Srgrimes } else if (f->f_prevcount > 1) { 11741553Srgrimes v->iov_base = repbuf; 117582724Skris v->iov_len = snprintf(repbuf, sizeof repbuf, 117682724Skris "last message repeated %d times", f->f_prevcount); 1177174533Sobrien } else if (f->f_prevline) { 11781553Srgrimes v->iov_base = f->f_prevline; 11791553Srgrimes v->iov_len = f->f_prevlen; 1180174533Sobrien } else { 1181174533Sobrien return; 11821553Srgrimes } 11831553Srgrimes v++; 11841553Srgrimes 11851553Srgrimes dprintf("Logging to %s", TypeNames[f->f_type]); 11861553Srgrimes f->f_time = now; 11871553Srgrimes 11881553Srgrimes switch (f->f_type) { 1189157821Sjulian int port; 11901553Srgrimes case F_UNUSED: 11911553Srgrimes dprintf("\n"); 11921553Srgrimes break; 11931553Srgrimes 11941553Srgrimes case F_FORW: 1195157821Sjulian port = (int)ntohs(((struct sockaddr_in *) 1196157821Sjulian (f->f_un.f_forw.f_addr->ai_addr))->sin_port); 1197157821Sjulian if (port != 514) { 1198157821Sjulian dprintf(" %s:%d\n", f->f_un.f_forw.f_hname, port); 1199157821Sjulian } else { 1200157821Sjulian dprintf(" %s\n", f->f_un.f_forw.f_hname); 1201157821Sjulian } 120237209Ssteve /* check for local vs remote messages */ 120349940Sbrian if (strcasecmp(f->f_prevhost, LocalHostName)) 120437209Ssteve l = snprintf(line, sizeof line - 1, 120537209Ssteve "<%d>%.15s Forwarded from %s: %s", 1206129756Sdwmalone f->f_prevpri, (char *)iov[0].iov_base, 1207129756Sdwmalone f->f_prevhost, (char *)iov[5].iov_base); 120837209Ssteve else 120937209Ssteve l = snprintf(line, sizeof line - 1, "<%d>%.15s %s", 1210129756Sdwmalone f->f_prevpri, (char *)iov[0].iov_base, 1211129756Sdwmalone (char *)iov[5].iov_base); 121281977Sbrian if (l < 0) 121381977Sbrian l = 0; 121481977Sbrian else if (l > MAXLINE) 12151553Srgrimes l = MAXLINE; 121670099Sume 121770099Sume if (finet) { 121870099Sume for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) { 121970099Sume for (i = 0; i < *finet; i++) { 1220137569Sglebius#if 0 122170099Sume /* 122270099Sume * should we check AF first, or just 122370099Sume * trial and error? FWD 122470099Sume */ 122570099Sume if (r->ai_family == 1226137569Sglebius address_family_of(finet[i+1])) 122770099Sume#endif 122870099Sume lsent = sendto(finet[i+1], line, l, 0, 122970099Sume r->ai_addr, r->ai_addrlen); 1230137569Sglebius if (lsent == l) 123170099Sume break; 123270099Sume } 1233137569Sglebius if (lsent == l && !send_to_all) 123470099Sume break; 123570099Sume } 1236102401Scjc dprintf("lsent/l: %d/%d\n", lsent, l); 123770099Sume if (lsent != l) { 123870099Sume int e = errno; 1239102401Scjc logerror("sendto"); 124070099Sume errno = e; 1241102401Scjc switch (errno) { 1242146414Scsjp case ENOBUFS: 1243146414Scsjp case ENETDOWN: 1244102401Scjc case EHOSTUNREACH: 1245102401Scjc case EHOSTDOWN: 1246102401Scjc break; 1247102401Scjc /* case EBADF: */ 1248102401Scjc /* case EACCES: */ 1249102401Scjc /* case ENOTSOCK: */ 1250102401Scjc /* case EFAULT: */ 1251102401Scjc /* case EMSGSIZE: */ 1252102401Scjc /* case EAGAIN: */ 1253102401Scjc /* case ENOBUFS: */ 1254102401Scjc /* case ECONNREFUSED: */ 1255102401Scjc default: 1256122814Sdwmalone dprintf("removing entry\n"); 1257102401Scjc f->f_type = F_UNUSED; 1258102401Scjc break; 1259102401Scjc } 126070099Sume } 12611553Srgrimes } 12621553Srgrimes break; 12631553Srgrimes 12641553Srgrimes case F_FILE: 12651553Srgrimes dprintf(" %s\n", f->f_un.f_fname); 1266129756Sdwmalone v->iov_base = lf; 126719854Speter v->iov_len = 1; 1268186234Sobrien if (writev(f->f_file, iov, IOV_SIZE) < 0) { 1269157311Scsjp /* 1270157311Scsjp * If writev(2) fails for potentially transient errors 1271174533Sobrien * like the filesystem being full, ignore it. 1272174533Sobrien * Otherwise remove this logfile from the list. 1273157311Scsjp */ 1274157311Scsjp if (errno != ENOSPC) { 1275157311Scsjp int e = errno; 1276157311Scsjp (void)close(f->f_file); 1277157311Scsjp f->f_type = F_UNUSED; 1278157311Scsjp errno = e; 1279157311Scsjp logerror(f->f_un.f_fname); 1280157311Scsjp } 1281131589Scperciva } else if ((flags & SYNC_FILE) && (f->f_flags & FFLAG_SYNC)) { 1282131589Scperciva f->f_flags |= FFLAG_NEEDSYNC; 1283131589Scperciva needdofsync = 1; 1284131589Scperciva } 12851553Srgrimes break; 12861553Srgrimes 128722984Sjoerg case F_PIPE: 128822984Sjoerg dprintf(" %s\n", f->f_un.f_pipe.f_pname); 1289129756Sdwmalone v->iov_base = lf; 129022984Sjoerg v->iov_len = 1; 129122984Sjoerg if (f->f_un.f_pipe.f_pid == 0) { 129222984Sjoerg if ((f->f_file = p_open(f->f_un.f_pipe.f_pname, 129322984Sjoerg &f->f_un.f_pipe.f_pid)) < 0) { 129422984Sjoerg f->f_type = F_UNUSED; 129522984Sjoerg logerror(f->f_un.f_pipe.f_pname); 129622984Sjoerg break; 129722984Sjoerg } 129822984Sjoerg } 1299186234Sobrien if (writev(f->f_file, iov, IOV_SIZE) < 0) { 130022984Sjoerg int e = errno; 130122984Sjoerg (void)close(f->f_file); 130222984Sjoerg if (f->f_un.f_pipe.f_pid > 0) 130357558Sjoerg deadq_enter(f->f_un.f_pipe.f_pid, 130457558Sjoerg f->f_un.f_pipe.f_pname); 130522984Sjoerg f->f_un.f_pipe.f_pid = 0; 130622984Sjoerg errno = e; 130722984Sjoerg logerror(f->f_un.f_pipe.f_pname); 130822984Sjoerg } 130922984Sjoerg break; 131022984Sjoerg 131119962Speter case F_CONSOLE: 131219962Speter if (flags & IGN_CONS) { 131319962Speter dprintf(" (ignored)\n"); 131419962Speter break; 131519962Speter } 131619962Speter /* FALLTHROUGH */ 131719962Speter 131819854Speter case F_TTY: 131919962Speter dprintf(" %s%s\n", _PATH_DEV, f->f_un.f_fname); 1320129756Sdwmalone v->iov_base = crlf; 132119854Speter v->iov_len = 2; 132219854Speter 132319854Speter errno = 0; /* ttymsg() only sometimes returns an errno */ 1324186234Sobrien if ((msgret = ttymsg(iov, IOV_SIZE, f->f_un.f_fname, 10))) { 132519854Speter f->f_type = F_UNUSED; 132619854Speter logerror(msgret); 132719854Speter } 132819854Speter break; 132919854Speter 13301553Srgrimes case F_USERS: 13311553Srgrimes case F_WALL: 13321553Srgrimes dprintf("\n"); 1333129756Sdwmalone v->iov_base = crlf; 13341553Srgrimes v->iov_len = 2; 1335186234Sobrien wallmsg(f, iov, IOV_SIZE); 13361553Srgrimes break; 13371553Srgrimes } 13381553Srgrimes f->f_prevcount = 0; 1339182605Sobrien free(wmsg); 13401553Srgrimes} 13411553Srgrimes 13421553Srgrimes/* 13431553Srgrimes * WALLMSG -- Write a message to the world at large 13441553Srgrimes * 13451553Srgrimes * Write the specified message to either the entire 13461553Srgrimes * world, or a list of approved users. 13471553Srgrimes */ 134893078Sdesstatic void 1349186234Sobrienwallmsg(struct filed *f, struct iovec *iov, const int iovlen) 13501553Srgrimes{ 13511553Srgrimes static int reenter; /* avoid calling ourselves */ 1352200954Sed struct utmpx *ut; 13531553Srgrimes int i; 135483243Sdd const char *p; 13551553Srgrimes 13561553Srgrimes if (reenter++) 13571553Srgrimes return; 1358200954Sed setutxent(); 13591553Srgrimes /* NOSTRICT */ 1360200954Sed while ((ut = getutxent()) != NULL) { 1361200954Sed if (ut->ut_type != USER_PROCESS) 13621553Srgrimes continue; 13631553Srgrimes if (f->f_type == F_WALL) { 1364200954Sed if ((p = ttymsg(iov, iovlen, ut->ut_line, 1365200954Sed TTYMSGTIME)) != NULL) { 13661553Srgrimes errno = 0; /* already in msg */ 13671553Srgrimes logerror(p); 13681553Srgrimes } 13691553Srgrimes continue; 13701553Srgrimes } 13711553Srgrimes /* should we send the message to this user? */ 13721553Srgrimes for (i = 0; i < MAXUNAMES; i++) { 13731553Srgrimes if (!f->f_un.f_uname[i][0]) 13741553Srgrimes break; 1375200954Sed if (!strcmp(f->f_un.f_uname[i], ut->ut_user)) { 1376200954Sed if ((p = ttymsg(iov, iovlen, ut->ut_line, 1377200954Sed TTYMSGTIME)) != NULL) { 13781553Srgrimes errno = 0; /* already in msg */ 13791553Srgrimes logerror(p); 13801553Srgrimes } 13811553Srgrimes break; 13821553Srgrimes } 13831553Srgrimes } 13841553Srgrimes } 1385200954Sed endutxent(); 13861553Srgrimes reenter = 0; 13871553Srgrimes} 13881553Srgrimes 138993078Sdesstatic void 139093078Sdesreapchild(int signo __unused) 13911553Srgrimes{ 139257558Sjoerg int status; 139322984Sjoerg pid_t pid; 139422984Sjoerg struct filed *f; 13951553Srgrimes 139622984Sjoerg while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) { 139722984Sjoerg if (!Initialized) 139822984Sjoerg /* Don't tell while we are initting. */ 139922984Sjoerg continue; 140022984Sjoerg 140122984Sjoerg /* First, look if it's a process from the dead queue. */ 140257558Sjoerg if (deadq_remove(pid)) 140357558Sjoerg goto oncemore; 140422984Sjoerg 140522984Sjoerg /* Now, look in list of active processes. */ 140622984Sjoerg for (f = Files; f; f = f->f_next) 140722984Sjoerg if (f->f_type == F_PIPE && 140822984Sjoerg f->f_un.f_pipe.f_pid == pid) { 140922984Sjoerg (void)close(f->f_file); 141022984Sjoerg f->f_un.f_pipe.f_pid = 0; 141157558Sjoerg log_deadchild(pid, status, 141257558Sjoerg f->f_un.f_pipe.f_pname); 141322984Sjoerg break; 141422984Sjoerg } 141522984Sjoerg oncemore: 141655971Sdes continue; 141722984Sjoerg } 14181553Srgrimes} 14191553Srgrimes 14201553Srgrimes/* 14211553Srgrimes * Return a printable representation of a host address. 14221553Srgrimes */ 142393078Sdesstatic const char * 142493078Sdescvthname(struct sockaddr *f) 14251553Srgrimes{ 1426114676Sgshapiro int error, hl; 142742114Scwt sigset_t omask, nmask; 142870099Sume static char hname[NI_MAXHOST], ip[NI_MAXHOST]; 14291553Srgrimes 143070099Sume error = getnameinfo((struct sockaddr *)f, 143170099Sume ((struct sockaddr *)f)->sa_len, 1432146187Sume ip, sizeof ip, NULL, 0, NI_NUMERICHOST); 143370099Sume dprintf("cvthname(%s)\n", ip); 14341553Srgrimes 143570099Sume if (error) { 143670099Sume dprintf("Malformed from address %s\n", gai_strerror(error)); 14371553Srgrimes return ("???"); 14381553Srgrimes } 143970099Sume if (!resolve) 144070099Sume return (ip); 144170099Sume 144242114Scwt sigemptyset(&nmask); 144342114Scwt sigaddset(&nmask, SIGHUP); 144442114Scwt sigprocmask(SIG_BLOCK, &nmask, &omask); 144570099Sume error = getnameinfo((struct sockaddr *)f, 144670099Sume ((struct sockaddr *)f)->sa_len, 1447146187Sume hname, sizeof hname, NULL, 0, NI_NAMEREQD); 144842114Scwt sigprocmask(SIG_SETMASK, &omask, NULL); 144970099Sume if (error) { 145070099Sume dprintf("Host name for your address (%s) unknown\n", ip); 145170099Sume return (ip); 14521553Srgrimes } 1453114676Sgshapiro hl = strlen(hname); 1454114676Sgshapiro if (hl > 0 && hname[hl-1] == '.') 1455114676Sgshapiro hname[--hl] = '\0'; 1456115108Sgshapiro trimdomain(hname, hl); 145770099Sume return (hname); 14581553Srgrimes} 14591553Srgrimes 146093078Sdesstatic void 146193078Sdesdodie(int signo) 14621553Srgrimes{ 14631553Srgrimes 146482724Skris WantDie = signo; 146582724Skris} 14661553Srgrimes 146793078Sdesstatic void 146893078Sdesdomark(int signo __unused) 146982724Skris{ 147022984Sjoerg 147182724Skris MarkSet = 1; 14721553Srgrimes} 14731553Srgrimes 14741553Srgrimes/* 14751553Srgrimes * Print syslogd errors some place. 14761553Srgrimes */ 147793078Sdesstatic void 147893078Sdeslogerror(const char *type) 14791553Srgrimes{ 148022984Sjoerg char buf[512]; 1481122815Sdwmalone static int recursed = 0; 14821553Srgrimes 1483122815Sdwmalone /* If there's an error while trying to log an error, give up. */ 1484122815Sdwmalone if (recursed) 1485122815Sdwmalone return; 1486122815Sdwmalone recursed++; 14871553Srgrimes if (errno) 14881553Srgrimes (void)snprintf(buf, 148929623Sbrian sizeof buf, "syslogd: %s: %s", type, strerror(errno)); 14901553Srgrimes else 149129623Sbrian (void)snprintf(buf, sizeof buf, "syslogd: %s", type); 14921553Srgrimes errno = 0; 14931553Srgrimes dprintf("%s\n", buf); 14941553Srgrimes logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); 1495122815Sdwmalone recursed--; 14961553Srgrimes} 14971553Srgrimes 149893078Sdesstatic void 149993078Sdesdie(int signo) 15001553Srgrimes{ 15011553Srgrimes struct filed *f; 1502137232Sglebius struct funix *fx; 150323868Sjoerg int was_initialized; 15041553Srgrimes char buf[100]; 15051553Srgrimes 150623868Sjoerg was_initialized = Initialized; 150722984Sjoerg Initialized = 0; /* Don't log SIGCHLDs. */ 15081553Srgrimes for (f = Files; f != NULL; f = f->f_next) { 15091553Srgrimes /* flush any pending output */ 15101553Srgrimes if (f->f_prevcount) 15111553Srgrimes fprintlog(f, 0, (char *)NULL); 1512129855Sdwmalone if (f->f_type == F_PIPE && f->f_un.f_pipe.f_pid > 0) { 151322984Sjoerg (void)close(f->f_file); 1514129855Sdwmalone f->f_un.f_pipe.f_pid = 0; 1515129855Sdwmalone } 15161553Srgrimes } 151723868Sjoerg Initialized = was_initialized; 15181553Srgrimes if (signo) { 15191553Srgrimes dprintf("syslogd: exiting on signal %d\n", signo); 152082724Skris (void)snprintf(buf, sizeof(buf), "exiting on signal %d", signo); 15211553Srgrimes errno = 0; 15221553Srgrimes logerror(buf); 15231553Srgrimes } 1524137232Sglebius STAILQ_FOREACH(fx, &funixes, next) 1525137232Sglebius (void)unlink(fx->name); 1526149425Spjd pidfile_remove(pfh); 1527137232Sglebius 152819854Speter exit(1); 15291553Srgrimes} 15301553Srgrimes 15311553Srgrimes/* 15321553Srgrimes * INIT -- Initialize syslogd from configuration table 15331553Srgrimes */ 153493078Sdesstatic void 153593078Sdesinit(int signo) 15361553Srgrimes{ 15371553Srgrimes int i; 15381553Srgrimes FILE *cf; 15391553Srgrimes struct filed *f, *next, **nextp; 15401553Srgrimes char *p; 15411553Srgrimes char cline[LINE_MAX]; 15425278Swollman char prog[NAME_MAX+1]; 154374053Sbrian char host[MAXHOSTNAMELEN]; 154482442Scjc char oldLocalHostName[MAXHOSTNAMELEN]; 154582442Scjc char hostMsg[2*MAXHOSTNAMELEN+40]; 154687000Sdd char bootfileMsg[LINE_MAX]; 15471553Srgrimes 15481553Srgrimes dprintf("init\n"); 15491553Srgrimes 15501553Srgrimes /* 155182442Scjc * Load hostname (may have changed). 155282442Scjc */ 155382442Scjc if (signo != 0) 155482442Scjc (void)strlcpy(oldLocalHostName, LocalHostName, 155582442Scjc sizeof(oldLocalHostName)); 155682442Scjc if (gethostname(LocalHostName, sizeof(LocalHostName))) 155782442Scjc err(EX_OSERR, "gethostname() failed"); 155882442Scjc if ((p = strchr(LocalHostName, '.')) != NULL) { 155982442Scjc *p++ = '\0'; 156082442Scjc LocalDomain = p; 156193080Sdes } else { 156282442Scjc LocalDomain = ""; 156393080Sdes } 156482442Scjc 156582442Scjc /* 15661553Srgrimes * Close all open log files. 15671553Srgrimes */ 15681553Srgrimes Initialized = 0; 15691553Srgrimes for (f = Files; f != NULL; f = next) { 15701553Srgrimes /* flush any pending output */ 15711553Srgrimes if (f->f_prevcount) 15721553Srgrimes fprintlog(f, 0, (char *)NULL); 15731553Srgrimes 15741553Srgrimes switch (f->f_type) { 15751553Srgrimes case F_FILE: 15761553Srgrimes case F_FORW: 157719962Speter case F_CONSOLE: 157819962Speter case F_TTY: 157920290Speter (void)close(f->f_file); 158019962Speter break; 158122984Sjoerg case F_PIPE: 1582129855Sdwmalone if (f->f_un.f_pipe.f_pid > 0) { 1583129855Sdwmalone (void)close(f->f_file); 158457558Sjoerg deadq_enter(f->f_un.f_pipe.f_pid, 158557558Sjoerg f->f_un.f_pipe.f_pname); 1586129855Sdwmalone } 158722984Sjoerg f->f_un.f_pipe.f_pid = 0; 158822984Sjoerg break; 15891553Srgrimes } 15901553Srgrimes next = f->f_next; 159164195Sdwmalone if (f->f_program) free(f->f_program); 159263795Sdwmalone if (f->f_host) free(f->f_host); 15931553Srgrimes free((char *)f); 15941553Srgrimes } 15951553Srgrimes Files = NULL; 15961553Srgrimes nextp = &Files; 15971553Srgrimes 15981553Srgrimes /* open the configuration file */ 15991553Srgrimes if ((cf = fopen(ConfFile, "r")) == NULL) { 16001553Srgrimes dprintf("cannot open %s\n", ConfFile); 16011553Srgrimes *nextp = (struct filed *)calloc(1, sizeof(*f)); 160284168Sdes if (*nextp == NULL) { 160384168Sdes logerror("calloc"); 160484168Sdes exit(1); 160584168Sdes } 160663795Sdwmalone cfline("*.ERR\t/dev/console", *nextp, "*", "*"); 16071553Srgrimes (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); 160884168Sdes if ((*nextp)->f_next == NULL) { 160984168Sdes logerror("calloc"); 161084168Sdes exit(1); 161184168Sdes } 161263795Sdwmalone cfline("*.PANIC\t*", (*nextp)->f_next, "*", "*"); 16131553Srgrimes Initialized = 1; 16141553Srgrimes return; 16151553Srgrimes } 16161553Srgrimes 16171553Srgrimes /* 16181553Srgrimes * Foreach line in the conf table, open that file. 16191553Srgrimes */ 16201553Srgrimes f = NULL; 162182724Skris (void)strlcpy(host, "*", sizeof(host)); 162282724Skris (void)strlcpy(prog, "*", sizeof(prog)); 16231553Srgrimes while (fgets(cline, sizeof(cline), cf) != NULL) { 16241553Srgrimes /* 16251553Srgrimes * check for end-of-section, comments, strip off trailing 16265278Swollman * spaces and newline character. #!prog is treated specially: 16275278Swollman * following lines apply only to that program. 16281553Srgrimes */ 16291553Srgrimes for (p = cline; isspace(*p); ++p) 16301553Srgrimes continue; 16315278Swollman if (*p == 0) 16321553Srgrimes continue; 163364195Sdwmalone if (*p == '#') { 16345278Swollman p++; 163563795Sdwmalone if (*p != '!' && *p != '+' && *p != '-') 16365278Swollman continue; 16375278Swollman } 163863795Sdwmalone if (*p == '+' || *p == '-') { 163983392Sdes host[0] = *p++; 164083388Sdes while (isspace(*p)) 164183388Sdes p++; 164263795Sdwmalone if ((!*p) || (*p == '*')) { 164382724Skris (void)strlcpy(host, "*", sizeof(host)); 164463795Sdwmalone continue; 164563795Sdwmalone } 164663795Sdwmalone if (*p == '@') 164763795Sdwmalone p = LocalHostName; 164874053Sbrian for (i = 1; i < MAXHOSTNAMELEN - 1; i++) { 1649111221Sthomas if (!isalnum(*p) && *p != '.' && *p != '-' 1650139384Sdwmalone && *p != ',' && *p != ':' && *p != '%') 165163795Sdwmalone break; 165263795Sdwmalone host[i] = *p++; 165363795Sdwmalone } 165463795Sdwmalone host[i] = '\0'; 165563795Sdwmalone continue; 165663795Sdwmalone } 165764195Sdwmalone if (*p == '!') { 16585278Swollman p++; 165964195Sdwmalone while (isspace(*p)) p++; 166064195Sdwmalone if ((!*p) || (*p == '*')) { 166182724Skris (void)strlcpy(prog, "*", sizeof(prog)); 16625278Swollman continue; 16635278Swollman } 166464195Sdwmalone for (i = 0; i < NAME_MAX; i++) { 1665139381Sdwmalone if (!isprint(p[i]) || isspace(p[i])) 16665278Swollman break; 16675278Swollman prog[i] = p[i]; 16685278Swollman } 16695278Swollman prog[i] = 0; 16705278Swollman continue; 16715278Swollman } 1672180380Ssobomax for (p = cline + 1; *p != '\0'; p++) { 1673180380Ssobomax if (*p != '#') 1674180380Ssobomax continue; 1675180380Ssobomax if (*(p - 1) == '\\') { 1676180380Ssobomax strcpy(p - 1, p); 1677180380Ssobomax p--; 1678180380Ssobomax continue; 1679180380Ssobomax } 1680180380Ssobomax *p = '\0'; 1681180380Ssobomax break; 1682180380Ssobomax } 1683129854Sdwmalone for (i = strlen(cline) - 1; i >= 0 && isspace(cline[i]); i--) 1684129854Sdwmalone cline[i] = '\0'; 16851553Srgrimes f = (struct filed *)calloc(1, sizeof(*f)); 168684168Sdes if (f == NULL) { 168784168Sdes logerror("calloc"); 168884168Sdes exit(1); 168984168Sdes } 16901553Srgrimes *nextp = f; 16911553Srgrimes nextp = &f->f_next; 169263795Sdwmalone cfline(cline, f, prog, host); 16931553Srgrimes } 16941553Srgrimes 16951553Srgrimes /* close the configuration file */ 16961553Srgrimes (void)fclose(cf); 16971553Srgrimes 16981553Srgrimes Initialized = 1; 16991553Srgrimes 17001553Srgrimes if (Debug) { 1701157821Sjulian int port; 17021553Srgrimes for (f = Files; f; f = f->f_next) { 17031553Srgrimes for (i = 0; i <= LOG_NFACILITIES; i++) 17041553Srgrimes if (f->f_pmask[i] == INTERNAL_NOPRI) 17051553Srgrimes printf("X "); 17061553Srgrimes else 17071553Srgrimes printf("%d ", f->f_pmask[i]); 17081553Srgrimes printf("%s: ", TypeNames[f->f_type]); 17091553Srgrimes switch (f->f_type) { 17101553Srgrimes case F_FILE: 17111553Srgrimes printf("%s", f->f_un.f_fname); 17121553Srgrimes break; 17131553Srgrimes 171419962Speter case F_CONSOLE: 171519962Speter case F_TTY: 171619962Speter printf("%s%s", _PATH_DEV, f->f_un.f_fname); 171719962Speter break; 171819962Speter 17191553Srgrimes case F_FORW: 1720157821Sjulian port = (int)ntohs(((struct sockaddr_in *) 1721157821Sjulian (f->f_un.f_forw.f_addr->ai_addr))->sin_port); 1722157821Sjulian if (port != 514) { 1723157821Sjulian printf("%s:%d", 1724157821Sjulian f->f_un.f_forw.f_hname, port); 1725157821Sjulian } else { 1726157821Sjulian printf("%s", f->f_un.f_forw.f_hname); 1727157821Sjulian } 17281553Srgrimes break; 17291553Srgrimes 173022984Sjoerg case F_PIPE: 173122984Sjoerg printf("%s", f->f_un.f_pipe.f_pname); 173222984Sjoerg break; 173322984Sjoerg 17341553Srgrimes case F_USERS: 17351553Srgrimes for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++) 17361553Srgrimes printf("%s, ", f->f_un.f_uname[i]); 17371553Srgrimes break; 17381553Srgrimes } 173964195Sdwmalone if (f->f_program) 17405278Swollman printf(" (%s)", f->f_program); 17411553Srgrimes printf("\n"); 17421553Srgrimes } 17431553Srgrimes } 17441553Srgrimes 17451553Srgrimes logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); 17461553Srgrimes dprintf("syslogd: restarted\n"); 174782442Scjc /* 174882442Scjc * Log a change in hostname, but only on a restart. 174982442Scjc */ 175082442Scjc if (signo != 0 && strcmp(oldLocalHostName, LocalHostName) != 0) { 175182442Scjc (void)snprintf(hostMsg, sizeof(hostMsg), 175282442Scjc "syslogd: hostname changed, \"%s\" to \"%s\"", 175382442Scjc oldLocalHostName, LocalHostName); 175482442Scjc logmsg(LOG_SYSLOG|LOG_INFO, hostMsg, LocalHostName, ADDDATE); 175582442Scjc dprintf("%s\n", hostMsg); 175682442Scjc } 175787000Sdd /* 175887000Sdd * Log the kernel boot file if we aren't going to use it as 175987000Sdd * the prefix, and if this is *not* a restart. 176087000Sdd */ 176187000Sdd if (signo == 0 && !use_bootfile) { 176287000Sdd (void)snprintf(bootfileMsg, sizeof(bootfileMsg), 176387000Sdd "syslogd: kernel boot file is %s", bootfile); 176487000Sdd logmsg(LOG_KERN|LOG_INFO, bootfileMsg, LocalHostName, ADDDATE); 176587000Sdd dprintf("%s\n", bootfileMsg); 176687000Sdd } 17671553Srgrimes} 17681553Srgrimes 17691553Srgrimes/* 17701553Srgrimes * Crack a configuration file line 17711553Srgrimes */ 177293078Sdesstatic void 177393078Sdescfline(const char *line, struct filed *f, const char *prog, const char *host) 17741553Srgrimes{ 177570099Sume struct addrinfo hints, *res; 1776129865Sdwmalone int error, i, pri, syncfile; 177783243Sdd const char *p, *q; 177883243Sdd char *bp; 17791553Srgrimes char buf[MAXLINE], ebuf[100]; 17801553Srgrimes 178163795Sdwmalone dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line, prog, host); 17821553Srgrimes 17831553Srgrimes errno = 0; /* keep strerror() stuff out of logerror messages */ 17841553Srgrimes 17851553Srgrimes /* clear out file entry */ 17861553Srgrimes memset(f, 0, sizeof(*f)); 17871553Srgrimes for (i = 0; i <= LOG_NFACILITIES; i++) 17881553Srgrimes f->f_pmask[i] = INTERNAL_NOPRI; 17891553Srgrimes 179063795Sdwmalone /* save hostname if any */ 179164195Sdwmalone if (host && *host == '*') 179264195Sdwmalone host = NULL; 179383392Sdes if (host) { 1794114676Sgshapiro int hl; 179583392Sdes 179664194Sdwmalone f->f_host = strdup(host); 179784168Sdes if (f->f_host == NULL) { 179884168Sdes logerror("strdup"); 179984168Sdes exit(1); 180084168Sdes } 180183392Sdes hl = strlen(f->f_host); 1802114676Sgshapiro if (hl > 0 && f->f_host[hl-1] == '.') 180383392Sdes f->f_host[--hl] = '\0'; 1804115108Sgshapiro trimdomain(f->f_host, hl); 180583392Sdes } 180663795Sdwmalone 18075278Swollman /* save program name if any */ 180864195Sdwmalone if (prog && *prog == '*') 180964195Sdwmalone prog = NULL; 181084168Sdes if (prog) { 181164195Sdwmalone f->f_program = strdup(prog); 181284168Sdes if (f->f_program == NULL) { 181384168Sdes logerror("strdup"); 181484168Sdes exit(1); 181584168Sdes } 181684168Sdes } 18175278Swollman 18181553Srgrimes /* scan through the list of selectors */ 181941498Sjkh for (p = line; *p && *p != '\t' && *p != ' ';) { 182037820Sphk int pri_done; 182137820Sphk int pri_cmp; 1822102940Sdwmalone int pri_invert; 18231553Srgrimes 18241553Srgrimes /* find the end of this facility name list */ 182541498Sjkh for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.'; ) 18261553Srgrimes continue; 18271553Srgrimes 182837820Sphk /* get the priority comparison */ 182937820Sphk pri_cmp = 0; 183037820Sphk pri_done = 0; 1831102940Sdwmalone pri_invert = 0; 1832102940Sdwmalone if (*q == '!') { 1833102940Sdwmalone pri_invert = 1; 1834102940Sdwmalone q++; 1835102940Sdwmalone } 183637820Sphk while (!pri_done) { 183737820Sphk switch (*q) { 183837820Sphk case '<': 183937820Sphk pri_cmp |= PRI_LT; 184037820Sphk q++; 184137820Sphk break; 184237820Sphk case '=': 184337820Sphk pri_cmp |= PRI_EQ; 184437820Sphk q++; 184537820Sphk break; 184637820Sphk case '>': 184737820Sphk pri_cmp |= PRI_GT; 184837820Sphk q++; 184937820Sphk break; 185037820Sphk default: 185137820Sphk pri_done++; 185237820Sphk break; 185337820Sphk } 185437820Sphk } 185537820Sphk 18561553Srgrimes /* collect priority name */ 185741498Sjkh for (bp = buf; *q && !strchr("\t,; ", *q); ) 18581553Srgrimes *bp++ = *q++; 18591553Srgrimes *bp = '\0'; 18601553Srgrimes 18611553Srgrimes /* skip cruft */ 186241498Sjkh while (strchr(",;", *q)) 18631553Srgrimes q++; 18641553Srgrimes 18651553Srgrimes /* decode priority name */ 186693080Sdes if (*buf == '*') { 1867174533Sobrien pri = LOG_PRIMASK; 1868102940Sdwmalone pri_cmp = PRI_LT | PRI_EQ | PRI_GT; 186993080Sdes } else { 1870129854Sdwmalone /* Ignore trailing spaces. */ 1871129854Sdwmalone for (i = strlen(buf) - 1; i >= 0 && buf[i] == ' '; i--) 1872129854Sdwmalone buf[i] = '\0'; 1873129854Sdwmalone 18741553Srgrimes pri = decode(buf, prioritynames); 18751553Srgrimes if (pri < 0) { 1876244881Smarkj errno = 0; 187729623Sbrian (void)snprintf(ebuf, sizeof ebuf, 18781553Srgrimes "unknown priority name \"%s\"", buf); 18791553Srgrimes logerror(ebuf); 18801553Srgrimes return; 18811553Srgrimes } 18821553Srgrimes } 1883102940Sdwmalone if (!pri_cmp) 1884102940Sdwmalone pri_cmp = (UniquePriority) 1885102940Sdwmalone ? (PRI_EQ) 1886102940Sdwmalone : (PRI_EQ | PRI_GT) 1887102940Sdwmalone ; 1888102940Sdwmalone if (pri_invert) 1889102940Sdwmalone pri_cmp ^= PRI_LT | PRI_EQ | PRI_GT; 18901553Srgrimes 18911553Srgrimes /* scan facilities */ 189241498Sjkh while (*p && !strchr("\t.; ", *p)) { 189341498Sjkh for (bp = buf; *p && !strchr("\t,;. ", *p); ) 18941553Srgrimes *bp++ = *p++; 18951553Srgrimes *bp = '\0'; 189637820Sphk 189793080Sdes if (*buf == '*') { 189837820Sphk for (i = 0; i < LOG_NFACILITIES; i++) { 18991553Srgrimes f->f_pmask[i] = pri; 190037820Sphk f->f_pcmp[i] = pri_cmp; 190137820Sphk } 190293080Sdes } else { 19031553Srgrimes i = decode(buf, facilitynames); 19041553Srgrimes if (i < 0) { 1905244881Smarkj errno = 0; 190629623Sbrian (void)snprintf(ebuf, sizeof ebuf, 19071553Srgrimes "unknown facility name \"%s\"", 19081553Srgrimes buf); 19091553Srgrimes logerror(ebuf); 19101553Srgrimes return; 19111553Srgrimes } 19121553Srgrimes f->f_pmask[i >> 3] = pri; 191337820Sphk f->f_pcmp[i >> 3] = pri_cmp; 19141553Srgrimes } 19151553Srgrimes while (*p == ',' || *p == ' ') 19161553Srgrimes p++; 19171553Srgrimes } 19181553Srgrimes 19191553Srgrimes p = q; 19201553Srgrimes } 19211553Srgrimes 19221553Srgrimes /* skip to action part */ 192341498Sjkh while (*p == '\t' || *p == ' ') 19241553Srgrimes p++; 19251553Srgrimes 1926129865Sdwmalone if (*p == '-') { 1927129865Sdwmalone syncfile = 0; 1928129865Sdwmalone p++; 1929129865Sdwmalone } else 1930129865Sdwmalone syncfile = 1; 1931129865Sdwmalone 193293079Sdes switch (*p) { 19331553Srgrimes case '@': 1934157821Sjulian { 1935157821Sjulian char *tp; 1936241473Seadler char endkey = ':'; 1937157821Sjulian /* 1938157821Sjulian * scan forward to see if there is a port defined. 1939157821Sjulian * so we can't use strlcpy.. 1940157821Sjulian */ 1941157821Sjulian i = sizeof(f->f_un.f_forw.f_hname); 1942157821Sjulian tp = f->f_un.f_forw.f_hname; 1943157821Sjulian p++; 1944157821Sjulian 1945241473Seadler /* 1946241473Seadler * an ipv6 address should start with a '[' in that case 1947241473Seadler * we should scan for a ']' 1948241473Seadler */ 1949241473Seadler if (*p == '[') { 1950241473Seadler p++; 1951241473Seadler endkey = ']'; 1952241473Seadler } 1953241473Seadler while (*p && (*p != endkey) && (i-- > 0)) { 1954157821Sjulian *tp++ = *p++; 1955157821Sjulian } 1956241473Seadler if (endkey == ']' && *p == endkey) 1957241473Seadler p++; 1958157821Sjulian *tp = '\0'; 1959157821Sjulian } 1960157821Sjulian /* See if we copied a domain and have a port */ 1961157821Sjulian if (*p == ':') 1962157821Sjulian p++; 1963157821Sjulian else 1964157821Sjulian p = NULL; 1965174316Sobrien 196670099Sume memset(&hints, 0, sizeof(hints)); 196770099Sume hints.ai_family = family; 196870099Sume hints.ai_socktype = SOCK_DGRAM; 1969157821Sjulian error = getaddrinfo(f->f_un.f_forw.f_hname, 1970174316Sobrien p ? p : "syslog", &hints, &res); 197170099Sume if (error) { 197270099Sume logerror(gai_strerror(error)); 19731553Srgrimes break; 19741553Srgrimes } 197570099Sume f->f_un.f_forw.f_addr = res; 19761553Srgrimes f->f_type = F_FORW; 19771553Srgrimes break; 19781553Srgrimes 19791553Srgrimes case '/': 1980156339Spjd if ((f->f_file = open(p, logflags, 0600)) < 0) { 198120290Speter f->f_type = F_UNUSED; 19821553Srgrimes logerror(p); 19831553Srgrimes break; 19841553Srgrimes } 1985129865Sdwmalone if (syncfile) 1986129865Sdwmalone f->f_flags |= FFLAG_SYNC; 198719962Speter if (isatty(f->f_file)) { 198819962Speter if (strcmp(p, ctty) == 0) 198919962Speter f->f_type = F_CONSOLE; 199019962Speter else 199119962Speter f->f_type = F_TTY; 199283054Skris (void)strlcpy(f->f_un.f_fname, p + sizeof(_PATH_DEV) - 1, 199382724Skris sizeof(f->f_un.f_fname)); 199419962Speter } else { 199582724Skris (void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname)); 19961553Srgrimes f->f_type = F_FILE; 199719962Speter } 19981553Srgrimes break; 19991553Srgrimes 200022984Sjoerg case '|': 200122984Sjoerg f->f_un.f_pipe.f_pid = 0; 2002176427Sdwmalone (void)strlcpy(f->f_un.f_pipe.f_pname, p + 1, 2003176427Sdwmalone sizeof(f->f_un.f_pipe.f_pname)); 200422984Sjoerg f->f_type = F_PIPE; 200522984Sjoerg break; 200622984Sjoerg 20071553Srgrimes case '*': 20081553Srgrimes f->f_type = F_WALL; 20091553Srgrimes break; 20101553Srgrimes 20111553Srgrimes default: 20121553Srgrimes for (i = 0; i < MAXUNAMES && *p; i++) { 20131553Srgrimes for (q = p; *q && *q != ','; ) 20141553Srgrimes q++; 2015200954Sed (void)strncpy(f->f_un.f_uname[i], p, MAXLOGNAME - 1); 2016200954Sed if ((q - p) >= MAXLOGNAME) 2017200954Sed f->f_un.f_uname[i][MAXLOGNAME - 1] = '\0'; 20181553Srgrimes else 20191553Srgrimes f->f_un.f_uname[i][q - p] = '\0'; 20201553Srgrimes while (*q == ',' || *q == ' ') 20211553Srgrimes q++; 20221553Srgrimes p = q; 20231553Srgrimes } 20241553Srgrimes f->f_type = F_USERS; 20251553Srgrimes break; 20261553Srgrimes } 20271553Srgrimes} 20281553Srgrimes 20291553Srgrimes 20301553Srgrimes/* 20311553Srgrimes * Decode a symbolic name to a numeric value 20321553Srgrimes */ 203393078Sdesstatic int 203493078Sdesdecode(const char *name, CODE *codetab) 20351553Srgrimes{ 20361553Srgrimes CODE *c; 20371553Srgrimes char *p, buf[40]; 20381553Srgrimes 20391553Srgrimes if (isdigit(*name)) 20401553Srgrimes return (atoi(name)); 20411553Srgrimes 20421553Srgrimes for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) { 20431553Srgrimes if (isupper(*name)) 20441553Srgrimes *p = tolower(*name); 20451553Srgrimes else 20461553Srgrimes *p = *name; 20471553Srgrimes } 20481553Srgrimes *p = '\0'; 20491553Srgrimes for (c = codetab; c->c_name; c++) 20501553Srgrimes if (!strcmp(buf, c->c_name)) 20511553Srgrimes return (c->c_val); 20521553Srgrimes 20531553Srgrimes return (-1); 20541553Srgrimes} 205518710Speter 205693078Sdesstatic void 205782724Skrismarkit(void) 205882724Skris{ 205982724Skris struct filed *f; 2060104573Sdes dq_t q, next; 206182724Skris 206282724Skris now = time((time_t *)NULL); 206382724Skris MarkSeq += TIMERINTVL; 206482724Skris if (MarkSeq >= MarkInterval) { 206582724Skris logmsg(LOG_INFO, "-- MARK --", 206682724Skris LocalHostName, ADDDATE|MARK); 206782724Skris MarkSeq = 0; 206882724Skris } 206982724Skris 207082724Skris for (f = Files; f; f = f->f_next) { 207182724Skris if (f->f_prevcount && now >= REPEATTIME(f)) { 207282724Skris dprintf("flush %s: repeated %d times, %d sec.\n", 207382724Skris TypeNames[f->f_type], f->f_prevcount, 207482724Skris repeatinterval[f->f_repeatcount]); 207582724Skris fprintlog(f, 0, (char *)NULL); 207682724Skris BACKOFF(f); 207782724Skris } 207882724Skris } 207982724Skris 208082724Skris /* Walk the dead queue, and see if we should signal somebody. */ 2081104573Sdes for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = next) { 2082104573Sdes next = TAILQ_NEXT(q, dq_entries); 2083104573Sdes 208482724Skris switch (q->dq_timeout) { 208582724Skris case 0: 208682724Skris /* Already signalled once, try harder now. */ 208782724Skris if (kill(q->dq_pid, SIGKILL) != 0) 208882724Skris (void)deadq_remove(q->dq_pid); 208982724Skris break; 209082724Skris 209182724Skris case 1: 209282724Skris /* 209382724Skris * Timed out on dead queue, send terminate 209482724Skris * signal. Note that we leave the removal 209582724Skris * from the dead queue to reapchild(), which 209682724Skris * will also log the event (unless the process 209782724Skris * didn't even really exist, in case we simply 209882724Skris * drop it from the dead queue). 209982724Skris */ 210082724Skris if (kill(q->dq_pid, SIGTERM) != 0) 210182724Skris (void)deadq_remove(q->dq_pid); 210282724Skris /* FALLTHROUGH */ 210382724Skris 210482724Skris default: 210582724Skris q->dq_timeout--; 210682724Skris } 210793080Sdes } 210882724Skris MarkSet = 0; 210982724Skris (void)alarm(TIMERINTVL); 211082724Skris} 211182724Skris 211219854Speter/* 211319854Speter * fork off and become a daemon, but wait for the child to come online 211419854Speter * before returing to the parent, or we get disk thrashing at boot etc. 211519854Speter * Set a timer so we don't hang forever if it wedges. 211619854Speter */ 211793078Sdesstatic int 211893078Sdeswaitdaemon(int nochdir, int noclose, int maxwait) 211918710Speter{ 212018710Speter int fd; 212119854Speter int status; 212219854Speter pid_t pid, childpid; 212318710Speter 212419854Speter switch (childpid = fork()) { 212518710Speter case -1: 212618710Speter return (-1); 212718710Speter case 0: 212818710Speter break; 212918710Speter default: 213019854Speter signal(SIGALRM, timedout); 213118710Speter alarm(maxwait); 213219854Speter while ((pid = wait3(&status, 0, NULL)) != -1) { 213319854Speter if (WIFEXITED(status)) 213419854Speter errx(1, "child pid %d exited with return code %d", 213519854Speter pid, WEXITSTATUS(status)); 213619854Speter if (WIFSIGNALED(status)) 213719854Speter errx(1, "child pid %d exited on signal %d%s", 213819854Speter pid, WTERMSIG(status), 213919854Speter WCOREDUMP(status) ? " (core dumped)" : 214019854Speter ""); 214119854Speter if (pid == childpid) /* it's gone... */ 214219854Speter break; 214319854Speter } 214419854Speter exit(0); 214518710Speter } 214618710Speter 214718710Speter if (setsid() == -1) 214818710Speter return (-1); 214918710Speter 215018710Speter if (!nochdir) 215118710Speter (void)chdir("/"); 215218710Speter 215318710Speter if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 215418710Speter (void)dup2(fd, STDIN_FILENO); 215518710Speter (void)dup2(fd, STDOUT_FILENO); 215618710Speter (void)dup2(fd, STDERR_FILENO); 215718710Speter if (fd > 2) 215818710Speter (void)close (fd); 215918710Speter } 216018710Speter return (getppid()); 216118710Speter} 216219854Speter 216319854Speter/* 216419854Speter * We get a SIGALRM from the child when it's running and finished doing it's 216519854Speter * fsync()'s or O_SYNC writes for all the boot messages. 216619854Speter * 216719854Speter * We also get a signal from the kernel if the timer expires, so check to 216819854Speter * see what happened. 216919854Speter */ 217093078Sdesstatic void 217193078Sdestimedout(int sig __unused) 217219854Speter{ 217319854Speter int left; 217419854Speter left = alarm(0); 217519854Speter signal(SIGALRM, SIG_DFL); 217619854Speter if (left == 0) 217719854Speter errx(1, "timed out waiting for child"); 217819854Speter else 217982724Skris _exit(0); 218019854Speter} 218122984Sjoerg 218222984Sjoerg/* 218325437Sjoerg * Add `s' to the list of allowable peer addresses to accept messages 218425437Sjoerg * from. 218525437Sjoerg * 218625437Sjoerg * `s' is a string in the form: 218725437Sjoerg * 218825437Sjoerg * [*]domainname[:{servicename|portnumber|*}] 218925437Sjoerg * 219025437Sjoerg * or 219125437Sjoerg * 219225437Sjoerg * netaddr/maskbits[:{servicename|portnumber|*}] 219325437Sjoerg * 219425437Sjoerg * Returns -1 on error, 0 if the argument was valid. 219525437Sjoerg */ 219693078Sdesstatic int 219793078Sdesallowaddr(char *s) 219825437Sjoerg{ 219925437Sjoerg char *cp1, *cp2; 220025437Sjoerg struct allowedpeer ap; 220125437Sjoerg struct servent *se; 2202186263Savatar int masklen = -1; 220370099Sume struct addrinfo hints, *res; 220470099Sume struct in_addr *addrp, *maskp; 2205186263Savatar#ifdef INET6 2206186263Savatar int i; 220780011Sume u_int32_t *addr6p, *mask6p; 2208186263Savatar#endif 220970099Sume char ip[NI_MAXHOST]; 221025437Sjoerg 221170099Sume#ifdef INET6 221270099Sume if (*s != '[' || (cp1 = strchr(s + 1, ']')) == NULL) 221370099Sume#endif 221470099Sume cp1 = s; 221570099Sume if ((cp1 = strrchr(cp1, ':'))) { 221625437Sjoerg /* service/port provided */ 221725437Sjoerg *cp1++ = '\0'; 221825437Sjoerg if (strlen(cp1) == 1 && *cp1 == '*') 221925437Sjoerg /* any port allowed */ 222070099Sume ap.port = 0; 222193080Sdes else if ((se = getservbyname(cp1, "udp"))) { 222270099Sume ap.port = ntohs(se->s_port); 222393080Sdes } else { 222470099Sume ap.port = strtol(cp1, &cp2, 0); 222525437Sjoerg if (*cp2 != '\0') 222693079Sdes return (-1); /* port not numeric */ 222725437Sjoerg } 222825437Sjoerg } else { 222925437Sjoerg if ((se = getservbyname("syslog", "udp"))) 223070099Sume ap.port = ntohs(se->s_port); 223125437Sjoerg else 223225437Sjoerg /* sanity, should not happen */ 223370099Sume ap.port = 514; 223425437Sjoerg } 223525437Sjoerg 223670099Sume if ((cp1 = strchr(s, '/')) != NULL && 223770099Sume strspn(cp1 + 1, "0123456789") == strlen(cp1 + 1)) { 223870099Sume *cp1 = '\0'; 223970099Sume if ((masklen = atoi(cp1 + 1)) < 0) 224093079Sdes return (-1); 224170099Sume } 224270099Sume#ifdef INET6 224370099Sume if (*s == '[') { 224470099Sume cp2 = s + strlen(s) - 1; 224570099Sume if (*cp2 == ']') { 224670099Sume ++s; 224770099Sume *cp2 = '\0'; 224893080Sdes } else { 224970099Sume cp2 = NULL; 225093080Sdes } 225193080Sdes } else { 225270099Sume cp2 = NULL; 225393080Sdes } 225470099Sume#endif 225570099Sume memset(&hints, 0, sizeof(hints)); 225670099Sume hints.ai_family = PF_UNSPEC; 225770099Sume hints.ai_socktype = SOCK_DGRAM; 225870099Sume hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 225970099Sume if (getaddrinfo(s, NULL, &hints, &res) == 0) { 226025437Sjoerg ap.isnumeric = 1; 226170099Sume memcpy(&ap.a_addr, res->ai_addr, res->ai_addrlen); 226270099Sume memset(&ap.a_mask, 0, sizeof(ap.a_mask)); 226370099Sume ap.a_mask.ss_family = res->ai_family; 226470099Sume if (res->ai_family == AF_INET) { 226570099Sume ap.a_mask.ss_len = sizeof(struct sockaddr_in); 226670099Sume maskp = &((struct sockaddr_in *)&ap.a_mask)->sin_addr; 226779089Scjc addrp = &((struct sockaddr_in *)&ap.a_addr)->sin_addr; 226870099Sume if (masklen < 0) { 226970099Sume /* use default netmask */ 227070099Sume if (IN_CLASSA(ntohl(addrp->s_addr))) 227170099Sume maskp->s_addr = htonl(IN_CLASSA_NET); 227270099Sume else if (IN_CLASSB(ntohl(addrp->s_addr))) 227370099Sume maskp->s_addr = htonl(IN_CLASSB_NET); 227470099Sume else 227570099Sume maskp->s_addr = htonl(IN_CLASSC_NET); 227670099Sume } else if (masklen <= 32) { 227770099Sume /* convert masklen to netmask */ 227886343Sps if (masklen == 0) 227986343Sps maskp->s_addr = 0; 228086343Sps else 228186343Sps maskp->s_addr = htonl(~((1 << (32 - masklen)) - 1)); 228270099Sume } else { 228370099Sume freeaddrinfo(res); 228493079Sdes return (-1); 228570099Sume } 228679089Scjc /* Lose any host bits in the network number. */ 228779089Scjc addrp->s_addr &= maskp->s_addr; 228870099Sume } 228970099Sume#ifdef INET6 229070099Sume else if (res->ai_family == AF_INET6 && masklen <= 128) { 229170099Sume ap.a_mask.ss_len = sizeof(struct sockaddr_in6); 229270099Sume if (masklen < 0) 229370099Sume masklen = 128; 229470099Sume mask6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_mask)->sin6_addr; 229525437Sjoerg /* convert masklen to netmask */ 229670099Sume while (masklen > 0) { 229770099Sume if (masklen < 32) { 229870099Sume *mask6p = htonl(~(0xffffffff >> masklen)); 229970099Sume break; 230070099Sume } 230170099Sume *mask6p++ = 0xffffffff; 230270099Sume masklen -= 32; 230370099Sume } 230480011Sume /* Lose any host bits in the network number. */ 230580011Sume mask6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_mask)->sin6_addr; 230680011Sume addr6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_addr)->sin6_addr; 230780011Sume for (i = 0; i < 4; i++) 230880011Sume addr6p[i] &= mask6p[i]; 230925437Sjoerg } 231070099Sume#endif 231170099Sume else { 231270099Sume freeaddrinfo(res); 231393079Sdes return (-1); 231425437Sjoerg } 231570099Sume freeaddrinfo(res); 231625437Sjoerg } else { 231725437Sjoerg /* arg `s' is domain name */ 231825437Sjoerg ap.isnumeric = 0; 231925437Sjoerg ap.a_name = s; 232070099Sume if (cp1) 232170099Sume *cp1 = '/'; 232270099Sume#ifdef INET6 232370099Sume if (cp2) { 232470099Sume *cp2 = ']'; 232570099Sume --s; 232670099Sume } 232770099Sume#endif 232825437Sjoerg } 232925437Sjoerg 233025437Sjoerg if (Debug) { 233125437Sjoerg printf("allowaddr: rule %d: ", NumAllowed); 233225437Sjoerg if (ap.isnumeric) { 233325437Sjoerg printf("numeric, "); 233470099Sume getnameinfo((struct sockaddr *)&ap.a_addr, 233570099Sume ((struct sockaddr *)&ap.a_addr)->sa_len, 2336146187Sume ip, sizeof ip, NULL, 0, NI_NUMERICHOST); 233770099Sume printf("addr = %s, ", ip); 233870099Sume getnameinfo((struct sockaddr *)&ap.a_mask, 233970099Sume ((struct sockaddr *)&ap.a_mask)->sa_len, 2340146187Sume ip, sizeof ip, NULL, 0, NI_NUMERICHOST); 234170099Sume printf("mask = %s; ", ip); 234293080Sdes } else { 234325437Sjoerg printf("domainname = %s; ", ap.a_name); 234493080Sdes } 234570099Sume printf("port = %d\n", ap.port); 234625437Sjoerg } 234725437Sjoerg 234825437Sjoerg if ((AllowedPeers = realloc(AllowedPeers, 234925437Sjoerg ++NumAllowed * sizeof(struct allowedpeer))) 235025437Sjoerg == NULL) { 235184168Sdes logerror("realloc"); 235284168Sdes exit(1); 235325437Sjoerg } 235425437Sjoerg memcpy(&AllowedPeers[NumAllowed - 1], &ap, sizeof(struct allowedpeer)); 235593079Sdes return (0); 235625437Sjoerg} 235725437Sjoerg 235825437Sjoerg/* 235925437Sjoerg * Validate that the remote peer has permission to log to us. 236025437Sjoerg */ 236193078Sdesstatic int 236293078Sdesvalidate(struct sockaddr *sa, const char *hname) 236325437Sjoerg{ 2364186263Savatar int i; 236525437Sjoerg size_t l1, l2; 236670099Sume char *cp, name[NI_MAXHOST], ip[NI_MAXHOST], port[NI_MAXSERV]; 236725437Sjoerg struct allowedpeer *ap; 236883243Sdd struct sockaddr_in *sin4, *a4p = NULL, *m4p = NULL; 2369186263Savatar#ifdef INET6 2370186263Savatar int j, reject; 237170099Sume struct sockaddr_in6 *sin6, *a6p = NULL, *m6p = NULL; 2372186263Savatar#endif 237370099Sume struct addrinfo hints, *res; 237470099Sume u_short sport; 237525437Sjoerg 237625437Sjoerg if (NumAllowed == 0) 237725437Sjoerg /* traditional behaviour, allow everything */ 237893079Sdes return (1); 237925437Sjoerg 238082724Skris (void)strlcpy(name, hname, sizeof(name)); 238170099Sume memset(&hints, 0, sizeof(hints)); 238270099Sume hints.ai_family = PF_UNSPEC; 238370099Sume hints.ai_socktype = SOCK_DGRAM; 238470099Sume hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 238570099Sume if (getaddrinfo(name, NULL, &hints, &res) == 0) 238670099Sume freeaddrinfo(res); 238770099Sume else if (strchr(name, '.') == NULL) { 238861384Skris strlcat(name, ".", sizeof name); 238961384Skris strlcat(name, LocalDomain, sizeof name); 239025437Sjoerg } 239170099Sume if (getnameinfo(sa, sa->sa_len, ip, sizeof ip, port, sizeof port, 2392146187Sume NI_NUMERICHOST | NI_NUMERICSERV) != 0) 239393079Sdes return (0); /* for safety, should not occur */ 239470099Sume dprintf("validate: dgram from IP %s, port %s, name %s;\n", 239570099Sume ip, port, name); 239670099Sume sport = atoi(port); 239725437Sjoerg 239825437Sjoerg /* now, walk down the list */ 239925437Sjoerg for (i = 0, ap = AllowedPeers; i < NumAllowed; i++, ap++) { 240070099Sume if (ap->port != 0 && ap->port != sport) { 240125437Sjoerg dprintf("rejected in rule %d due to port mismatch.\n", i); 240225437Sjoerg continue; 240325437Sjoerg } 240425437Sjoerg 240525437Sjoerg if (ap->isnumeric) { 240670099Sume if (ap->a_addr.ss_family != sa->sa_family) { 240770099Sume dprintf("rejected in rule %d due to address family mismatch.\n", i); 240825437Sjoerg continue; 240925437Sjoerg } 241070099Sume if (ap->a_addr.ss_family == AF_INET) { 241183243Sdd sin4 = (struct sockaddr_in *)sa; 241270099Sume a4p = (struct sockaddr_in *)&ap->a_addr; 241370099Sume m4p = (struct sockaddr_in *)&ap->a_mask; 241483243Sdd if ((sin4->sin_addr.s_addr & m4p->sin_addr.s_addr) 241570099Sume != a4p->sin_addr.s_addr) { 241670099Sume dprintf("rejected in rule %d due to IP mismatch.\n", i); 241770099Sume continue; 241870099Sume } 241970099Sume } 242070099Sume#ifdef INET6 242170099Sume else if (ap->a_addr.ss_family == AF_INET6) { 242270099Sume sin6 = (struct sockaddr_in6 *)sa; 242370099Sume a6p = (struct sockaddr_in6 *)&ap->a_addr; 242470099Sume m6p = (struct sockaddr_in6 *)&ap->a_mask; 242570099Sume if (a6p->sin6_scope_id != 0 && 242670099Sume sin6->sin6_scope_id != a6p->sin6_scope_id) { 242770099Sume dprintf("rejected in rule %d due to scope mismatch.\n", i); 242870099Sume continue; 242970099Sume } 243070099Sume reject = 0; 243170099Sume for (j = 0; j < 16; j += 4) { 243280011Sume if ((*(u_int32_t *)&sin6->sin6_addr.s6_addr[j] & *(u_int32_t *)&m6p->sin6_addr.s6_addr[j]) 243380011Sume != *(u_int32_t *)&a6p->sin6_addr.s6_addr[j]) { 243470099Sume ++reject; 243570099Sume break; 243670099Sume } 243770099Sume } 243870099Sume if (reject) { 243970099Sume dprintf("rejected in rule %d due to IP mismatch.\n", i); 244070099Sume continue; 244170099Sume } 244270099Sume } 244370099Sume#endif 244470099Sume else 244570099Sume continue; 244625437Sjoerg } else { 244725437Sjoerg cp = ap->a_name; 244825437Sjoerg l1 = strlen(name); 244925437Sjoerg if (*cp == '*') { 245025437Sjoerg /* allow wildmatch */ 245125437Sjoerg cp++; 245225437Sjoerg l2 = strlen(cp); 245325437Sjoerg if (l2 > l1 || memcmp(cp, &name[l1 - l2], l2) != 0) { 245425437Sjoerg dprintf("rejected in rule %d due to name mismatch.\n", i); 245525437Sjoerg continue; 245625437Sjoerg } 245725437Sjoerg } else { 245825437Sjoerg /* exact match */ 245925437Sjoerg l2 = strlen(cp); 246025437Sjoerg if (l2 != l1 || memcmp(cp, name, l1) != 0) { 246125437Sjoerg dprintf("rejected in rule %d due to name mismatch.\n", i); 246225437Sjoerg continue; 246325437Sjoerg } 246425437Sjoerg } 246525437Sjoerg } 246625437Sjoerg dprintf("accepted in rule %d.\n", i); 246793079Sdes return (1); /* hooray! */ 246825437Sjoerg } 246993079Sdes return (0); 247025437Sjoerg} 247125437Sjoerg 247225437Sjoerg/* 247322984Sjoerg * Fairly similar to popen(3), but returns an open descriptor, as 247422984Sjoerg * opposed to a FILE *. 247522984Sjoerg */ 247693078Sdesstatic int 2477129855Sdwmalonep_open(const char *prog, pid_t *rpid) 247822984Sjoerg{ 2479250232Sjilles int pfd[2], nulldesc; 2480129855Sdwmalone pid_t pid; 248122984Sjoerg sigset_t omask, mask; 248222984Sjoerg char *argv[4]; /* sh -c cmd NULL */ 248322984Sjoerg char errmsg[200]; 248422984Sjoerg 248522984Sjoerg if (pipe(pfd) == -1) 248693079Sdes return (-1); 248722984Sjoerg if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1) 248822984Sjoerg /* we are royally screwed anyway */ 248993079Sdes return (-1); 249022984Sjoerg 249133921Sjraynard sigemptyset(&mask); 249233921Sjraynard sigaddset(&mask, SIGALRM); 249333921Sjraynard sigaddset(&mask, SIGHUP); 249433921Sjraynard sigprocmask(SIG_BLOCK, &mask, &omask); 2495129855Sdwmalone switch ((pid = fork())) { 249622984Sjoerg case -1: 249733921Sjraynard sigprocmask(SIG_SETMASK, &omask, 0); 249822984Sjoerg close(nulldesc); 249993079Sdes return (-1); 250022984Sjoerg 250122984Sjoerg case 0: 250283243Sdd argv[0] = strdup("sh"); 250383243Sdd argv[1] = strdup("-c"); 250483243Sdd argv[2] = strdup(prog); 250522984Sjoerg argv[3] = NULL; 250684168Sdes if (argv[0] == NULL || argv[1] == NULL || argv[2] == NULL) { 250784168Sdes logerror("strdup"); 250884168Sdes exit(1); 250984168Sdes } 251022984Sjoerg 251122984Sjoerg alarm(0); 251222984Sjoerg (void)setsid(); /* Avoid catching SIGHUPs. */ 251322984Sjoerg 251422984Sjoerg /* 251522984Sjoerg * Throw away pending signals, and reset signal 251622984Sjoerg * behaviour to standard values. 251722984Sjoerg */ 251822984Sjoerg signal(SIGALRM, SIG_IGN); 251922984Sjoerg signal(SIGHUP, SIG_IGN); 252033921Sjraynard sigprocmask(SIG_SETMASK, &omask, 0); 252122984Sjoerg signal(SIGPIPE, SIG_DFL); 252222984Sjoerg signal(SIGQUIT, SIG_DFL); 252322984Sjoerg signal(SIGALRM, SIG_DFL); 252422984Sjoerg signal(SIGHUP, SIG_DFL); 252522984Sjoerg 252622984Sjoerg dup2(pfd[0], STDIN_FILENO); 252722984Sjoerg dup2(nulldesc, STDOUT_FILENO); 252822984Sjoerg dup2(nulldesc, STDERR_FILENO); 2529250232Sjilles closefrom(3); 253022984Sjoerg 253193080Sdes (void)execvp(_PATH_BSHELL, argv); 253222984Sjoerg _exit(255); 253322984Sjoerg } 253422984Sjoerg 253533921Sjraynard sigprocmask(SIG_SETMASK, &omask, 0); 253622984Sjoerg close(nulldesc); 253722984Sjoerg close(pfd[0]); 253822984Sjoerg /* 253922984Sjoerg * Avoid blocking on a hung pipe. With O_NONBLOCK, we are 254022984Sjoerg * supposed to get an EWOULDBLOCK on writev(2), which is 254122984Sjoerg * caught by the logic above anyway, which will in turn close 254222984Sjoerg * the pipe, and fork a new logging subprocess if necessary. 254322984Sjoerg * The stale subprocess will be killed some time later unless 254422984Sjoerg * it terminated itself due to closing its input pipe (so we 254522984Sjoerg * get rid of really dead puppies). 254622984Sjoerg */ 254722984Sjoerg if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) { 254822984Sjoerg /* This is bad. */ 254922984Sjoerg (void)snprintf(errmsg, sizeof errmsg, 255022984Sjoerg "Warning: cannot change pipe to PID %d to " 255122984Sjoerg "non-blocking behaviour.", 2552129855Sdwmalone (int)pid); 255322984Sjoerg logerror(errmsg); 255422984Sjoerg } 2555129855Sdwmalone *rpid = pid; 255693079Sdes return (pfd[1]); 255722984Sjoerg} 255822984Sjoerg 255993078Sdesstatic void 256093078Sdesdeadq_enter(pid_t pid, const char *name) 256122984Sjoerg{ 256222984Sjoerg dq_t p; 256357558Sjoerg int status; 256422984Sjoerg 256557558Sjoerg /* 256657558Sjoerg * Be paranoid, if we can't signal the process, don't enter it 256757558Sjoerg * into the dead queue (perhaps it's already dead). If possible, 256857558Sjoerg * we try to fetch and log the child's status. 256957558Sjoerg */ 257057558Sjoerg if (kill(pid, 0) != 0) { 257157558Sjoerg if (waitpid(pid, &status, WNOHANG) > 0) 257257558Sjoerg log_deadchild(pid, status, name); 257357558Sjoerg return; 257457558Sjoerg } 257557558Sjoerg 257622984Sjoerg p = malloc(sizeof(struct deadq_entry)); 257783392Sdes if (p == NULL) { 257884168Sdes logerror("malloc"); 257922984Sjoerg exit(1); 258022984Sjoerg } 258122984Sjoerg 258222984Sjoerg p->dq_pid = pid; 258322984Sjoerg p->dq_timeout = DQ_TIMO_INIT; 258422984Sjoerg TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries); 258522984Sjoerg} 258657558Sjoerg 258793078Sdesstatic int 258893078Sdesdeadq_remove(pid_t pid) 258957558Sjoerg{ 259057558Sjoerg dq_t q; 259157558Sjoerg 259293080Sdes TAILQ_FOREACH(q, &deadq_head, dq_entries) { 259357558Sjoerg if (q->dq_pid == pid) { 259457558Sjoerg TAILQ_REMOVE(&deadq_head, q, dq_entries); 259557558Sjoerg free(q); 259693079Sdes return (1); 259757558Sjoerg } 259893080Sdes } 259957558Sjoerg 260093079Sdes return (0); 260157558Sjoerg} 260257558Sjoerg 260393078Sdesstatic void 260493078Sdeslog_deadchild(pid_t pid, int status, const char *name) 260557558Sjoerg{ 260657558Sjoerg int code; 260757558Sjoerg char buf[256]; 260857558Sjoerg const char *reason; 260957558Sjoerg 261057558Sjoerg errno = 0; /* Keep strerror() stuff out of logerror messages. */ 261157558Sjoerg if (WIFSIGNALED(status)) { 261257558Sjoerg reason = "due to signal"; 261357558Sjoerg code = WTERMSIG(status); 261457558Sjoerg } else { 261557558Sjoerg reason = "with status"; 261657558Sjoerg code = WEXITSTATUS(status); 261757558Sjoerg if (code == 0) 261857558Sjoerg return; 261957558Sjoerg } 262057558Sjoerg (void)snprintf(buf, sizeof buf, 262157558Sjoerg "Logging subprocess %d (%s) exited %s %d.", 262257558Sjoerg pid, name, reason, code); 262357558Sjoerg logerror(buf); 262457558Sjoerg} 262570099Sume 262693078Sdesstatic int * 2627211023Sollisocksetup(int af, char *bindhostname) 262870099Sume{ 262970099Sume struct addrinfo hints, *res, *r; 2630211023Solli const char *bindservice; 2631211023Solli char *cp; 263270099Sume int error, maxs, *s, *socks; 263370099Sume 2634211023Solli /* 2635211023Solli * We have to handle this case for backwards compatibility: 2636211023Solli * If there are two (or more) colons but no '[' and ']', 2637211023Solli * assume this is an inet6 address without a service. 2638211023Solli */ 2639211023Solli bindservice = "syslog"; 2640211023Solli if (bindhostname != NULL) { 2641211023Solli#ifdef INET6 2642211023Solli if (*bindhostname == '[' && 2643211023Solli (cp = strchr(bindhostname + 1, ']')) != NULL) { 2644211023Solli ++bindhostname; 2645211023Solli *cp = '\0'; 2646211023Solli if (cp[1] == ':' && cp[2] != '\0') 2647211023Solli bindservice = cp + 2; 2648211023Solli } else { 2649211023Solli#endif 2650211023Solli cp = strchr(bindhostname, ':'); 2651211023Solli if (cp != NULL && strchr(cp + 1, ':') == NULL) { 2652211023Solli *cp = '\0'; 2653211023Solli if (cp[1] != '\0') 2654211023Solli bindservice = cp + 1; 2655211023Solli if (cp == bindhostname) 2656211023Solli bindhostname = NULL; 2657211023Solli } 2658211023Solli#ifdef INET6 2659211023Solli } 2660211023Solli#endif 2661211023Solli } 2662211023Solli 266370099Sume memset(&hints, 0, sizeof(hints)); 266470099Sume hints.ai_flags = AI_PASSIVE; 266570099Sume hints.ai_family = af; 266670099Sume hints.ai_socktype = SOCK_DGRAM; 2667211023Solli error = getaddrinfo(bindhostname, bindservice, &hints, &res); 266870099Sume if (error) { 266970099Sume logerror(gai_strerror(error)); 267070099Sume errno = 0; 267170099Sume die(0); 267270099Sume } 267370099Sume 267470099Sume /* Count max number of sockets we may open */ 267570099Sume for (maxs = 0, r = res; r; r = r->ai_next, maxs++); 267670099Sume socks = malloc((maxs+1) * sizeof(int)); 267783392Sdes if (socks == NULL) { 267870099Sume logerror("couldn't allocate memory for sockets"); 267970099Sume die(0); 268070099Sume } 268170099Sume 268270099Sume *socks = 0; /* num of sockets counter at start of array */ 268370099Sume s = socks + 1; 268470099Sume for (r = res; r; r = r->ai_next) { 2685150689Scognet int on = 1; 268670099Sume *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); 268770099Sume if (*s < 0) { 268870099Sume logerror("socket"); 268970099Sume continue; 269070099Sume } 2691244881Smarkj#ifdef INET6 269270099Sume if (r->ai_family == AF_INET6) { 2693100505Sume if (setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY, 269470099Sume (char *)&on, sizeof (on)) < 0) { 269570099Sume logerror("setsockopt"); 269670099Sume close(*s); 269770099Sume continue; 269870099Sume } 269970099Sume } 2700244881Smarkj#endif 2701150689Scognet if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, 2702150690Scognet (char *)&on, sizeof (on)) < 0) { 2703150689Scognet logerror("setsockopt"); 2704150689Scognet close(*s); 2705150689Scognet continue; 2706150689Scognet } 2707224002Sdelphij /* 2708224002Sdelphij * RFC 3164 recommends that client side message 2709224002Sdelphij * should come from the privileged syslogd port. 2710224002Sdelphij * 2711224002Sdelphij * If the system administrator choose not to obey 2712224002Sdelphij * this, we can skip the bind() step so that the 2713224002Sdelphij * system will choose a port for us. 2714224002Sdelphij */ 2715224002Sdelphij if (!NoBind) { 2716224002Sdelphij if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) { 2717244881Smarkj logerror("bind"); 2718224002Sdelphij close(*s); 2719224002Sdelphij continue; 2720224002Sdelphij } 2721224002Sdelphij 2722224002Sdelphij if (!SecureMode) 2723224002Sdelphij double_rbuf(*s); 272470099Sume } 272570099Sume 272670099Sume (*socks)++; 272770099Sume s++; 272870099Sume } 272970099Sume 273070099Sume if (*socks == 0) { 273170099Sume free(socks); 273270099Sume if (Debug) 273393079Sdes return (NULL); 273470099Sume else 273570099Sume die(0); 273670099Sume } 273770099Sume if (res) 273870099Sume freeaddrinfo(res); 273970099Sume 274093079Sdes return (socks); 274170099Sume} 2742137568Sglebius 2743137568Sglebiusstatic void 2744137568Sglebiusdouble_rbuf(int fd) 2745137568Sglebius{ 2746137568Sglebius socklen_t slen, len; 2747137568Sglebius 2748137568Sglebius if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &slen) == 0) { 2749137568Sglebius len *= 2; 2750137568Sglebius setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, slen); 2751137568Sglebius } 2752137568Sglebius} 2753