1 1.147 jschauma /* $NetBSD: syslogd.c,v 1.147 2024/11/09 16:31:31 jschauma Exp $ */ 2 1.32 ad 3 1.1 cgd /* 4 1.5 perry * Copyright (c) 1983, 1988, 1993, 1994 5 1.5 perry * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.60 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.11 christos #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.86 lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993, 1994\ 35 1.87 christos The Regents of the University of California. All rights reserved."); 36 1.1 cgd #endif /* not lint */ 37 1.1 cgd 38 1.1 cgd #ifndef lint 39 1.11 christos #if 0 40 1.11 christos static char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94"; 41 1.11 christos #else 42 1.147 jschauma __RCSID("$NetBSD: syslogd.c,v 1.147 2024/11/09 16:31:31 jschauma Exp $"); 43 1.11 christos #endif 44 1.1 cgd #endif /* not lint */ 45 1.1 cgd 46 1.1 cgd /* 47 1.1 cgd * syslogd -- log system messages 48 1.1 cgd * 49 1.1 cgd * This program implements a system log. It takes a series of lines. 50 1.1 cgd * Each line may have a priority, signified as "<n>" as 51 1.1 cgd * the first characters of the line. If this is 52 1.1 cgd * not present, a default priority is used. 53 1.1 cgd * 54 1.1 cgd * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will 55 1.1 cgd * cause it to reread its configuration file. 56 1.1 cgd * 57 1.1 cgd * Defined Constants: 58 1.1 cgd * 59 1.1 cgd * MAXLINE -- the maximimum line length that can be handled. 60 1.1 cgd * DEFUPRI -- the default priority for user messages 61 1.1 cgd * DEFSPRI -- the default priority for kernel messages 62 1.1 cgd * 63 1.1 cgd * Author: Eric Allman 64 1.1 cgd * extensive changes by Ralph Campbell 65 1.1 cgd * more extensive changes by Eric Allman (again) 66 1.70 thorpej * Extension to log by program name as well as facility and priority 67 1.70 thorpej * by Peter da Silva. 68 1.72 wiz * -U and -v by Harlan Stenn. 69 1.70 thorpej * Priority comparison code by Harlan Stenn. 70 1.87 christos * TLS, syslog-protocol, and syslog-sign code by Martin Schuette. 71 1.1 cgd */ 72 1.87 christos #define SYSLOG_NAMES 73 1.117 christos #include <sys/stat.h> 74 1.108 christos #include <poll.h> 75 1.87 christos #include "syslogd.h" 76 1.87 christos #include "extern.h" 77 1.1 cgd 78 1.87 christos #ifndef DISABLE_SIGN 79 1.87 christos #include "sign.h" 80 1.87 christos struct sign_global_t GlobalSign = { 81 1.87 christos .rsid = 0, 82 1.87 christos .sig2_delims = STAILQ_HEAD_INITIALIZER(GlobalSign.sig2_delims) 83 1.87 christos }; 84 1.87 christos #endif /* !DISABLE_SIGN */ 85 1.53 wiz 86 1.87 christos #ifndef DISABLE_TLS 87 1.87 christos #include "tls.h" 88 1.87 christos #endif /* !DISABLE_TLS */ 89 1.1 cgd 90 1.46 itojun #ifdef LIBWRAP 91 1.46 itojun int allow_severity = LOG_AUTH|LOG_INFO; 92 1.46 itojun int deny_severity = LOG_AUTH|LOG_WARNING; 93 1.46 itojun #endif 94 1.46 itojun 95 1.87 christos const char *ConfFile = _PATH_LOGCONF; 96 1.1 cgd char ctty[] = _PATH_CONSOLE; 97 1.1 cgd 98 1.1 cgd /* 99 1.70 thorpej * Queue of about-to-be-dead processes we should watch out for. 100 1.70 thorpej */ 101 1.70 thorpej TAILQ_HEAD(, deadq_entry) deadq_head = TAILQ_HEAD_INITIALIZER(deadq_head); 102 1.70 thorpej 103 1.70 thorpej typedef struct deadq_entry { 104 1.70 thorpej pid_t dq_pid; 105 1.70 thorpej int dq_timeout; 106 1.70 thorpej TAILQ_ENTRY(deadq_entry) dq_entries; 107 1.70 thorpej } *dq_t; 108 1.70 thorpej 109 1.70 thorpej /* 110 1.87 christos * The timeout to apply to processes waiting on the dead queue. Unit 111 1.70 thorpej * of measure is "mark intervals", i.e. 20 minutes by default. 112 1.70 thorpej * Processes on the dead queue will be terminated after that time. 113 1.70 thorpej */ 114 1.87 christos #define DQ_TIMO_INIT 2 115 1.70 thorpej 116 1.125 christos #define RCVBUFLEN 16384 117 1.126 roy int buflen = RCVBUFLEN; 118 1.70 thorpej /* 119 1.1 cgd * Intervals at which we flush out "message repeated" messages, 120 1.87 christos * in seconds after previous message is logged. After each flush, 121 1.1 cgd * we move to the next interval until we reach the largest. 122 1.1 cgd */ 123 1.1 cgd int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ 124 1.87 christos #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) 125 1.87 christos #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) 126 1.96 lukem #define BACKOFF(f) { if ((size_t)(++(f)->f_repeatcount) > MAXREPEAT) \ 127 1.1 cgd (f)->f_repeatcount = MAXREPEAT; \ 128 1.1 cgd } 129 1.1 cgd 130 1.1 cgd /* values for f_type */ 131 1.1 cgd #define F_UNUSED 0 /* unused entry */ 132 1.1 cgd #define F_FILE 1 /* regular file */ 133 1.1 cgd #define F_TTY 2 /* terminal */ 134 1.1 cgd #define F_CONSOLE 3 /* console terminal */ 135 1.1 cgd #define F_FORW 4 /* remote machine */ 136 1.1 cgd #define F_USERS 5 /* list of users */ 137 1.1 cgd #define F_WALL 6 /* everyone logged on */ 138 1.87 christos #define F_PIPE 7 /* pipe to program */ 139 1.117 christos #define F_FIFO 8 /* mkfifo(2) file */ 140 1.117 christos #define F_TLS 9 141 1.1 cgd 142 1.87 christos struct TypeInfo { 143 1.87 christos const char *name; 144 1.87 christos char *queue_length_string; 145 1.87 christos const char *default_length_string; 146 1.87 christos char *queue_size_string; 147 1.87 christos const char *default_size_string; 148 1.87 christos int64_t queue_length; 149 1.87 christos int64_t queue_size; 150 1.87 christos int max_msg_length; 151 1.87 christos } TypeInfo[] = { 152 1.92 minskim /* numeric values are set in init() 153 1.87 christos * -1 in length/size or max_msg_length means infinite */ 154 1.92 minskim {"UNUSED", NULL, "0", NULL, "0", 0, 0, 0}, 155 1.92 minskim {"FILE", NULL, "1024", NULL, "1M", 0, 0, 16384}, 156 1.92 minskim {"TTY", NULL, "0", NULL, "0", 0, 0, 1024}, 157 1.92 minskim {"CONSOLE", NULL, "0", NULL, "0", 0, 0, 1024}, 158 1.92 minskim {"FORW", NULL, "0", NULL, "1M", 0, 0, 16384}, 159 1.92 minskim {"USERS", NULL, "0", NULL, "0", 0, 0, 1024}, 160 1.92 minskim {"WALL", NULL, "0", NULL, "0", 0, 0, 1024}, 161 1.87 christos {"PIPE", NULL, "1024", NULL, "1M", 0, 0, 16384}, 162 1.117 christos {"FIFO", NULL, "1024", NULL, "1M", 0, 0, 16384}, 163 1.87 christos #ifndef DISABLE_TLS 164 1.87 christos {"TLS", NULL, "-1", NULL, "16M", 0, 0, 16384} 165 1.87 christos #endif /* !DISABLE_TLS */ 166 1.1 cgd }; 167 1.1 cgd 168 1.87 christos struct filed *Files = NULL; 169 1.1 cgd struct filed consfile; 170 1.1 cgd 171 1.87 christos time_t now; 172 1.87 christos int Debug = D_NONE; /* debug flag */ 173 1.47 manu int daemonized = 0; /* we are not daemonized yet */ 174 1.87 christos char *LocalFQDN = NULL; /* our FQDN */ 175 1.87 christos char *oldLocalFQDN = NULL; /* our previous FQDN */ 176 1.87 christos char LocalHostName[MAXHOSTNAMELEN]; /* our hostname */ 177 1.87 christos struct socketEvent *finet; /* Internet datagram sockets and events */ 178 1.87 christos int *funix; /* Unix domain datagram sockets */ 179 1.87 christos #ifndef DISABLE_TLS 180 1.87 christos struct socketEvent *TLS_Listen_Set; /* TLS/TCP sockets and events */ 181 1.87 christos #endif /* !DISABLE_TLS */ 182 1.87 christos int Initialized = 0; /* set when we have initialized ourselves */ 183 1.70 thorpej int ShuttingDown; /* set when we die() */ 184 1.87 christos int MarkInterval = 20 * 60; /* interval between marks in seconds */ 185 1.1 cgd int MarkSeq = 0; /* mark sequence number */ 186 1.35 jwise int SecureMode = 0; /* listen only on unix domain socks */ 187 1.45 mrg int UseNameService = 1; /* make domain name queries */ 188 1.36 jwise int NumForwards = 0; /* number of forwarding actions in conf file */ 189 1.22 mrg char **LogPaths; /* array of pathnames to read messages from */ 190 1.63 lukem int NoRepeat = 0; /* disable "repeated"; log always */ 191 1.77 pavel int RemoteAddDate = 0; /* always add date to messages from network */ 192 1.66 mycroft int SyncKernel = 0; /* write kernel messages synchronously */ 193 1.70 thorpej int UniquePriority = 0; /* only log specified priority */ 194 1.70 thorpej int LogFacPri = 0; /* put facility and priority in log messages: */ 195 1.70 thorpej /* 0=no, 1=numeric, 2=names */ 196 1.127 roy int LogOverflow = 1; /* 0=no, any other value = yes */ 197 1.87 christos bool BSDOutputFormat = true; /* if true emit traditional BSD Syslog lines, 198 1.87 christos * otherwise new syslog-protocol lines 199 1.92 minskim * 200 1.87 christos * Open Issue: having a global flag is the 201 1.87 christos * easiest solution. If we get a more detailed 202 1.87 christos * config file this could/should be changed 203 1.87 christos * into a destination-specific flag. 204 1.87 christos * Most output code should be ready to handle 205 1.87 christos * this, it will only break some syslog-sign 206 1.87 christos * configurations (e.g. with SG="0"). 207 1.87 christos */ 208 1.144 gutterid bool KernXlat = true; /* translate kern.* -> user.* */ 209 1.87 christos char appname[] = "syslogd";/* the APPNAME for own messages */ 210 1.134 christos char *include_pid; /* include PID in own messages */ 211 1.135 christos char include_pid_buf[11]; 212 1.87 christos 213 1.87 christos 214 1.87 christos /* init and setup */ 215 1.87 christos void usage(void) __attribute__((__noreturn__)); 216 1.140 uwe void set_debug(const char *); 217 1.87 christos void logpath_add(char ***, int *, int *, const char *); 218 1.87 christos void logpath_fileadd(char ***, int *, int *, const char *); 219 1.87 christos void init(int fd, short event, void *ev); /* SIGHUP kevent dispatch routine */ 220 1.87 christos struct socketEvent* 221 1.87 christos socksetup(int, const char *); 222 1.87 christos int getmsgbufsize(void); 223 1.87 christos char *getLocalFQDN(void); 224 1.87 christos void trim_anydomain(char *); 225 1.87 christos /* pipe & subprocess handling */ 226 1.87 christos int p_open(char *, pid_t *); 227 1.87 christos void deadq_enter(pid_t, const char *); 228 1.87 christos int deadq_remove(pid_t); 229 1.87 christos void log_deadchild(pid_t, int, const char *); 230 1.87 christos void reapchild(int fd, short event, void *ev); /* SIGCHLD kevent dispatch routine */ 231 1.87 christos /* input message parsing & formatting */ 232 1.87 christos const char *cvthname(struct sockaddr_storage *); 233 1.87 christos void printsys(char *); 234 1.87 christos struct buf_msg *printline_syslogprotocol(const char*, char*, int, int); 235 1.87 christos struct buf_msg *printline_bsdsyslog(const char*, char*, int, int); 236 1.87 christos struct buf_msg *printline_kernelprintf(const char*, char*, int, int); 237 1.87 christos size_t check_timestamp(unsigned char *, char **, bool, bool); 238 1.87 christos char *copy_utf8_ascii(char*, size_t); 239 1.87 christos uint_fast32_t get_utf8_value(const char*); 240 1.87 christos unsigned valid_utf8(const char *); 241 1.87 christos static unsigned check_sd(char*); 242 1.87 christos static unsigned check_msgid(char *); 243 1.87 christos /* event handling */ 244 1.87 christos static void dispatch_read_klog(int fd, short event, void *ev); 245 1.87 christos static void dispatch_read_finet(int fd, short event, void *ev); 246 1.87 christos static void dispatch_read_funix(int fd, short event, void *ev); 247 1.87 christos static void domark(int fd, short event, void *ev); /* timer kevent dispatch routine */ 248 1.87 christos /* log messages */ 249 1.87 christos void logmsg_async(int, const char *, const char *, int); 250 1.87 christos void logmsg(struct buf_msg *); 251 1.87 christos int matches_spec(const char *, const char *, 252 1.87 christos char *(*)(const char *, const char *)); 253 1.87 christos void udp_send(struct filed *, char *, size_t); 254 1.87 christos void wallmsg(struct filed *, struct iovec *, size_t); 255 1.87 christos /* buffer & queue functions */ 256 1.87 christos size_t message_queue_purge(struct filed *f, size_t, int); 257 1.87 christos size_t message_allqueues_check(void); 258 1.87 christos static struct buf_queue * 259 1.87 christos find_qentry_to_delete(const struct buf_queue_head *, int, bool); 260 1.87 christos struct buf_queue * 261 1.87 christos message_queue_add(struct filed *, struct buf_msg *); 262 1.87 christos size_t buf_queue_obj_size(struct buf_queue*); 263 1.87 christos /* configuration & parsing */ 264 1.87 christos void cfline(size_t, const char *, struct filed *, const char *, 265 1.87 christos const char *); 266 1.87 christos void read_config_file(FILE*, struct filed**); 267 1.87 christos void store_sign_delim_sg2(char*); 268 1.87 christos int decode(const char *, CODE *); 269 1.87 christos bool copy_config_value(const char *, char **, const char **, 270 1.87 christos const char *, int); 271 1.87 christos bool copy_config_value_word(char **, const char **); 272 1.87 christos 273 1.87 christos /* config parsing */ 274 1.87 christos #ifndef DISABLE_TLS 275 1.87 christos void free_cred_SLIST(struct peer_cred_head *); 276 1.87 christos static inline void 277 1.87 christos free_incoming_tls_sockets(void); 278 1.87 christos #endif /* !DISABLE_TLS */ 279 1.108 christos static int writev1(int, struct iovec *, size_t); 280 1.87 christos 281 1.125 christos static void setsockbuf(int, const char *); 282 1.125 christos 283 1.87 christos /* for make_timestamp() */ 284 1.121 christos char timestamp[MAX_TIMESTAMPLEN + 1]; 285 1.70 thorpej /* 286 1.87 christos * Global line buffer. Since we only process one event at a time, 287 1.104 enami * a global one will do. But for klog, we use own buffer so that 288 1.104 enami * partial line at the end of buffer can be deferred. 289 1.70 thorpej */ 290 1.104 enami char *linebuf, *klog_linebuf; 291 1.104 enami size_t linebufsize, klog_linebufoff; 292 1.87 christos 293 1.79 christos static const char *bindhostname = NULL; 294 1.70 thorpej 295 1.87 christos #ifndef DISABLE_TLS 296 1.87 christos struct TLS_Incoming TLS_Incoming_Head = \ 297 1.87 christos SLIST_HEAD_INITIALIZER(TLS_Incoming_Head); 298 1.87 christos extern char *SSL_ERRCODE[]; 299 1.87 christos struct tls_global_options_t tls_opt; 300 1.87 christos #endif /* !DISABLE_TLS */ 301 1.70 thorpej 302 1.5 perry int 303 1.53 wiz main(int argc, char *argv[]) 304 1.1 cgd { 305 1.87 christos int ch, j, fklog; 306 1.22 mrg int funixsize = 0, funixmaxsize = 0; 307 1.70 thorpej struct sockaddr_un sunx; 308 1.70 thorpej char **pp; 309 1.87 christos struct event *ev; 310 1.47 manu uid_t uid = 0; 311 1.47 manu gid_t gid = 0; 312 1.47 manu char *user = NULL; 313 1.47 manu char *group = NULL; 314 1.87 christos const char *root = "/"; 315 1.47 manu char *endp; 316 1.47 manu struct group *gr; 317 1.47 manu struct passwd *pw; 318 1.57 itojun unsigned long l; 319 1.146 jschauma char pfpath[PATH_MAX]; 320 1.41 tron 321 1.87 christos /* should we set LC_TIME="C" to ensure correct timestamps&parsing? */ 322 1.41 tron (void)setlocale(LC_ALL, ""); 323 1.1 cgd 324 1.144 gutterid while ((ch = getopt(argc, argv, "b:B:d::knsSf:m:o:p:P:ru:g:t:TUvX")) != -1) 325 1.5 perry switch(ch) { 326 1.79 christos case 'b': 327 1.79 christos bindhostname = optarg; 328 1.79 christos break; 329 1.126 roy case 'B': 330 1.126 roy buflen = atoi(optarg); 331 1.126 roy if (buflen < RCVBUFLEN) 332 1.126 roy buflen = RCVBUFLEN; 333 1.126 roy break; 334 1.53 wiz case 'd': /* debug */ 335 1.140 uwe if (optarg != NULL) { 336 1.140 uwe /* 337 1.140 uwe * getopt passes as optarg everything 338 1.140 uwe * after 'd' in -darg, manually accept 339 1.140 uwe * -d=arg too. 340 1.140 uwe */ 341 1.140 uwe if (optarg[0] == '=') 342 1.140 uwe ++optarg; 343 1.140 uwe } else if (optind < argc) { 344 1.140 uwe /* 345 1.140 uwe * :: treats "-d ..." as missing 346 1.140 uwe * optarg, so look ahead manually and 347 1.140 uwe * pick up the next arg if it looks 348 1.140 uwe * like one. 349 1.140 uwe */ 350 1.140 uwe if (argv[optind][0] != '-') { 351 1.140 uwe optarg = argv[optind]; 352 1.140 uwe ++optind; 353 1.140 uwe } 354 1.140 uwe } 355 1.140 uwe set_debug(optarg); 356 1.53 wiz break; 357 1.53 wiz case 'f': /* configuration file */ 358 1.53 wiz ConfFile = optarg; 359 1.47 manu break; 360 1.47 manu case 'g': 361 1.47 manu group = optarg; 362 1.47 manu if (*group == '\0') 363 1.47 manu usage(); 364 1.47 manu break; 365 1.144 gutterid case 'k': /* pass-through (remote) kern.* */ 366 1.144 gutterid KernXlat = false; 367 1.144 gutterid break; 368 1.1 cgd case 'm': /* mark interval */ 369 1.1 cgd MarkInterval = atoi(optarg) * 60; 370 1.1 cgd break; 371 1.45 mrg case 'n': /* turn off DNS queries */ 372 1.45 mrg UseNameService = 0; 373 1.45 mrg break; 374 1.87 christos case 'o': /* message format */ 375 1.106 christos #define EQ(a) (strncmp(optarg, # a, sizeof(# a) - 1) == 0) 376 1.106 christos if (EQ(bsd) || EQ(rfc3264)) 377 1.87 christos BSDOutputFormat = true; 378 1.106 christos else if (EQ(syslog) || EQ(rfc5424)) 379 1.87 christos BSDOutputFormat = false; 380 1.87 christos else 381 1.87 christos usage(); 382 1.87 christos /* TODO: implement additional output option "osyslog" 383 1.87 christos * for old syslogd behaviour as introduced after 384 1.87 christos * FreeBSD PR#bin/7055. 385 1.87 christos */ 386 1.87 christos break; 387 1.1 cgd case 'p': /* path */ 388 1.92 minskim logpath_add(&LogPaths, &funixsize, 389 1.22 mrg &funixmaxsize, optarg); 390 1.22 mrg break; 391 1.22 mrg case 'P': /* file of paths */ 392 1.92 minskim logpath_fileadd(&LogPaths, &funixsize, 393 1.22 mrg &funixmaxsize, optarg); 394 1.1 cgd break; 395 1.63 lukem case 'r': /* disable "repeated" compression */ 396 1.63 lukem NoRepeat++; 397 1.63 lukem break; 398 1.35 jwise case 's': /* no network listen mode */ 399 1.7 perry SecureMode++; 400 1.7 perry break; 401 1.66 mycroft case 'S': 402 1.66 mycroft SyncKernel = 1; 403 1.66 mycroft break; 404 1.53 wiz case 't': 405 1.53 wiz root = optarg; 406 1.53 wiz if (*root == '\0') 407 1.53 wiz usage(); 408 1.53 wiz break; 409 1.77 pavel case 'T': 410 1.77 pavel RemoteAddDate = 1; 411 1.77 pavel break; 412 1.53 wiz case 'u': 413 1.53 wiz user = optarg; 414 1.53 wiz if (*user == '\0') 415 1.53 wiz usage(); 416 1.53 wiz break; 417 1.70 thorpej case 'U': /* only log specified priority */ 418 1.70 thorpej UniquePriority = 1; 419 1.70 thorpej break; 420 1.70 thorpej case 'v': /* log facility and priority */ 421 1.70 thorpej if (LogFacPri < 2) 422 1.70 thorpej LogFacPri++; 423 1.70 thorpej break; 424 1.127 roy case 'X': 425 1.127 roy LogOverflow = 0; 426 1.127 roy break; 427 1.1 cgd default: 428 1.1 cgd usage(); 429 1.1 cgd } 430 1.5 perry if ((argc -= optind) != 0) 431 1.1 cgd usage(); 432 1.1 cgd 433 1.47 manu setlinebuf(stdout); 434 1.90 blymn tzset(); /* init TZ information for localtime. */ 435 1.47 manu 436 1.47 manu if (user != NULL) { 437 1.47 manu if (isdigit((unsigned char)*user)) { 438 1.57 itojun errno = 0; 439 1.57 itojun endp = NULL; 440 1.57 itojun l = strtoul(user, &endp, 0); 441 1.57 itojun if (errno || *endp != '\0') 442 1.87 christos goto getuser; 443 1.57 itojun uid = (uid_t)l; 444 1.87 christos if (uid != l) {/* TODO: never executed */ 445 1.57 itojun errno = 0; 446 1.57 itojun logerror("UID out of range"); 447 1.87 christos die(0, 0, NULL); 448 1.57 itojun } 449 1.47 manu } else { 450 1.47 manu getuser: 451 1.47 manu if ((pw = getpwnam(user)) != NULL) { 452 1.47 manu uid = pw->pw_uid; 453 1.47 manu } else { 454 1.92 minskim errno = 0; 455 1.47 manu logerror("Cannot find user `%s'", user); 456 1.87 christos die(0, 0, NULL); 457 1.47 manu } 458 1.47 manu } 459 1.47 manu } 460 1.47 manu 461 1.47 manu if (group != NULL) { 462 1.47 manu if (isdigit((unsigned char)*group)) { 463 1.57 itojun errno = 0; 464 1.57 itojun endp = NULL; 465 1.57 itojun l = strtoul(group, &endp, 0); 466 1.57 itojun if (errno || *endp != '\0') 467 1.87 christos goto getgroup; 468 1.57 itojun gid = (gid_t)l; 469 1.87 christos if (gid != l) {/* TODO: never executed */ 470 1.57 itojun errno = 0; 471 1.57 itojun logerror("GID out of range"); 472 1.87 christos die(0, 0, NULL); 473 1.57 itojun } 474 1.47 manu } else { 475 1.47 manu getgroup: 476 1.47 manu if ((gr = getgrnam(group)) != NULL) { 477 1.47 manu gid = gr->gr_gid; 478 1.47 manu } else { 479 1.47 manu errno = 0; 480 1.47 manu logerror("Cannot find group `%s'", group); 481 1.87 christos die(0, 0, NULL); 482 1.47 manu } 483 1.47 manu } 484 1.47 manu } 485 1.47 manu 486 1.70 thorpej if (access(root, F_OK | R_OK)) { 487 1.53 wiz logerror("Cannot access `%s'", root); 488 1.87 christos die(0, 0, NULL); 489 1.47 manu } 490 1.1 cgd 491 1.1 cgd consfile.f_type = F_CONSOLE; 492 1.58 itojun (void)strlcpy(consfile.f_un.f_fname, ctty, 493 1.58 itojun sizeof(consfile.f_un.f_fname)); 494 1.70 thorpej linebufsize = getmsgbufsize(); 495 1.70 thorpej if (linebufsize < MAXLINE) 496 1.70 thorpej linebufsize = MAXLINE; 497 1.70 thorpej linebufsize++; 498 1.92 minskim 499 1.87 christos if (!(linebuf = malloc(linebufsize))) { 500 1.87 christos logerror("Couldn't allocate buffer"); 501 1.87 christos die(0, 0, NULL); 502 1.15 leo } 503 1.104 enami if (!(klog_linebuf = malloc(linebufsize))) { 504 1.104 enami logerror("Couldn't allocate buffer for klog"); 505 1.104 enami die(0, 0, NULL); 506 1.104 enami } 507 1.104 enami 508 1.5 perry 509 1.5 perry #ifndef SUN_LEN 510 1.5 perry #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 511 1.5 perry #endif 512 1.24 tron if (funixsize == 0) 513 1.92 minskim logpath_add(&LogPaths, &funixsize, 514 1.24 tron &funixmaxsize, _PATH_LOG); 515 1.107 christos funix = malloc(sizeof(*funix) * funixsize); 516 1.22 mrg if (funix == NULL) { 517 1.47 manu logerror("Couldn't allocate funix descriptors"); 518 1.87 christos die(0, 0, NULL); 519 1.1 cgd } 520 1.26 tron for (j = 0, pp = LogPaths; *pp; pp++, j++) { 521 1.87 christos DPRINTF(D_NET, "Making unix dgram socket `%s'\n", *pp); 522 1.22 mrg unlink(*pp); 523 1.22 mrg memset(&sunx, 0, sizeof(sunx)); 524 1.22 mrg sunx.sun_family = AF_LOCAL; 525 1.22 mrg (void)strncpy(sunx.sun_path, *pp, sizeof(sunx.sun_path)); 526 1.22 mrg funix[j] = socket(AF_LOCAL, SOCK_DGRAM, 0); 527 1.22 mrg if (funix[j] < 0 || bind(funix[j], 528 1.22 mrg (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 || 529 1.22 mrg chmod(*pp, 0666) < 0) { 530 1.47 manu logerror("Cannot create `%s'", *pp); 531 1.87 christos die(0, 0, NULL); 532 1.22 mrg } 533 1.125 christos setsockbuf(funix[j], *pp); 534 1.87 christos DPRINTF(D_NET, "Listening on unix dgram socket `%s'\n", *pp); 535 1.22 mrg } 536 1.7 perry 537 1.22 mrg if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0) { 538 1.87 christos DPRINTF(D_FILE, "Can't open `%s' (%d)\n", _PATH_KLOG, errno); 539 1.22 mrg } else { 540 1.87 christos DPRINTF(D_FILE, "Listening on kernel log `%s' with fd %d\n", 541 1.87 christos _PATH_KLOG, fklog); 542 1.87 christos } 543 1.87 christos 544 1.87 christos #if (!defined(DISABLE_TLS) && !defined(DISABLE_SIGN)) 545 1.87 christos /* basic OpenSSL init */ 546 1.87 christos SSL_load_error_strings(); 547 1.87 christos (void) SSL_library_init(); 548 1.87 christos OpenSSL_add_all_digests(); 549 1.87 christos /* OpenSSL PRNG needs /dev/urandom, thus initialize before chroot() */ 550 1.107 christos if (!RAND_status()) { 551 1.107 christos errno = 0; 552 1.87 christos logerror("Unable to initialize OpenSSL PRNG"); 553 1.107 christos } else { 554 1.87 christos DPRINTF(D_TLS, "Initializing PRNG\n"); 555 1.1 cgd } 556 1.87 christos #endif /* (!defined(DISABLE_TLS) && !defined(DISABLE_SIGN)) */ 557 1.87 christos #ifndef DISABLE_SIGN 558 1.87 christos /* initialize rsid -- we will use that later to determine 559 1.87 christos * whether sign_global_init() was already called */ 560 1.87 christos GlobalSign.rsid = 0; 561 1.87 christos #endif /* !DISABLE_SIGN */ 562 1.87 christos #if (IETF_NUM_PRIVALUES != (LOG_NFACILITIES<<3)) 563 1.87 christos logerror("Warning: system defines %d priority values, but " 564 1.87 christos "syslog-protocol/syslog-sign specify %d values", 565 1.142 gutterid LOG_NFACILITIES, IETF_NUM_PRIVALUES>>3); 566 1.87 christos #endif 567 1.1 cgd 568 1.146 jschauma #ifdef __NetBSD_Version__ 569 1.146 jschauma if ((uid != 0) || (gid != 0)) { 570 1.146 jschauma /* Create the pidfile here so we can chown it to the target 571 1.146 jschauma * user/group and possibly report any error before daemonizing. 572 1.146 jschauma * We then call pidfile(3) again to write the actual 573 1.146 jschauma * daemon pid below. 574 1.146 jschauma * 575 1.146 jschauma * Note: this will likely leave the truncated pidfile in 576 1.146 jschauma * place upon exit, since the effective user is unlikely 577 1.146 jschauma * to have write permissions to _PATH_VARRUN. */ 578 1.146 jschauma if (pidfile(NULL)) { 579 1.146 jschauma logerror("Failed to create pidfile"); 580 1.146 jschauma die(0, 0, NULL); 581 1.146 jschauma } 582 1.146 jschauma j = sizeof(pfpath); 583 1.147 jschauma if (snprintf(pfpath, j, "%s%s.pid", 584 1.146 jschauma _PATH_VARRUN, getprogname()) >= j) { 585 1.146 jschauma logerror("Pidfile path `%s' too long.", pfpath); 586 1.146 jschauma die(0, 0, NULL); 587 1.146 jschauma } 588 1.146 jschauma if (chown(pfpath, uid, gid) < 0) { 589 1.146 jschauma logerror("Failed to chown pidfile `%s` to `%d:%d`", pfpath, uid, gid); 590 1.146 jschauma die(0, 0, NULL); 591 1.146 jschauma } 592 1.146 jschauma } 593 1.146 jschauma #endif /* __NetBSD_Version__ */ 594 1.146 jschauma 595 1.92 minskim /* 596 1.145 jschauma * All files are open, we can drop privileges and chroot. 597 1.47 manu */ 598 1.92 minskim DPRINTF(D_MISC, "Attempt to chroot to `%s'\n", root); 599 1.107 christos if (chroot(root) == -1) { 600 1.53 wiz logerror("Failed to chroot to `%s'", root); 601 1.87 christos die(0, 0, NULL); 602 1.47 manu } 603 1.92 minskim DPRINTF(D_MISC, "Attempt to set GID/EGID to `%d'\n", gid); 604 1.53 wiz if (setgid(gid) || setegid(gid)) { 605 1.53 wiz logerror("Failed to set gid to `%d'", gid); 606 1.87 christos die(0, 0, NULL); 607 1.47 manu } 608 1.92 minskim DPRINTF(D_MISC, "Attempt to set UID/EUID to `%d'\n", uid); 609 1.53 wiz if (setuid(uid) || seteuid(uid)) { 610 1.53 wiz logerror("Failed to set uid to `%d'", uid); 611 1.87 christos die(0, 0, NULL); 612 1.47 manu } 613 1.92 minskim /* 614 1.92 minskim * We cannot detach from the terminal before we are sure we won't 615 1.47 manu * have a fatal error, because error message would not go to the 616 1.92 minskim * terminal and would not be logged because syslogd dies. 617 1.145 jschauma * All die() calls are behind us, we can call daemon(). 618 1.47 manu */ 619 1.47 manu if (!Debug) { 620 1.47 manu (void)daemon(0, 0); 621 1.47 manu daemonized = 1; 622 1.145 jschauma /* Tuck my process id away, if I'm not in debug mode. */ 623 1.87 christos #ifdef __NetBSD_Version__ 624 1.48 taca pidfile(NULL); 625 1.87 christos #endif /* __NetBSD_Version__ */ 626 1.47 manu } 627 1.47 manu 628 1.134 christos include_pid = include_pid_buf; 629 1.134 christos snprintf(include_pid_buf, sizeof(include_pid_buf), "%d", getpid()); 630 1.87 christos 631 1.70 thorpej /* 632 1.70 thorpej * Create the global kernel event descriptor. 633 1.70 thorpej * 634 1.137 andvar * NOTE: We MUST do this after daemon(), because the kqueue() 635 1.70 thorpej * API dictates that kqueue descriptors are not inherited 636 1.70 thorpej * across forks (lame!). 637 1.70 thorpej */ 638 1.87 christos (void)event_init(); 639 1.92 minskim 640 1.70 thorpej /* 641 1.71 thorpej * We must read the configuration file for the first time 642 1.71 thorpej * after the kqueue descriptor is created, because we install 643 1.71 thorpej * events during this process. 644 1.71 thorpej */ 645 1.87 christos init(0, 0, NULL); 646 1.71 thorpej 647 1.71 thorpej /* 648 1.70 thorpej * Always exit on SIGTERM. Also exit on SIGINT and SIGQUIT 649 1.70 thorpej * if we're debugging. 650 1.70 thorpej */ 651 1.70 thorpej (void)signal(SIGTERM, SIG_IGN); 652 1.70 thorpej (void)signal(SIGINT, SIG_IGN); 653 1.70 thorpej (void)signal(SIGQUIT, SIG_IGN); 654 1.92 minskim 655 1.87 christos ev = allocev(); 656 1.87 christos signal_set(ev, SIGTERM, die, ev); 657 1.87 christos EVENT_ADD(ev); 658 1.92 minskim 659 1.70 thorpej if (Debug) { 660 1.87 christos ev = allocev(); 661 1.87 christos signal_set(ev, SIGINT, die, ev); 662 1.87 christos EVENT_ADD(ev); 663 1.87 christos ev = allocev(); 664 1.87 christos signal_set(ev, SIGQUIT, die, ev); 665 1.87 christos EVENT_ADD(ev); 666 1.87 christos } 667 1.87 christos 668 1.87 christos ev = allocev(); 669 1.87 christos signal_set(ev, SIGCHLD, reapchild, ev); 670 1.87 christos EVENT_ADD(ev); 671 1.87 christos 672 1.87 christos ev = allocev(); 673 1.87 christos schedule_event(&ev, 674 1.87 christos &((struct timeval){TIMERINTVL, 0}), 675 1.87 christos domark, ev); 676 1.92 minskim 677 1.87 christos (void)signal(SIGPIPE, SIG_IGN); /* We'll catch EPIPE instead. */ 678 1.70 thorpej 679 1.70 thorpej /* Re-read configuration on SIGHUP. */ 680 1.70 thorpej (void) signal(SIGHUP, SIG_IGN); 681 1.87 christos ev = allocev(); 682 1.87 christos signal_set(ev, SIGHUP, init, ev); 683 1.87 christos EVENT_ADD(ev); 684 1.87 christos 685 1.87 christos #ifndef DISABLE_TLS 686 1.87 christos ev = allocev(); 687 1.87 christos signal_set(ev, SIGUSR1, dispatch_force_tls_reconnect, ev); 688 1.87 christos EVENT_ADD(ev); 689 1.87 christos #endif /* !DISABLE_TLS */ 690 1.70 thorpej 691 1.70 thorpej if (fklog >= 0) { 692 1.87 christos ev = allocev(); 693 1.87 christos DPRINTF(D_EVENT, 694 1.87 christos "register klog for fd %d with ev@%p\n", fklog, ev); 695 1.87 christos event_set(ev, fklog, EV_READ | EV_PERSIST, 696 1.87 christos dispatch_read_klog, ev); 697 1.87 christos EVENT_ADD(ev); 698 1.70 thorpej } 699 1.70 thorpej for (j = 0, pp = LogPaths; *pp; pp++, j++) { 700 1.87 christos ev = allocev(); 701 1.87 christos event_set(ev, funix[j], EV_READ | EV_PERSIST, 702 1.87 christos dispatch_read_funix, ev); 703 1.87 christos EVENT_ADD(ev); 704 1.70 thorpej } 705 1.70 thorpej 706 1.87 christos DPRINTF(D_MISC, "Off & running....\n"); 707 1.92 minskim 708 1.87 christos j = event_dispatch(); 709 1.87 christos /* normal termination via die(), reaching this is an error */ 710 1.87 christos DPRINTF(D_MISC, "event_dispatch() returned %d\n", j); 711 1.87 christos die(0, 0, NULL); 712 1.87 christos /*NOTREACHED*/ 713 1.87 christos return 0; 714 1.1 cgd } 715 1.1 cgd 716 1.5 perry void 717 1.53 wiz usage(void) 718 1.1 cgd { 719 1.5 perry 720 1.5 perry (void)fprintf(stderr, 721 1.144 gutterid "usage: %s [-dknrSsTUvX] [-B buffer_length] [-b bind_address]\n" 722 1.126 roy "\t[-f config_file] [-g group]\n" 723 1.80 wiz "\t[-m mark_interval] [-P file_list] [-p log_socket\n" 724 1.80 wiz "\t[-p log_socket2 ...]] [-t chroot_dir] [-u user]\n", 725 1.80 wiz getprogname()); 726 1.1 cgd exit(1); 727 1.1 cgd } 728 1.1 cgd 729 1.125 christos static void 730 1.125 christos setsockbuf(int fd, const char *name) 731 1.125 christos { 732 1.126 roy int curbuflen; 733 1.125 christos socklen_t socklen = sizeof(buflen); 734 1.126 roy 735 1.126 roy if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &curbuflen, &socklen) == -1) { 736 1.125 christos logerror("getsockopt: SO_RCVBUF: `%s'", name); 737 1.125 christos return; 738 1.125 christos } 739 1.126 roy if (curbuflen >= buflen) 740 1.125 christos return; 741 1.125 christos if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buflen, socklen) == -1) { 742 1.125 christos logerror("setsockopt: SO_RCVBUF: `%s'", name); 743 1.125 christos return; 744 1.125 christos } 745 1.125 christos } 746 1.125 christos 747 1.1 cgd /* 748 1.70 thorpej * Dispatch routine for reading /dev/klog 749 1.92 minskim * 750 1.87 christos * Note: slightly different semantic in dispatch_read functions: 751 1.87 christos * - read_klog() might give multiple messages in linebuf and 752 1.87 christos * leaves the task of splitting them to printsys() 753 1.87 christos * - all other read functions receive one message and 754 1.87 christos * then call printline() with one buffer. 755 1.70 thorpej */ 756 1.70 thorpej static void 757 1.87 christos dispatch_read_klog(int fd, short event, void *ev) 758 1.70 thorpej { 759 1.70 thorpej ssize_t rv; 760 1.104 enami size_t resid = linebufsize - klog_linebufoff; 761 1.70 thorpej 762 1.87 christos DPRINTF((D_CALL|D_EVENT), "Kernel log active (%d, %d, %p)" 763 1.87 christos " with linebuf@%p, length %zu)\n", fd, event, ev, 764 1.104 enami klog_linebuf, linebufsize); 765 1.70 thorpej 766 1.104 enami rv = read(fd, &klog_linebuf[klog_linebufoff], resid - 1); 767 1.70 thorpej if (rv > 0) { 768 1.104 enami klog_linebuf[klog_linebufoff + rv] = '\0'; 769 1.104 enami printsys(klog_linebuf); 770 1.127 roy } else if (rv < 0 && 771 1.127 roy errno != EINTR && 772 1.127 roy (errno != ENOBUFS || LogOverflow)) 773 1.127 roy { 774 1.70 thorpej /* 775 1.70 thorpej * /dev/klog has croaked. Disable the event 776 1.70 thorpej * so it won't bother us again. 777 1.70 thorpej */ 778 1.70 thorpej logerror("klog failed"); 779 1.87 christos event_del(ev); 780 1.70 thorpej } 781 1.70 thorpej } 782 1.70 thorpej 783 1.70 thorpej /* 784 1.70 thorpej * Dispatch routine for reading Unix domain sockets. 785 1.70 thorpej */ 786 1.70 thorpej static void 787 1.87 christos dispatch_read_funix(int fd, short event, void *ev) 788 1.70 thorpej { 789 1.70 thorpej struct sockaddr_un myname, fromunix; 790 1.70 thorpej ssize_t rv; 791 1.70 thorpej socklen_t sunlen; 792 1.70 thorpej 793 1.70 thorpej sunlen = sizeof(myname); 794 1.70 thorpej if (getsockname(fd, (struct sockaddr *)&myname, &sunlen) != 0) { 795 1.70 thorpej /* 796 1.70 thorpej * This should never happen, so ensure that it doesn't 797 1.70 thorpej * happen again. 798 1.70 thorpej */ 799 1.70 thorpej logerror("getsockname() unix failed"); 800 1.87 christos event_del(ev); 801 1.70 thorpej return; 802 1.70 thorpej } 803 1.70 thorpej 804 1.122 dholland #define SUN_PATHLEN(su) \ 805 1.122 dholland ((su)->sun_len - (sizeof(*(su)) - sizeof((su)->sun_path))) 806 1.122 dholland 807 1.87 christos DPRINTF((D_CALL|D_EVENT|D_NET), "Unix socket (%.*s) active (%d, %d %p)" 808 1.122 dholland " with linebuf@%p, size %zu)\n", (int)SUN_PATHLEN(&myname), 809 1.87 christos myname.sun_path, fd, event, ev, linebuf, linebufsize-1); 810 1.70 thorpej 811 1.70 thorpej sunlen = sizeof(fromunix); 812 1.87 christos rv = recvfrom(fd, linebuf, linebufsize-1, 0, 813 1.70 thorpej (struct sockaddr *)&fromunix, &sunlen); 814 1.70 thorpej if (rv > 0) { 815 1.70 thorpej linebuf[rv] = '\0'; 816 1.87 christos printline(LocalFQDN, linebuf, 0); 817 1.127 roy } else if (rv < 0 && 818 1.127 roy errno != EINTR && 819 1.127 roy (errno != ENOBUFS || LogOverflow)) 820 1.127 roy { 821 1.87 christos logerror("recvfrom() unix `%.*s'", 822 1.122 dholland (int)SUN_PATHLEN(&myname), myname.sun_path); 823 1.70 thorpej } 824 1.70 thorpej } 825 1.70 thorpej 826 1.70 thorpej /* 827 1.70 thorpej * Dispatch routine for reading Internet sockets. 828 1.70 thorpej */ 829 1.70 thorpej static void 830 1.87 christos dispatch_read_finet(int fd, short event, void *ev) 831 1.70 thorpej { 832 1.70 thorpej #ifdef LIBWRAP 833 1.70 thorpej struct request_info req; 834 1.70 thorpej #endif 835 1.70 thorpej struct sockaddr_storage frominet; 836 1.70 thorpej ssize_t rv; 837 1.70 thorpej socklen_t len; 838 1.70 thorpej int reject = 0; 839 1.70 thorpej 840 1.87 christos DPRINTF((D_CALL|D_EVENT|D_NET), "inet socket active (%d, %d %p) " 841 1.87 christos " with linebuf@%p, size %zu)\n", 842 1.87 christos fd, event, ev, linebuf, linebufsize-1); 843 1.70 thorpej 844 1.70 thorpej #ifdef LIBWRAP 845 1.87 christos request_init(&req, RQ_DAEMON, appname, RQ_FILE, fd, NULL); 846 1.70 thorpej fromhost(&req); 847 1.70 thorpej reject = !hosts_access(&req); 848 1.70 thorpej if (reject) 849 1.87 christos DPRINTF(D_NET, "access denied\n"); 850 1.70 thorpej #endif 851 1.70 thorpej 852 1.70 thorpej len = sizeof(frominet); 853 1.87 christos rv = recvfrom(fd, linebuf, linebufsize-1, 0, 854 1.70 thorpej (struct sockaddr *)&frominet, &len); 855 1.127 roy if (rv == 0 || 856 1.127 roy (rv < 0 && (errno == EINTR || 857 1.127 roy (errno == ENOBUFS && LogOverflow == 0)))) 858 1.70 thorpej return; 859 1.70 thorpej else if (rv < 0) { 860 1.70 thorpej logerror("recvfrom inet"); 861 1.70 thorpej return; 862 1.70 thorpej } 863 1.70 thorpej 864 1.70 thorpej linebuf[rv] = '\0'; 865 1.70 thorpej if (!reject) 866 1.77 pavel printline(cvthname(&frominet), linebuf, 867 1.87 christos RemoteAddDate ? ADDDATE : 0); 868 1.70 thorpej } 869 1.70 thorpej 870 1.70 thorpej /* 871 1.78 snj * given a pointer to an array of char *'s, a pointer to its current 872 1.22 mrg * size and current allocated max size, and a new char * to add, add 873 1.22 mrg * it, update everything as necessary, possibly allocating a new array 874 1.22 mrg */ 875 1.22 mrg void 876 1.87 christos logpath_add(char ***lp, int *szp, int *maxszp, const char *new) 877 1.22 mrg { 878 1.62 itojun char **nlp; 879 1.62 itojun int newmaxsz; 880 1.22 mrg 881 1.87 christos DPRINTF(D_FILE, "Adding `%s' to the %p logpath list\n", new, *lp); 882 1.22 mrg if (*szp == *maxszp) { 883 1.22 mrg if (*maxszp == 0) { 884 1.62 itojun newmaxsz = 4; /* start of with enough for now */ 885 1.26 tron *lp = NULL; 886 1.50 lukem } else 887 1.62 itojun newmaxsz = *maxszp * 2; 888 1.62 itojun nlp = realloc(*lp, sizeof(char *) * (newmaxsz + 1)); 889 1.62 itojun if (nlp == NULL) { 890 1.47 manu logerror("Couldn't allocate line buffer"); 891 1.87 christos die(0, 0, NULL); 892 1.22 mrg } 893 1.62 itojun *lp = nlp; 894 1.62 itojun *maxszp = newmaxsz; 895 1.22 mrg } 896 1.50 lukem if (((*lp)[(*szp)++] = strdup(new)) == NULL) { 897 1.50 lukem logerror("Couldn't allocate logpath"); 898 1.87 christos die(0, 0, NULL); 899 1.50 lukem } 900 1.26 tron (*lp)[(*szp)] = NULL; /* always keep it NULL terminated */ 901 1.22 mrg } 902 1.22 mrg 903 1.22 mrg /* do a file of log sockets */ 904 1.22 mrg void 905 1.87 christos logpath_fileadd(char ***lp, int *szp, int *maxszp, const char *file) 906 1.22 mrg { 907 1.22 mrg FILE *fp; 908 1.22 mrg char *line; 909 1.22 mrg size_t len; 910 1.22 mrg 911 1.22 mrg fp = fopen(file, "r"); 912 1.22 mrg if (fp == NULL) { 913 1.47 manu logerror("Could not open socket file list `%s'", file); 914 1.87 christos die(0, 0, NULL); 915 1.22 mrg } 916 1.22 mrg 917 1.87 christos while ((line = fgetln(fp, &len)) != NULL) { 918 1.22 mrg line[len - 1] = 0; 919 1.22 mrg logpath_add(lp, szp, maxszp, line); 920 1.22 mrg } 921 1.22 mrg fclose(fp); 922 1.22 mrg } 923 1.22 mrg 924 1.92 minskim /* 925 1.87 christos * checks UTF-8 codepoint 926 1.87 christos * returns either its length in bytes or 0 if *input is invalid 927 1.87 christos */ 928 1.87 christos unsigned 929 1.87 christos valid_utf8(const char *c) { 930 1.87 christos unsigned rc, nb; 931 1.87 christos 932 1.87 christos /* first byte gives sequence length */ 933 1.87 christos if ((*c & 0x80) == 0x00) return 1; /* 0bbbbbbb -- ASCII */ 934 1.87 christos else if ((*c & 0xc0) == 0x80) return 0; /* 10bbbbbb -- trailing byte */ 935 1.87 christos else if ((*c & 0xe0) == 0xc0) nb = 2; /* 110bbbbb */ 936 1.87 christos else if ((*c & 0xf0) == 0xe0) nb = 3; /* 1110bbbb */ 937 1.87 christos else if ((*c & 0xf8) == 0xf0) nb = 4; /* 11110bbb */ 938 1.92 minskim else return 0; /* UTF-8 allows only up to 4 bytes */ 939 1.87 christos 940 1.87 christos /* catch overlong encodings */ 941 1.87 christos if ((*c & 0xfe) == 0xc0) 942 1.87 christos return 0; /* 1100000b ... */ 943 1.87 christos else if (((*c & 0xff) == 0xe0) && ((*(c+1) & 0xe0) == 0x80)) 944 1.87 christos return 0; /* 11100000 100bbbbb ... */ 945 1.87 christos else if (((*c & 0xff) == 0xf0) && ((*(c+1) & 0xf0) == 0x80)) 946 1.87 christos return 0; /* 11110000 1000bbbb ... ... */ 947 1.87 christos 948 1.87 christos /* and also filter UTF-16 surrogates (=invalid in UTF-8) */ 949 1.87 christos if (((*c & 0xff) == 0xed) && ((*(c+1) & 0xe0) == 0xa0)) 950 1.87 christos return 0; /* 11101101 101bbbbb ... */ 951 1.87 christos 952 1.87 christos rc = nb; 953 1.87 christos /* check trailing bytes */ 954 1.87 christos switch (nb) { 955 1.87 christos default: return 0; 956 1.87 christos case 4: if ((*(c+3) & 0xc0) != 0x80) return 0; /*FALLTHROUGH*/ 957 1.87 christos case 3: if ((*(c+2) & 0xc0) != 0x80) return 0; /*FALLTHROUGH*/ 958 1.87 christos case 2: if ((*(c+1) & 0xc0) != 0x80) return 0; /*FALLTHROUGH*/ 959 1.87 christos } 960 1.87 christos return rc; 961 1.87 christos } 962 1.87 christos #define UTF8CHARMAX 4 963 1.87 christos 964 1.92 minskim /* 965 1.87 christos * read UTF-8 value 966 1.87 christos * returns a the codepoint number 967 1.87 christos */ 968 1.87 christos uint_fast32_t 969 1.87 christos get_utf8_value(const char *c) { 970 1.87 christos uint_fast32_t sum; 971 1.87 christos unsigned nb, i; 972 1.87 christos 973 1.87 christos /* first byte gives sequence length */ 974 1.87 christos if ((*c & 0x80) == 0x00) return *c;/* 0bbbbbbb -- ASCII */ 975 1.87 christos else if ((*c & 0xc0) == 0x80) return 0; /* 10bbbbbb -- trailing byte */ 976 1.87 christos else if ((*c & 0xe0) == 0xc0) { /* 110bbbbb */ 977 1.87 christos nb = 2; 978 1.87 christos sum = (*c & ~0xe0) & 0xff; 979 1.87 christos } else if ((*c & 0xf0) == 0xe0) { /* 1110bbbb */ 980 1.87 christos nb = 3; 981 1.87 christos sum = (*c & ~0xf0) & 0xff; 982 1.87 christos } else if ((*c & 0xf8) == 0xf0) { /* 11110bbb */ 983 1.87 christos nb = 4; 984 1.87 christos sum = (*c & ~0xf8) & 0xff; 985 1.87 christos } else return 0; /* UTF-8 allows only up to 4 bytes */ 986 1.87 christos 987 1.87 christos /* check trailing bytes -- 10bbbbbb */ 988 1.87 christos i = 1; 989 1.87 christos while (i < nb) { 990 1.87 christos sum <<= 6; 991 1.87 christos sum |= ((*(c+i) & ~0xc0) & 0xff); 992 1.87 christos i++; 993 1.87 christos } 994 1.87 christos return sum; 995 1.87 christos } 996 1.87 christos 997 1.87 christos /* note previous versions transscribe 998 1.87 christos * control characters, e.g. \007 --> "^G" 999 1.87 christos * did anyone rely on that? 1000 1.92 minskim * 1001 1.87 christos * this new version works on only one buffer and 1002 1.87 christos * replaces control characters with a space 1003 1.92 minskim */ 1004 1.87 christos #define NEXTFIELD(ptr) if (*(p) == ' ') (p)++; /* SP */ \ 1005 1.87 christos else { \ 1006 1.87 christos DPRINTF(D_DATA, "format error\n"); \ 1007 1.87 christos if (*(p) == '\0') start = (p); \ 1008 1.87 christos goto all_syslog_msg; \ 1009 1.87 christos } 1010 1.87 christos #define FORCE2ASCII(c) ((iscntrl((unsigned char)(c)) && (c) != '\t') \ 1011 1.87 christos ? ((c) == '\n' ? ' ' : '?') \ 1012 1.87 christos : (c) & 0177) 1013 1.87 christos 1014 1.87 christos /* following syslog-protocol */ 1015 1.87 christos #define printusascii(ch) (ch >= 33 && ch <= 126) 1016 1.87 christos #define sdname(ch) (ch != '=' && ch != ' ' \ 1017 1.87 christos && ch != ']' && ch != '"' \ 1018 1.87 christos && printusascii(ch)) 1019 1.87 christos 1020 1.87 christos /* checks whether the first word of string p can be interpreted as 1021 1.87 christos * a syslog-protocol MSGID and if so returns its length. 1022 1.92 minskim * 1023 1.87 christos * otherwise returns 0 1024 1.87 christos */ 1025 1.87 christos static unsigned 1026 1.87 christos check_msgid(char *p) 1027 1.87 christos { 1028 1.87 christos char *q = p; 1029 1.92 minskim 1030 1.87 christos /* consider the NILVALUE to be valid */ 1031 1.87 christos if (*q == '-' && *(q+1) == ' ') 1032 1.87 christos return 1; 1033 1.87 christos 1034 1.87 christos for (;;) { 1035 1.87 christos if (*q == ' ') 1036 1.87 christos return q - p; 1037 1.87 christos else if (*q == '\0' || !printusascii(*q) || q - p >= MSGID_MAX) 1038 1.87 christos return 0; 1039 1.87 christos else 1040 1.87 christos q++; 1041 1.87 christos } 1042 1.87 christos } 1043 1.87 christos 1044 1.92 minskim /* 1045 1.87 christos * returns number of chars found in SD at beginning of string p 1046 1.87 christos * thus returns 0 if no valid SD is found 1047 1.92 minskim * 1048 1.87 christos * if ascii == true then substitute all non-ASCII chars 1049 1.87 christos * otherwise use syslog-protocol rules to allow UTF-8 in values 1050 1.87 christos * note: one pass for filtering and scanning, so a found SD 1051 1.87 christos * is always filtered, but an invalid one could be partially 1052 1.87 christos * filtered up to the format error. 1053 1.87 christos */ 1054 1.87 christos static unsigned 1055 1.87 christos check_sd(char* p) 1056 1.87 christos { 1057 1.87 christos char *q = p; 1058 1.87 christos bool esc = false; 1059 1.87 christos 1060 1.87 christos /* consider the NILVALUE to be valid */ 1061 1.87 christos if (*q == '-' && (*(q+1) == ' ' || *(q+1) == '\0')) 1062 1.87 christos return 1; 1063 1.87 christos 1064 1.87 christos for(;;) { /* SD-ELEMENT */ 1065 1.87 christos if (*q++ != '[') return 0; 1066 1.87 christos /* SD-ID */ 1067 1.87 christos if (!sdname(*q)) return 0; 1068 1.87 christos while (sdname(*q)) { 1069 1.87 christos *q = FORCE2ASCII(*q); 1070 1.87 christos q++; 1071 1.87 christos } 1072 1.87 christos for(;;) { /* SD-PARAM */ 1073 1.87 christos if (*q == ']') { 1074 1.87 christos q++; 1075 1.87 christos if (*q == ' ' || *q == '\0') return q - p; 1076 1.87 christos else if (*q == '[') break; 1077 1.87 christos } else if (*q++ != ' ') return 0; 1078 1.87 christos 1079 1.87 christos /* PARAM-NAME */ 1080 1.87 christos if (!sdname(*q)) return 0; 1081 1.87 christos while (sdname(*q)) { 1082 1.87 christos *q = FORCE2ASCII(*q); 1083 1.87 christos q++; 1084 1.87 christos } 1085 1.87 christos 1086 1.87 christos if (*q++ != '=') return 0; 1087 1.87 christos if (*q++ != '"') return 0; 1088 1.87 christos 1089 1.87 christos for(;;) { /* PARAM-VALUE */ 1090 1.87 christos if (esc) { 1091 1.87 christos esc = false; 1092 1.87 christos if (*q == '\\' || *q == '"' || 1093 1.87 christos *q == ']') { 1094 1.87 christos q++; 1095 1.87 christos continue; 1096 1.87 christos } 1097 1.87 christos /* no else because invalid 1098 1.87 christos * escape sequences are accepted */ 1099 1.87 christos } 1100 1.87 christos else if (*q == '"') break; 1101 1.87 christos else if (*q == '\0' || *q == ']') return 0; 1102 1.87 christos else if (*q == '\\') esc = true; 1103 1.87 christos else { 1104 1.87 christos int i; 1105 1.87 christos i = valid_utf8(q); 1106 1.87 christos if (i == 0) 1107 1.87 christos *q = '?'; 1108 1.87 christos else if (i == 1) 1109 1.87 christos *q = FORCE2ASCII(*q); 1110 1.87 christos else /* multi byte char */ 1111 1.87 christos q += (i-1); 1112 1.87 christos } 1113 1.87 christos q++; 1114 1.87 christos } 1115 1.87 christos q++; 1116 1.87 christos } 1117 1.87 christos } 1118 1.87 christos } 1119 1.87 christos 1120 1.87 christos struct buf_msg * 1121 1.87 christos printline_syslogprotocol(const char *hname, char *msg, 1122 1.87 christos int flags, int pri) 1123 1.87 christos { 1124 1.87 christos struct buf_msg *buffer; 1125 1.87 christos char *p, *start; 1126 1.87 christos unsigned sdlen = 0, i = 0; 1127 1.87 christos bool utf8allowed = false; /* for some fields */ 1128 1.87 christos 1129 1.87 christos DPRINTF((D_CALL|D_BUFFER|D_DATA), "printline_syslogprotocol(" 1130 1.87 christos "\"%s\", \"%s\", %d, %d)\n", hname, msg, flags, pri); 1131 1.92 minskim 1132 1.87 christos buffer = buf_msg_new(0); 1133 1.87 christos p = msg; 1134 1.94 christos p += check_timestamp((unsigned char*) p, 1135 1.87 christos &buffer->timestamp, true, !BSDOutputFormat); 1136 1.87 christos DPRINTF(D_DATA, "Got timestamp \"%s\"\n", buffer->timestamp); 1137 1.87 christos 1138 1.94 christos if (flags & ADDDATE) { 1139 1.94 christos FREEPTR(buffer->timestamp); 1140 1.121 christos buffer->timestamp = make_timestamp(NULL, !BSDOutputFormat, 0); 1141 1.94 christos } 1142 1.94 christos 1143 1.94 christos start = p; 1144 1.87 christos NEXTFIELD(p); 1145 1.87 christos /* extract host */ 1146 1.87 christos for (start = p;; p++) { 1147 1.87 christos if ((*p == ' ' || *p == '\0') 1148 1.87 christos && start == p-1 && *(p-1) == '-') { 1149 1.92 minskim /* NILVALUE */ 1150 1.87 christos break; 1151 1.87 christos } else if ((*p == ' ' || *p == '\0') 1152 1.87 christos && (start != p-1 || *(p-1) != '-')) { 1153 1.87 christos buffer->host = strndup(start, p - start); 1154 1.87 christos break; 1155 1.87 christos } else { 1156 1.87 christos *p = FORCE2ASCII(*p); 1157 1.87 christos } 1158 1.87 christos } 1159 1.87 christos /* p @ SP after host */ 1160 1.87 christos DPRINTF(D_DATA, "Got host \"%s\"\n", buffer->host); 1161 1.87 christos 1162 1.87 christos /* extract app-name */ 1163 1.87 christos NEXTFIELD(p); 1164 1.87 christos for (start = p;; p++) { 1165 1.87 christos if ((*p == ' ' || *p == '\0') 1166 1.87 christos && start == p-1 && *(p-1) == '-') { 1167 1.92 minskim /* NILVALUE */ 1168 1.87 christos break; 1169 1.87 christos } else if ((*p == ' ' || *p == '\0') 1170 1.87 christos && (start != p-1 || *(p-1) != '-')) { 1171 1.87 christos buffer->prog = strndup(start, p - start); 1172 1.87 christos break; 1173 1.87 christos } else { 1174 1.87 christos *p = FORCE2ASCII(*p); 1175 1.87 christos } 1176 1.87 christos } 1177 1.87 christos DPRINTF(D_DATA, "Got prog \"%s\"\n", buffer->prog); 1178 1.87 christos 1179 1.87 christos /* extract procid */ 1180 1.87 christos NEXTFIELD(p); 1181 1.87 christos for (start = p;; p++) { 1182 1.87 christos if ((*p == ' ' || *p == '\0') 1183 1.87 christos && start == p-1 && *(p-1) == '-') { 1184 1.92 minskim /* NILVALUE */ 1185 1.87 christos break; 1186 1.87 christos } else if ((*p == ' ' || *p == '\0') 1187 1.87 christos && (start != p-1 || *(p-1) != '-')) { 1188 1.87 christos buffer->pid = strndup(start, p - start); 1189 1.87 christos start = p; 1190 1.87 christos break; 1191 1.87 christos } else { 1192 1.87 christos *p = FORCE2ASCII(*p); 1193 1.87 christos } 1194 1.87 christos } 1195 1.87 christos DPRINTF(D_DATA, "Got pid \"%s\"\n", buffer->pid); 1196 1.87 christos 1197 1.87 christos /* extract msgid */ 1198 1.87 christos NEXTFIELD(p); 1199 1.87 christos for (start = p;; p++) { 1200 1.87 christos if ((*p == ' ' || *p == '\0') 1201 1.87 christos && start == p-1 && *(p-1) == '-') { 1202 1.92 minskim /* NILVALUE */ 1203 1.87 christos start = p+1; 1204 1.87 christos break; 1205 1.87 christos } else if ((*p == ' ' || *p == '\0') 1206 1.87 christos && (start != p-1 || *(p-1) != '-')) { 1207 1.87 christos buffer->msgid = strndup(start, p - start); 1208 1.87 christos start = p+1; 1209 1.87 christos break; 1210 1.87 christos } else { 1211 1.87 christos *p = FORCE2ASCII(*p); 1212 1.87 christos } 1213 1.87 christos } 1214 1.87 christos DPRINTF(D_DATA, "Got msgid \"%s\"\n", buffer->msgid); 1215 1.87 christos 1216 1.87 christos /* extract SD */ 1217 1.87 christos NEXTFIELD(p); 1218 1.87 christos start = p; 1219 1.87 christos sdlen = check_sd(p); 1220 1.87 christos DPRINTF(D_DATA, "check_sd(\"%s\") returned %d\n", p, sdlen); 1221 1.92 minskim 1222 1.87 christos if (sdlen == 1 && *p == '-') { 1223 1.87 christos /* NILVALUE */ 1224 1.87 christos p++; 1225 1.87 christos } else if (sdlen > 1) { 1226 1.87 christos buffer->sd = strndup(p, sdlen); 1227 1.87 christos p += sdlen; 1228 1.87 christos } else { 1229 1.87 christos DPRINTF(D_DATA, "format error\n"); 1230 1.87 christos } 1231 1.87 christos if (*p == '\0') start = p; 1232 1.87 christos else if (*p == ' ') start = ++p; /* SP */ 1233 1.87 christos DPRINTF(D_DATA, "Got SD \"%s\"\n", buffer->sd); 1234 1.87 christos 1235 1.92 minskim /* and now the message itself 1236 1.87 christos * note: move back to last start to check for BOM 1237 1.87 christos */ 1238 1.87 christos all_syslog_msg: 1239 1.87 christos p = start; 1240 1.87 christos 1241 1.87 christos /* check for UTF-8-BOM */ 1242 1.87 christos if (IS_BOM(p)) { 1243 1.87 christos DPRINTF(D_DATA, "UTF-8 BOM\n"); 1244 1.87 christos utf8allowed = true; 1245 1.87 christos p += 3; 1246 1.87 christos } 1247 1.87 christos 1248 1.87 christos if (*p != '\0' && !utf8allowed) { 1249 1.87 christos size_t msglen; 1250 1.87 christos 1251 1.87 christos msglen = strlen(p); 1252 1.87 christos assert(!buffer->msg); 1253 1.87 christos buffer->msg = copy_utf8_ascii(p, msglen); 1254 1.87 christos buffer->msgorig = buffer->msg; 1255 1.87 christos buffer->msglen = buffer->msgsize = strlen(buffer->msg)+1; 1256 1.87 christos } else if (*p != '\0' && utf8allowed) { 1257 1.87 christos while (*p != '\0') { 1258 1.87 christos i = valid_utf8(p); 1259 1.87 christos if (i == 0) 1260 1.87 christos *p++ = '?'; 1261 1.87 christos else if (i == 1) 1262 1.87 christos *p = FORCE2ASCII(*p); 1263 1.87 christos p += i; 1264 1.87 christos } 1265 1.87 christos assert(p != start); 1266 1.87 christos assert(!buffer->msg); 1267 1.87 christos buffer->msg = strndup(start, p - start); 1268 1.87 christos buffer->msgorig = buffer->msg; 1269 1.87 christos buffer->msglen = buffer->msgsize = 1 + p - start; 1270 1.87 christos } 1271 1.87 christos DPRINTF(D_DATA, "Got msg \"%s\"\n", buffer->msg); 1272 1.87 christos 1273 1.87 christos buffer->recvhost = strdup(hname); 1274 1.87 christos buffer->pri = pri; 1275 1.87 christos buffer->flags = flags; 1276 1.87 christos 1277 1.87 christos return buffer; 1278 1.87 christos } 1279 1.87 christos 1280 1.87 christos /* copies an input into a new ASCII buffer 1281 1.87 christos * ASCII controls are converted to format "^X" 1282 1.87 christos * multi-byte UTF-8 chars are converted to format "<ab><cd>" 1283 1.87 christos */ 1284 1.87 christos #define INIT_BUFSIZE 512 1285 1.87 christos char * 1286 1.87 christos copy_utf8_ascii(char *p, size_t p_len) 1287 1.87 christos { 1288 1.87 christos size_t idst = 0, isrc = 0, dstsize = INIT_BUFSIZE, i; 1289 1.87 christos char *dst, *tmp_dst; 1290 1.92 minskim 1291 1.87 christos MALLOC(dst, dstsize); 1292 1.87 christos while (isrc < p_len) { 1293 1.87 christos if (dstsize < idst + 10) { 1294 1.87 christos /* check for enough space for \0 and a UTF-8 1295 1.87 christos * conversion; longest possible is <U+123456> */ 1296 1.87 christos tmp_dst = realloc(dst, dstsize + INIT_BUFSIZE); 1297 1.87 christos if (!tmp_dst) 1298 1.87 christos break; 1299 1.87 christos dst = tmp_dst; 1300 1.87 christos dstsize += INIT_BUFSIZE; 1301 1.87 christos } 1302 1.92 minskim 1303 1.87 christos i = valid_utf8(&p[isrc]); 1304 1.87 christos if (i == 0) { /* invalid encoding */ 1305 1.87 christos dst[idst++] = '?'; 1306 1.87 christos isrc++; 1307 1.87 christos } else if (i == 1) { /* check printable */ 1308 1.87 christos if (iscntrl((unsigned char)p[isrc]) 1309 1.87 christos && p[isrc] != '\t') { 1310 1.87 christos if (p[isrc] == '\n') { 1311 1.87 christos dst[idst++] = ' '; 1312 1.87 christos isrc++; 1313 1.87 christos } else { 1314 1.87 christos dst[idst++] = '^'; 1315 1.87 christos dst[idst++] = p[isrc++] ^ 0100; 1316 1.87 christos } 1317 1.87 christos } else 1318 1.87 christos dst[idst++] = p[isrc++]; 1319 1.87 christos } else { /* convert UTF-8 to ASCII */ 1320 1.87 christos dst[idst++] = '<'; 1321 1.87 christos idst += snprintf(&dst[idst], dstsize - idst, "U+%x", 1322 1.87 christos get_utf8_value(&p[isrc])); 1323 1.87 christos isrc += i; 1324 1.87 christos dst[idst++] = '>'; 1325 1.87 christos } 1326 1.87 christos } 1327 1.87 christos dst[idst] = '\0'; 1328 1.87 christos 1329 1.87 christos /* shrink buffer to right size */ 1330 1.87 christos tmp_dst = realloc(dst, idst+1); 1331 1.87 christos if (tmp_dst) 1332 1.87 christos return tmp_dst; 1333 1.87 christos else 1334 1.87 christos return dst; 1335 1.87 christos } 1336 1.87 christos 1337 1.87 christos struct buf_msg * 1338 1.87 christos printline_bsdsyslog(const char *hname, char *msg, 1339 1.87 christos int flags, int pri) 1340 1.87 christos { 1341 1.87 christos struct buf_msg *buffer; 1342 1.87 christos char *p, *start; 1343 1.87 christos unsigned msgidlen = 0, sdlen = 0; 1344 1.87 christos 1345 1.87 christos DPRINTF((D_CALL|D_BUFFER|D_DATA), "printline_bsdsyslog(" 1346 1.87 christos "\"%s\", \"%s\", %d, %d)\n", hname, msg, flags, pri); 1347 1.87 christos 1348 1.87 christos buffer = buf_msg_new(0); 1349 1.87 christos p = msg; 1350 1.94 christos p += check_timestamp((unsigned char*) p, 1351 1.87 christos &buffer->timestamp, false, !BSDOutputFormat); 1352 1.87 christos DPRINTF(D_DATA, "Got timestamp \"%s\"\n", buffer->timestamp); 1353 1.87 christos 1354 1.94 christos if (flags & ADDDATE || !buffer->timestamp) { 1355 1.94 christos FREEPTR(buffer->timestamp); 1356 1.121 christos buffer->timestamp = make_timestamp(NULL, !BSDOutputFormat, 0); 1357 1.94 christos } 1358 1.94 christos 1359 1.87 christos if (*p == ' ') p++; /* SP */ 1360 1.87 christos else goto all_bsd_msg; 1361 1.87 christos /* in any error case we skip header parsing and 1362 1.92 minskim * treat all following data as message content */ 1363 1.87 christos 1364 1.87 christos /* extract host */ 1365 1.87 christos for (start = p;; p++) { 1366 1.87 christos if (*p == ' ' || *p == '\0') { 1367 1.87 christos buffer->host = strndup(start, p - start); 1368 1.87 christos break; 1369 1.87 christos } else if (*p == '[' || (*p == ':' 1370 1.87 christos && (*(p+1) == ' ' || *(p+1) == '\0'))) { 1371 1.87 christos /* no host in message */ 1372 1.124 ginsbach buffer->host = strdup(hname); 1373 1.87 christos buffer->prog = strndup(start, p - start); 1374 1.87 christos break; 1375 1.87 christos } else { 1376 1.87 christos *p = FORCE2ASCII(*p); 1377 1.87 christos } 1378 1.87 christos } 1379 1.87 christos DPRINTF(D_DATA, "Got host \"%s\"\n", buffer->host); 1380 1.87 christos /* p @ SP after host, or @ :/[ after prog */ 1381 1.87 christos 1382 1.87 christos /* extract program */ 1383 1.87 christos if (!buffer->prog) { 1384 1.87 christos if (*p == ' ') p++; /* SP */ 1385 1.87 christos else goto all_bsd_msg; 1386 1.92 minskim 1387 1.87 christos for (start = p;; p++) { 1388 1.87 christos if (*p == ' ' || *p == '\0') { /* error */ 1389 1.87 christos goto all_bsd_msg; 1390 1.87 christos } else if (*p == '[' || (*p == ':' 1391 1.87 christos && (*(p+1) == ' ' || *(p+1) == '\0'))) { 1392 1.87 christos buffer->prog = strndup(start, p - start); 1393 1.87 christos break; 1394 1.87 christos } else { 1395 1.87 christos *p = FORCE2ASCII(*p); 1396 1.87 christos } 1397 1.87 christos } 1398 1.87 christos } 1399 1.87 christos DPRINTF(D_DATA, "Got prog \"%s\"\n", buffer->prog); 1400 1.87 christos start = p; 1401 1.87 christos 1402 1.87 christos /* p @ :/[ after prog */ 1403 1.87 christos if (*p == '[') { 1404 1.87 christos p++; 1405 1.87 christos if (*p == ' ') p++; /* SP */ 1406 1.87 christos for (start = p;; p++) { 1407 1.87 christos if (*p == ' ' || *p == '\0') { /* error */ 1408 1.87 christos goto all_bsd_msg; 1409 1.87 christos } else if (*p == ']') { 1410 1.87 christos buffer->pid = strndup(start, p - start); 1411 1.87 christos break; 1412 1.87 christos } else { 1413 1.87 christos *p = FORCE2ASCII(*p); 1414 1.87 christos } 1415 1.87 christos } 1416 1.87 christos } 1417 1.87 christos DPRINTF(D_DATA, "Got pid \"%s\"\n", buffer->pid); 1418 1.87 christos 1419 1.87 christos if (*p == ']') p++; 1420 1.87 christos if (*p == ':') p++; 1421 1.87 christos if (*p == ' ') p++; 1422 1.92 minskim 1423 1.87 christos /* p @ msgid, @ opening [ of SD or @ first byte of message 1424 1.87 christos * accept either case and try to detect MSGID and SD fields 1425 1.87 christos * 1426 1.87 christos * only limitation: we do not accept UTF-8 data in 1427 1.87 christos * BSD Syslog messages -- so all SD values are ASCII-filtered 1428 1.92 minskim * 1429 1.87 christos * I have found one scenario with 'unexpected' behaviour: 1430 1.87 christos * if there is only a SD intended, but a) it is short enough 1431 1.87 christos * to be a MSGID and b) the first word of the message can also 1432 1.87 christos * be parsed as an SD. 1433 1.87 christos * example: 1434 1.87 christos * "<35>Jul 6 12:39:08 tag[123]: [exampleSDID@0] - hello" 1435 1.87 christos * --> parsed as 1436 1.87 christos * MSGID = "[exampleSDID@0]" 1437 1.87 christos * SD = "-" 1438 1.87 christos * MSG = "hello" 1439 1.87 christos */ 1440 1.87 christos start = p; 1441 1.87 christos msgidlen = check_msgid(p); 1442 1.87 christos if (msgidlen) /* check for SD in 2nd field */ 1443 1.87 christos sdlen = check_sd(p+msgidlen+1); 1444 1.92 minskim 1445 1.87 christos if (msgidlen && sdlen) { 1446 1.87 christos /* MSGID in 1st and SD in 2nd field 1447 1.87 christos * now check for NILVALUEs and copy */ 1448 1.87 christos if (msgidlen == 1 && *p == '-') { 1449 1.87 christos p++; /* - */ 1450 1.87 christos p++; /* SP */ 1451 1.87 christos DPRINTF(D_DATA, "Got MSGID \"-\"\n"); 1452 1.87 christos } else { 1453 1.92 minskim /* only has ASCII chars after check_msgid() */ 1454 1.87 christos buffer->msgid = strndup(p, msgidlen); 1455 1.87 christos p += msgidlen; 1456 1.87 christos p++; /* SP */ 1457 1.87 christos DPRINTF(D_DATA, "Got MSGID \"%s\"\n", 1458 1.87 christos buffer->msgid); 1459 1.87 christos } 1460 1.87 christos } else { 1461 1.87 christos /* either no msgid or no SD in 2nd field 1462 1.87 christos * --> check 1st field for SD */ 1463 1.87 christos DPRINTF(D_DATA, "No MSGID\n"); 1464 1.87 christos sdlen = check_sd(p); 1465 1.87 christos } 1466 1.92 minskim 1467 1.87 christos if (sdlen == 0) { 1468 1.87 christos DPRINTF(D_DATA, "No SD\n"); 1469 1.87 christos } else if (sdlen > 1) { 1470 1.87 christos buffer->sd = copy_utf8_ascii(p, sdlen); 1471 1.87 christos DPRINTF(D_DATA, "Got SD \"%s\"\n", buffer->sd); 1472 1.87 christos } else if (sdlen == 1 && *p == '-') { 1473 1.87 christos p++; 1474 1.87 christos DPRINTF(D_DATA, "Got SD \"-\"\n"); 1475 1.87 christos } else { 1476 1.87 christos DPRINTF(D_DATA, "Error\n"); 1477 1.87 christos } 1478 1.87 christos 1479 1.87 christos if (*p == ' ') p++; 1480 1.87 christos start = p; 1481 1.92 minskim /* and now the message itself 1482 1.87 christos * note: do not reset start, because we might come here 1483 1.87 christos * by goto and want to have the incomplete field as part 1484 1.87 christos * of the msg 1485 1.87 christos */ 1486 1.87 christos all_bsd_msg: 1487 1.87 christos if (*p != '\0') { 1488 1.87 christos size_t msglen = strlen(p); 1489 1.87 christos buffer->msg = copy_utf8_ascii(p, msglen); 1490 1.87 christos buffer->msgorig = buffer->msg; 1491 1.87 christos buffer->msglen = buffer->msgsize = strlen(buffer->msg)+1; 1492 1.87 christos } 1493 1.87 christos DPRINTF(D_DATA, "Got msg \"%s\"\n", buffer->msg); 1494 1.87 christos 1495 1.87 christos buffer->recvhost = strdup(hname); 1496 1.87 christos buffer->pri = pri; 1497 1.87 christos buffer->flags = flags | BSDSYSLOG; 1498 1.87 christos 1499 1.87 christos return buffer; 1500 1.87 christos } 1501 1.87 christos 1502 1.87 christos struct buf_msg * 1503 1.87 christos printline_kernelprintf(const char *hname, char *msg, 1504 1.87 christos int flags, int pri) 1505 1.87 christos { 1506 1.87 christos struct buf_msg *buffer; 1507 1.87 christos char *p; 1508 1.87 christos unsigned sdlen = 0; 1509 1.87 christos 1510 1.87 christos DPRINTF((D_CALL|D_BUFFER|D_DATA), "printline_kernelprintf(" 1511 1.87 christos "\"%s\", \"%s\", %d, %d)\n", hname, msg, flags, pri); 1512 1.87 christos 1513 1.87 christos buffer = buf_msg_new(0); 1514 1.121 christos buffer->timestamp = make_timestamp(NULL, !BSDOutputFormat, 0); 1515 1.87 christos buffer->pri = pri; 1516 1.87 christos buffer->flags = flags; 1517 1.87 christos 1518 1.87 christos /* assume there is no MSGID but there might be SD */ 1519 1.87 christos p = msg; 1520 1.87 christos sdlen = check_sd(p); 1521 1.92 minskim 1522 1.87 christos if (sdlen == 0) { 1523 1.87 christos DPRINTF(D_DATA, "No SD\n"); 1524 1.87 christos } else if (sdlen > 1) { 1525 1.87 christos buffer->sd = copy_utf8_ascii(p, sdlen); 1526 1.87 christos DPRINTF(D_DATA, "Got SD \"%s\"\n", buffer->sd); 1527 1.87 christos } else if (sdlen == 1 && *p == '-') { 1528 1.87 christos p++; 1529 1.87 christos DPRINTF(D_DATA, "Got SD \"-\"\n"); 1530 1.87 christos } else { 1531 1.87 christos DPRINTF(D_DATA, "Error\n"); 1532 1.87 christos } 1533 1.87 christos 1534 1.87 christos if (*p == ' ') p++; 1535 1.87 christos if (*p != '\0') { 1536 1.87 christos size_t msglen = strlen(p); 1537 1.87 christos buffer->msg = copy_utf8_ascii(p, msglen); 1538 1.87 christos buffer->msgorig = buffer->msg; 1539 1.87 christos buffer->msglen = buffer->msgsize = strlen(buffer->msg)+1; 1540 1.87 christos } 1541 1.87 christos DPRINTF(D_DATA, "Got msg \"%s\"\n", buffer->msg); 1542 1.87 christos 1543 1.87 christos return buffer; 1544 1.87 christos } 1545 1.87 christos 1546 1.22 mrg /* 1547 1.87 christos * Take a raw input line, read priority and version, call the 1548 1.87 christos * right message parsing function, then call logmsg(). 1549 1.1 cgd */ 1550 1.5 perry void 1551 1.87 christos printline(const char *hname, char *msg, int flags) 1552 1.1 cgd { 1553 1.87 christos struct buf_msg *buffer; 1554 1.87 christos int pri; 1555 1.87 christos char *p, *q; 1556 1.70 thorpej long n; 1557 1.87 christos bool bsdsyslog = true; 1558 1.1 cgd 1559 1.87 christos DPRINTF((D_CALL|D_BUFFER|D_DATA), 1560 1.87 christos "printline(\"%s\", \"%s\", %d)\n", hname, msg, flags); 1561 1.92 minskim 1562 1.1 cgd /* test for special codes */ 1563 1.1 cgd pri = DEFUPRI; 1564 1.1 cgd p = msg; 1565 1.1 cgd if (*p == '<') { 1566 1.70 thorpej errno = 0; 1567 1.70 thorpej n = strtol(p + 1, &q, 10); 1568 1.70 thorpej if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) { 1569 1.70 thorpej p = q + 1; 1570 1.70 thorpej pri = (int)n; 1571 1.94 christos /* check for syslog-protocol version */ 1572 1.94 christos if (*p == '1' && p[1] == ' ') { 1573 1.87 christos p += 2; /* skip version and space */ 1574 1.87 christos bsdsyslog = false; 1575 1.87 christos } else { 1576 1.87 christos bsdsyslog = true; 1577 1.87 christos } 1578 1.70 thorpej } 1579 1.1 cgd } 1580 1.87 christos if (pri & ~(LOG_FACMASK|LOG_PRIMASK)) 1581 1.1 cgd pri = DEFUPRI; 1582 1.1 cgd 1583 1.70 thorpej /* 1584 1.144 gutterid * Don't (usually) allow users to log kernel messages. 1585 1.70 thorpej * NOTE: Since LOG_KERN == 0, this will also match 1586 1.70 thorpej * messages with no facility specified. 1587 1.70 thorpej */ 1588 1.144 gutterid if ((pri & LOG_FACMASK) == LOG_KERN && KernXlat) 1589 1.143 gutterid pri = LOG_USER | LOG_PRI(pri); 1590 1.1 cgd 1591 1.87 christos if (bsdsyslog) { 1592 1.87 christos buffer = printline_bsdsyslog(hname, p, flags, pri); 1593 1.87 christos } else { 1594 1.87 christos buffer = printline_syslogprotocol(hname, p, flags, pri); 1595 1.42 sommerfe } 1596 1.87 christos logmsg(buffer); 1597 1.87 christos DELREF(buffer); 1598 1.1 cgd } 1599 1.1 cgd 1600 1.1 cgd /* 1601 1.1 cgd * Take a raw input line from /dev/klog, split and format similar to syslog(). 1602 1.1 cgd */ 1603 1.5 perry void 1604 1.53 wiz printsys(char *msg) 1605 1.1 cgd { 1606 1.87 christos int n, is_printf, pri, flags; 1607 1.70 thorpej char *p, *q; 1608 1.87 christos struct buf_msg *buffer; 1609 1.1 cgd 1610 1.104 enami klog_linebufoff = 0; 1611 1.1 cgd for (p = msg; *p != '\0'; ) { 1612 1.87 christos bool bsdsyslog = true; 1613 1.87 christos 1614 1.87 christos is_printf = 1; 1615 1.87 christos flags = ISKERNEL | ADDDATE | BSDSYSLOG; 1616 1.66 mycroft if (SyncKernel) 1617 1.66 mycroft flags |= SYNC_FILE; 1618 1.87 christos if (is_printf) /* kernel printf's come out on console */ 1619 1.87 christos flags |= IGN_CONS; 1620 1.1 cgd pri = DEFSPRI; 1621 1.87 christos 1622 1.1 cgd if (*p == '<') { 1623 1.70 thorpej errno = 0; 1624 1.70 thorpej n = (int)strtol(p + 1, &q, 10); 1625 1.70 thorpej if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) { 1626 1.70 thorpej p = q + 1; 1627 1.87 christos is_printf = 0; 1628 1.70 thorpej pri = n; 1629 1.87 christos if (*p == '1') { /* syslog-protocol version */ 1630 1.87 christos p += 2; /* skip version and space */ 1631 1.87 christos bsdsyslog = false; 1632 1.87 christos } else { 1633 1.87 christos bsdsyslog = true; 1634 1.87 christos } 1635 1.70 thorpej } 1636 1.70 thorpej } 1637 1.70 thorpej for (q = p; *q != '\0' && *q != '\n'; q++) 1638 1.87 christos /* look for end of line; no further checks. 1639 1.87 christos * trust the kernel to send ASCII only */; 1640 1.70 thorpej if (*q != '\0') 1641 1.70 thorpej *q++ = '\0'; 1642 1.103 enami else { 1643 1.104 enami memcpy(linebuf, p, klog_linebufoff = q - p); 1644 1.103 enami break; 1645 1.103 enami } 1646 1.87 christos 1647 1.87 christos if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 1648 1.87 christos pri = DEFSPRI; 1649 1.87 christos 1650 1.87 christos /* allow all kinds of input from kernel */ 1651 1.87 christos if (is_printf) 1652 1.87 christos buffer = printline_kernelprintf( 1653 1.87 christos LocalFQDN, p, flags, pri); 1654 1.87 christos else { 1655 1.87 christos if (bsdsyslog) 1656 1.87 christos buffer = printline_bsdsyslog( 1657 1.87 christos LocalFQDN, p, flags, pri); 1658 1.87 christos else 1659 1.87 christos buffer = printline_syslogprotocol( 1660 1.87 christos LocalFQDN, p, flags, pri); 1661 1.87 christos } 1662 1.87 christos 1663 1.87 christos /* set fields left open */ 1664 1.87 christos if (!buffer->prog) 1665 1.87 christos buffer->prog = strdup(_PATH_UNIX); 1666 1.87 christos if (!buffer->host) 1667 1.87 christos buffer->host = LocalFQDN; 1668 1.87 christos if (!buffer->recvhost) 1669 1.87 christos buffer->recvhost = LocalFQDN; 1670 1.87 christos 1671 1.87 christos logmsg(buffer); 1672 1.87 christos DELREF(buffer); 1673 1.70 thorpej p = q; 1674 1.1 cgd } 1675 1.1 cgd } 1676 1.1 cgd 1677 1.1 cgd /* 1678 1.70 thorpej * Check to see if `name' matches the provided specification, using the 1679 1.70 thorpej * specified strstr function. 1680 1.70 thorpej */ 1681 1.70 thorpej int 1682 1.70 thorpej matches_spec(const char *name, const char *spec, 1683 1.70 thorpej char *(*check)(const char *, const char *)) 1684 1.70 thorpej { 1685 1.70 thorpej const char *s; 1686 1.83 yamt const char *cursor; 1687 1.70 thorpej char prev, next; 1688 1.84 christos size_t len; 1689 1.84 christos 1690 1.84 christos if (name[0] == '\0') 1691 1.87 christos return 0; 1692 1.70 thorpej 1693 1.83 yamt if (strchr(name, ',')) /* sanity */ 1694 1.87 christos return 0; 1695 1.83 yamt 1696 1.84 christos len = strlen(name); 1697 1.83 yamt cursor = spec; 1698 1.83 yamt while ((s = (*check)(cursor, name)) != NULL) { 1699 1.70 thorpej prev = s == spec ? ',' : *(s - 1); 1700 1.84 christos cursor = s + len; 1701 1.83 yamt next = *cursor; 1702 1.70 thorpej 1703 1.70 thorpej if (prev == ',' && (next == '\0' || next == ',')) 1704 1.87 christos return 1; 1705 1.70 thorpej } 1706 1.70 thorpej 1707 1.87 christos return 0; 1708 1.70 thorpej } 1709 1.70 thorpej 1710 1.92 minskim /* 1711 1.87 christos * wrapper with old function signature, 1712 1.87 christos * keeps calling code shorter and hides buffer allocation 1713 1.1 cgd */ 1714 1.5 perry void 1715 1.87 christos logmsg_async(int pri, const char *sd, const char *msg, int flags) 1716 1.1 cgd { 1717 1.87 christos struct buf_msg *buffer; 1718 1.87 christos size_t msglen; 1719 1.92 minskim 1720 1.87 christos DPRINTF((D_CALL|D_DATA), "logmsg_async(%d, \"%s\", \"%s\", %d)\n", 1721 1.87 christos pri, sd, msg, flags); 1722 1.1 cgd 1723 1.87 christos if (msg) { 1724 1.87 christos msglen = strlen(msg); 1725 1.87 christos msglen++; /* adds \0 */ 1726 1.87 christos buffer = buf_msg_new(msglen); 1727 1.87 christos buffer->msglen = strlcpy(buffer->msg, msg, msglen) + 1; 1728 1.87 christos } else { 1729 1.87 christos buffer = buf_msg_new(0); 1730 1.87 christos } 1731 1.87 christos if (sd) buffer->sd = strdup(sd); 1732 1.121 christos buffer->timestamp = make_timestamp(NULL, !BSDOutputFormat, 0); 1733 1.87 christos buffer->prog = appname; 1734 1.87 christos buffer->pid = include_pid; 1735 1.87 christos buffer->recvhost = buffer->host = LocalFQDN; 1736 1.87 christos buffer->pri = pri; 1737 1.87 christos buffer->flags = flags; 1738 1.1 cgd 1739 1.87 christos logmsg(buffer); 1740 1.87 christos DELREF(buffer); 1741 1.87 christos } 1742 1.1 cgd 1743 1.87 christos /* read timestamp in from_buf, convert into a timestamp in to_buf 1744 1.87 christos * 1745 1.87 christos * returns length of timestamp found in from_buf (= number of bytes consumed) 1746 1.87 christos */ 1747 1.87 christos size_t 1748 1.87 christos check_timestamp(unsigned char *from_buf, char **to_buf, 1749 1.87 christos bool from_iso, bool to_iso) 1750 1.87 christos { 1751 1.87 christos unsigned char *q; 1752 1.87 christos int p; 1753 1.87 christos bool found_ts = false; 1754 1.92 minskim 1755 1.87 christos DPRINTF((D_CALL|D_DATA), "check_timestamp(%p = \"%s\", from_iso=%d, " 1756 1.87 christos "to_iso=%d)\n", from_buf, from_buf, from_iso, to_iso); 1757 1.92 minskim 1758 1.87 christos if (!from_buf) return 0; 1759 1.1 cgd /* 1760 1.1 cgd * Check to see if msg looks non-standard. 1761 1.87 christos * looks at every char because we do not have a msg length yet 1762 1.1 cgd */ 1763 1.87 christos /* detailed checking adapted from Albert Mietus' sl_timestamp.c */ 1764 1.87 christos if (from_iso) { 1765 1.87 christos if (from_buf[4] == '-' && from_buf[7] == '-' 1766 1.87 christos && from_buf[10] == 'T' && from_buf[13] == ':' 1767 1.87 christos && from_buf[16] == ':' 1768 1.92 minskim && isdigit(from_buf[0]) && isdigit(from_buf[1]) 1769 1.87 christos && isdigit(from_buf[2]) && isdigit(from_buf[3]) /* YYYY */ 1770 1.87 christos && isdigit(from_buf[5]) && isdigit(from_buf[6]) 1771 1.87 christos && isdigit(from_buf[8]) && isdigit(from_buf[9]) /* mm dd */ 1772 1.87 christos && isdigit(from_buf[11]) && isdigit(from_buf[12]) /* HH */ 1773 1.87 christos && isdigit(from_buf[14]) && isdigit(from_buf[15]) /* MM */ 1774 1.87 christos && isdigit(from_buf[17]) && isdigit(from_buf[18]) /* SS */ 1775 1.87 christos ) { 1776 1.87 christos /* time-secfrac */ 1777 1.87 christos if (from_buf[19] == '.') 1778 1.87 christos for (p=20; isdigit(from_buf[p]); p++) /* NOP*/; 1779 1.87 christos else 1780 1.87 christos p = 19; 1781 1.87 christos /* time-offset */ 1782 1.87 christos if (from_buf[p] == 'Z' 1783 1.87 christos || ((from_buf[p] == '+' || from_buf[p] == '-') 1784 1.87 christos && from_buf[p+3] == ':' 1785 1.87 christos && isdigit(from_buf[p+1]) && isdigit(from_buf[p+2]) 1786 1.87 christos && isdigit(from_buf[p+4]) && isdigit(from_buf[p+5]) 1787 1.87 christos )) 1788 1.87 christos found_ts = true; 1789 1.87 christos } 1790 1.87 christos } else { 1791 1.87 christos if (from_buf[3] == ' ' && from_buf[6] == ' ' 1792 1.87 christos && from_buf[9] == ':' && from_buf[12] == ':' 1793 1.87 christos && (from_buf[4] == ' ' || isdigit(from_buf[4])) 1794 1.87 christos && isdigit(from_buf[5]) /* dd */ 1795 1.87 christos && isdigit(from_buf[7]) && isdigit(from_buf[8]) /* HH */ 1796 1.87 christos && isdigit(from_buf[10]) && isdigit(from_buf[11]) /* MM */ 1797 1.87 christos && isdigit(from_buf[13]) && isdigit(from_buf[14]) /* SS */ 1798 1.87 christos && isupper(from_buf[0]) && islower(from_buf[1]) /* month */ 1799 1.87 christos && islower(from_buf[2])) 1800 1.87 christos found_ts = true; 1801 1.87 christos } 1802 1.94 christos if (!found_ts) { 1803 1.94 christos if (from_buf[0] == '-' && from_buf[1] == ' ') { 1804 1.94 christos /* NILVALUE */ 1805 1.94 christos if (to_iso) { 1806 1.94 christos /* with ISO = syslog-protocol output leave 1807 1.94 christos * it as is, because it is better to have 1808 1.94 christos * no timestamp than a wrong one. 1809 1.94 christos */ 1810 1.94 christos *to_buf = strdup("-"); 1811 1.94 christos } else { 1812 1.141 uwe /* with BSD Syslog the field is required 1813 1.94 christos * so replace it with current time 1814 1.94 christos */ 1815 1.121 christos *to_buf = make_timestamp(NULL, false, 0); 1816 1.94 christos } 1817 1.94 christos return 2; 1818 1.87 christos } 1819 1.121 christos *to_buf = make_timestamp(NULL, false, 0); 1820 1.94 christos return 0; 1821 1.1 cgd } 1822 1.92 minskim 1823 1.87 christos if (!from_iso && !to_iso) { 1824 1.87 christos /* copy BSD timestamp */ 1825 1.87 christos DPRINTF(D_CALL, "check_timestamp(): copy BSD timestamp\n"); 1826 1.87 christos *to_buf = strndup((char *)from_buf, BSD_TIMESTAMPLEN); 1827 1.87 christos return BSD_TIMESTAMPLEN; 1828 1.87 christos } else if (from_iso && to_iso) { 1829 1.87 christos /* copy ISO timestamp */ 1830 1.87 christos DPRINTF(D_CALL, "check_timestamp(): copy ISO timestamp\n"); 1831 1.87 christos if (!(q = (unsigned char *) strchr((char *)from_buf, ' '))) 1832 1.87 christos q = from_buf + strlen((char *)from_buf); 1833 1.87 christos *to_buf = strndup((char *)from_buf, q - from_buf); 1834 1.87 christos return q - from_buf; 1835 1.87 christos } else if (from_iso && !to_iso) { 1836 1.87 christos /* convert ISO->BSD */ 1837 1.87 christos struct tm parsed; 1838 1.87 christos time_t timeval; 1839 1.87 christos char tsbuf[MAX_TIMESTAMPLEN]; 1840 1.123 christos int i = 0, j; 1841 1.87 christos 1842 1.87 christos DPRINTF(D_CALL, "check_timestamp(): convert ISO->BSD\n"); 1843 1.87 christos for(i = 0; i < MAX_TIMESTAMPLEN && from_buf[i] != '\0' 1844 1.87 christos && from_buf[i] != '.' && from_buf[i] != ' '; i++) 1845 1.87 christos tsbuf[i] = from_buf[i]; /* copy date & time */ 1846 1.123 christos j = i; 1847 1.87 christos for(; i < MAX_TIMESTAMPLEN && from_buf[i] != '\0' 1848 1.87 christos && from_buf[i] != '+' && from_buf[i] != '-' 1849 1.87 christos && from_buf[i] != 'Z' && from_buf[i] != ' '; i++) 1850 1.87 christos ; /* skip fraction digits */ 1851 1.87 christos for(; i < MAX_TIMESTAMPLEN && from_buf[i] != '\0' 1852 1.123 christos && from_buf[i] != ':' && from_buf[i] != ' ' ; i++, j++) 1853 1.123 christos tsbuf[j] = from_buf[i]; /* copy TZ */ 1854 1.87 christos if (from_buf[i] == ':') i++; /* skip colon */ 1855 1.87 christos for(; i < MAX_TIMESTAMPLEN && from_buf[i] != '\0' 1856 1.123 christos && from_buf[i] != ' ' ; i++, j++) 1857 1.123 christos tsbuf[j] = from_buf[i]; /* copy TZ */ 1858 1.87 christos 1859 1.89 christos (void)memset(&parsed, 0, sizeof(parsed)); 1860 1.123 christos (void)strptime(tsbuf, "%FT%T%z", &parsed); 1861 1.89 christos parsed.tm_isdst = -1; 1862 1.87 christos timeval = mktime(&parsed); 1863 1.87 christos 1864 1.121 christos *to_buf = make_timestamp(&timeval, false, BSD_TIMESTAMPLEN); 1865 1.87 christos return i; 1866 1.87 christos } else if (!from_iso && to_iso) { 1867 1.87 christos /* convert BSD->ISO */ 1868 1.87 christos struct tm parsed; 1869 1.87 christos struct tm *current; 1870 1.87 christos time_t timeval; 1871 1.87 christos 1872 1.89 christos (void)memset(&parsed, 0, sizeof(parsed)); 1873 1.89 christos parsed.tm_isdst = -1; 1874 1.87 christos DPRINTF(D_CALL, "check_timestamp(): convert BSD->ISO\n"); 1875 1.121 christos strptime((char *)from_buf, "%b %d %T", &parsed); 1876 1.87 christos current = gmtime(&now); 1877 1.87 christos 1878 1.87 christos /* use current year and timezone */ 1879 1.87 christos parsed.tm_isdst = current->tm_isdst; 1880 1.87 christos parsed.tm_gmtoff = current->tm_gmtoff; 1881 1.87 christos parsed.tm_year = current->tm_year; 1882 1.87 christos if (current->tm_mon == 0 && parsed.tm_mon == 11) 1883 1.87 christos parsed.tm_year--; 1884 1.87 christos 1885 1.87 christos timeval = mktime(&parsed); 1886 1.121 christos *to_buf = make_timestamp(&timeval, true, MAX_TIMESTAMPLEN - 1); 1887 1.1 cgd 1888 1.87 christos return BSD_TIMESTAMPLEN; 1889 1.87 christos } else { 1890 1.87 christos DPRINTF(D_MISC, 1891 1.87 christos "Executing unreachable code in check_timestamp()\n"); 1892 1.87 christos return 0; 1893 1.70 thorpej } 1894 1.87 christos } 1895 1.70 thorpej 1896 1.87 christos /* 1897 1.87 christos * Log a message to the appropriate log files, users, etc. based on 1898 1.87 christos * the priority. 1899 1.87 christos */ 1900 1.87 christos void 1901 1.87 christos logmsg(struct buf_msg *buffer) 1902 1.87 christos { 1903 1.87 christos struct filed *f; 1904 1.87 christos int fac, omask, prilev; 1905 1.1 cgd 1906 1.87 christos DPRINTF((D_CALL|D_BUFFER), "logmsg: buffer@%p, pri 0%o/%d, flags 0x%x," 1907 1.87 christos " timestamp \"%s\", from \"%s\", sd \"%s\", msg \"%s\"\n", 1908 1.87 christos buffer, buffer->pri, buffer->pri, buffer->flags, 1909 1.87 christos buffer->timestamp, buffer->recvhost, buffer->sd, buffer->msg); 1910 1.87 christos 1911 1.87 christos omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); 1912 1.87 christos 1913 1.87 christos /* sanity check */ 1914 1.87 christos assert(buffer->refcount == 1); 1915 1.87 christos assert(buffer->msglen <= buffer->msgsize); 1916 1.87 christos assert(buffer->msgorig <= buffer->msg); 1917 1.87 christos assert((buffer->msg && buffer->msglen == strlen(buffer->msg)+1) 1918 1.87 christos || (!buffer->msg && !buffer->msglen)); 1919 1.87 christos if (!buffer->msg && !buffer->sd && !buffer->msgid) 1920 1.87 christos DPRINTF(D_BUFFER, "Empty message?\n"); 1921 1.87 christos 1922 1.87 christos /* extract facility and priority level */ 1923 1.87 christos if (buffer->flags & MARK) 1924 1.87 christos fac = LOG_NFACILITIES; 1925 1.87 christos else 1926 1.87 christos fac = LOG_FAC(buffer->pri); 1927 1.87 christos prilev = LOG_PRI(buffer->pri); 1928 1.70 thorpej 1929 1.1 cgd /* log the message to the particular outputs */ 1930 1.1 cgd if (!Initialized) { 1931 1.1 cgd f = &consfile; 1932 1.108 christos f->f_file = open(ctty, O_WRONLY | O_NDELAY, 0); 1933 1.1 cgd 1934 1.1 cgd if (f->f_file >= 0) { 1935 1.87 christos DELREF(f->f_prevmsg); 1936 1.87 christos f->f_prevmsg = NEWREF(buffer); 1937 1.87 christos fprintlog(f, NEWREF(buffer), NULL); 1938 1.87 christos DELREF(buffer); 1939 1.5 perry (void)close(f->f_file); 1940 1.1 cgd } 1941 1.5 perry (void)sigsetmask(omask); 1942 1.1 cgd return; 1943 1.1 cgd } 1944 1.87 christos 1945 1.1 cgd for (f = Files; f; f = f->f_next) { 1946 1.120 jnemeth char *h; /* host to use for comparing */ 1947 1.120 jnemeth 1948 1.1 cgd /* skip messages that are incorrect priority */ 1949 1.87 christos if (!MATCH_PRI(f, fac, prilev) 1950 1.70 thorpej || f->f_pmask[fac] == INTERNAL_NOPRI) 1951 1.1 cgd continue; 1952 1.1 cgd 1953 1.70 thorpej /* skip messages with the incorrect host name */ 1954 1.120 jnemeth /* compare with host (which is supposedly more correct), */ 1955 1.120 jnemeth /* but fallback to recvhost if host is NULL */ 1956 1.120 jnemeth h = (buffer->host != NULL) ? buffer->host : buffer->recvhost; 1957 1.120 jnemeth if (f->f_host != NULL && h != NULL) { 1958 1.120 jnemeth char shost[MAXHOSTNAMELEN + 1]; 1959 1.120 jnemeth 1960 1.120 jnemeth if (BSDOutputFormat) { 1961 1.120 jnemeth (void)strlcpy(shost, h, sizeof(shost)); 1962 1.93 christos trim_anydomain(shost); 1963 1.93 christos h = shost; 1964 1.93 christos } 1965 1.70 thorpej switch (f->f_host[0]) { 1966 1.70 thorpej case '+': 1967 1.93 christos if (! matches_spec(h, f->f_host + 1, 1968 1.87 christos strcasestr)) 1969 1.70 thorpej continue; 1970 1.70 thorpej break; 1971 1.70 thorpej case '-': 1972 1.93 christos if (matches_spec(h, f->f_host + 1, 1973 1.87 christos strcasestr)) 1974 1.70 thorpej continue; 1975 1.70 thorpej break; 1976 1.70 thorpej } 1977 1.70 thorpej } 1978 1.70 thorpej 1979 1.70 thorpej /* skip messages with the incorrect program name */ 1980 1.87 christos if (f->f_program != NULL && buffer->prog != NULL) { 1981 1.70 thorpej switch (f->f_program[0]) { 1982 1.70 thorpej case '+': 1983 1.87 christos if (!matches_spec(buffer->prog, 1984 1.87 christos f->f_program + 1, strstr)) 1985 1.70 thorpej continue; 1986 1.70 thorpej break; 1987 1.70 thorpej case '-': 1988 1.87 christos if (matches_spec(buffer->prog, 1989 1.87 christos f->f_program + 1, strstr)) 1990 1.70 thorpej continue; 1991 1.70 thorpej break; 1992 1.70 thorpej default: 1993 1.87 christos if (!matches_spec(buffer->prog, 1994 1.87 christos f->f_program, strstr)) 1995 1.70 thorpej continue; 1996 1.70 thorpej break; 1997 1.70 thorpej } 1998 1.70 thorpej } 1999 1.70 thorpej 2000 1.87 christos if (f->f_type == F_CONSOLE && (buffer->flags & IGN_CONS)) 2001 1.1 cgd continue; 2002 1.1 cgd 2003 1.1 cgd /* don't output marks to recently written files */ 2004 1.87 christos if ((buffer->flags & MARK) 2005 1.87 christos && (now - f->f_time) < MarkInterval / 2) 2006 1.1 cgd continue; 2007 1.1 cgd 2008 1.1 cgd /* 2009 1.63 lukem * suppress duplicate lines to this file unless NoRepeat 2010 1.1 cgd */ 2011 1.87 christos #define MSG_FIELD_EQ(x) ((!buffer->x && !f->f_prevmsg->x) || \ 2012 1.87 christos (buffer->x && f->f_prevmsg->x && !strcmp(buffer->x, f->f_prevmsg->x))) 2013 1.87 christos 2014 1.87 christos if ((buffer->flags & MARK) == 0 && 2015 1.87 christos f->f_prevmsg && 2016 1.87 christos buffer->msglen == f->f_prevmsg->msglen && 2017 1.63 lukem !NoRepeat && 2018 1.87 christos MSG_FIELD_EQ(host) && 2019 1.87 christos MSG_FIELD_EQ(sd) && 2020 1.87 christos MSG_FIELD_EQ(msg) 2021 1.87 christos ) { 2022 1.1 cgd f->f_prevcount++; 2023 1.87 christos DPRINTF(D_DATA, "Msg repeated %d times, %ld sec of %d\n", 2024 1.12 thorpej f->f_prevcount, (long)(now - f->f_time), 2025 1.1 cgd repeatinterval[f->f_repeatcount]); 2026 1.1 cgd /* 2027 1.1 cgd * If domark would have logged this by now, 2028 1.1 cgd * flush it now (so we don't hold isolated messages), 2029 1.1 cgd * but back off so we'll flush less often 2030 1.1 cgd * in the future. 2031 1.1 cgd */ 2032 1.1 cgd if (now > REPEATTIME(f)) { 2033 1.87 christos fprintlog(f, NEWREF(buffer), NULL); 2034 1.87 christos DELREF(buffer); 2035 1.1 cgd BACKOFF(f); 2036 1.1 cgd } 2037 1.1 cgd } else { 2038 1.1 cgd /* new line, save it */ 2039 1.1 cgd if (f->f_prevcount) 2040 1.87 christos fprintlog(f, NULL, NULL); 2041 1.1 cgd f->f_repeatcount = 0; 2042 1.87 christos DELREF(f->f_prevmsg); 2043 1.87 christos f->f_prevmsg = NEWREF(buffer); 2044 1.87 christos fprintlog(f, NEWREF(buffer), NULL); 2045 1.87 christos DELREF(buffer); 2046 1.1 cgd } 2047 1.1 cgd } 2048 1.5 perry (void)sigsetmask(omask); 2049 1.1 cgd } 2050 1.1 cgd 2051 1.87 christos /* 2052 1.87 christos * format one buffer into output format given by flag BSDOutputFormat 2053 1.87 christos * line is allocated and has to be free()d by caller 2054 1.87 christos * size_t pointers are optional, if not NULL then they will return 2055 1.132 msaitoh * different lengths used for formatting and output 2056 1.87 christos */ 2057 1.87 christos #define OUT(x) ((x)?(x):"-") 2058 1.87 christos bool 2059 1.87 christos format_buffer(struct buf_msg *buffer, char **line, size_t *ptr_linelen, 2060 1.87 christos size_t *ptr_msglen, size_t *ptr_tlsprefixlen, size_t *ptr_prilen) 2061 1.1 cgd { 2062 1.87 christos #define FPBUFSIZE 30 2063 1.87 christos static char ascii_empty[] = ""; 2064 1.87 christos char fp_buf[FPBUFSIZE] = "\0"; 2065 1.87 christos char *hostname, *shorthostname = NULL; 2066 1.87 christos char *ascii_sd = ascii_empty; 2067 1.87 christos char *ascii_msg = ascii_empty; 2068 1.87 christos size_t linelen, msglen, tlsprefixlen, prilen, j; 2069 1.87 christos 2070 1.87 christos DPRINTF(D_CALL, "format_buffer(%p)\n", buffer); 2071 1.87 christos if (!buffer) return false; 2072 1.87 christos 2073 1.87 christos /* All buffer fields are set with strdup(). To avoid problems 2074 1.87 christos * on memory exhaustion we allow them to be empty and replace 2075 1.87 christos * the essential fields with already allocated generic values. 2076 1.87 christos */ 2077 1.87 christos if (!buffer->timestamp) 2078 1.87 christos buffer->timestamp = timestamp; 2079 1.87 christos if (!buffer->host && !buffer->recvhost) 2080 1.87 christos buffer->host = LocalFQDN; 2081 1.92 minskim 2082 1.70 thorpej if (LogFacPri) { 2083 1.70 thorpej const char *f_s = NULL, *p_s = NULL; 2084 1.87 christos int fac = buffer->pri & LOG_FACMASK; 2085 1.87 christos int pri = LOG_PRI(buffer->pri); 2086 1.70 thorpej char f_n[5], p_n[5]; 2087 1.70 thorpej 2088 1.70 thorpej if (LogFacPri > 1) { 2089 1.70 thorpej CODE *c; 2090 1.70 thorpej 2091 1.70 thorpej for (c = facilitynames; c->c_name != NULL; c++) { 2092 1.70 thorpej if (c->c_val == fac) { 2093 1.70 thorpej f_s = c->c_name; 2094 1.70 thorpej break; 2095 1.70 thorpej } 2096 1.70 thorpej } 2097 1.70 thorpej for (c = prioritynames; c->c_name != NULL; c++) { 2098 1.70 thorpej if (c->c_val == pri) { 2099 1.70 thorpej p_s = c->c_name; 2100 1.70 thorpej break; 2101 1.70 thorpej } 2102 1.70 thorpej } 2103 1.70 thorpej } 2104 1.70 thorpej if (f_s == NULL) { 2105 1.70 thorpej snprintf(f_n, sizeof(f_n), "%d", LOG_FAC(fac)); 2106 1.70 thorpej f_s = f_n; 2107 1.70 thorpej } 2108 1.70 thorpej if (p_s == NULL) { 2109 1.70 thorpej snprintf(p_n, sizeof(p_n), "%d", pri); 2110 1.70 thorpej p_s = p_n; 2111 1.70 thorpej } 2112 1.70 thorpej snprintf(fp_buf, sizeof(fp_buf), "<%s.%s>", f_s, p_s); 2113 1.87 christos } 2114 1.87 christos 2115 1.87 christos /* hostname or FQDN */ 2116 1.87 christos hostname = (buffer->host ? buffer->host : buffer->recvhost); 2117 1.87 christos if (BSDOutputFormat 2118 1.87 christos && (shorthostname = strdup(hostname))) { 2119 1.87 christos /* if the previous BSD output format with "host [recvhost]:" 2120 1.87 christos * gets implemented, this is the right place to distinguish 2121 1.87 christos * between buffer->host and buffer->recvhost 2122 1.87 christos */ 2123 1.87 christos trim_anydomain(shorthostname); 2124 1.87 christos hostname = shorthostname; 2125 1.87 christos } 2126 1.87 christos 2127 1.87 christos /* new message formatting: 2128 1.87 christos * instead of using iov always assemble one complete TLS-ready line 2129 1.87 christos * with length and priority (depending on BSDOutputFormat either in 2130 1.87 christos * BSD Syslog or syslog-protocol format) 2131 1.92 minskim * 2132 1.87 christos * additionally save the length of the prefixes, 2133 1.87 christos * so UDP destinations can skip the length prefix and 2134 1.87 christos * file/pipe/wall destinations can omit length and priority 2135 1.87 christos */ 2136 1.87 christos /* first determine required space */ 2137 1.87 christos if (BSDOutputFormat) { 2138 1.87 christos /* only output ASCII chars */ 2139 1.87 christos if (buffer->sd) 2140 1.87 christos ascii_sd = copy_utf8_ascii(buffer->sd, 2141 1.87 christos strlen(buffer->sd)); 2142 1.87 christos if (buffer->msg) { 2143 1.87 christos if (IS_BOM(buffer->msg)) 2144 1.87 christos ascii_msg = copy_utf8_ascii(buffer->msg, 2145 1.87 christos buffer->msglen - 1); 2146 1.87 christos else /* assume already converted at input */ 2147 1.87 christos ascii_msg = buffer->msg; 2148 1.87 christos } 2149 1.87 christos msglen = snprintf(NULL, 0, "<%d>%s%.15s %s %s%s%s%s: %s%s%s", 2150 1.87 christos buffer->pri, fp_buf, buffer->timestamp, 2151 1.87 christos hostname, OUT(buffer->prog), 2152 1.92 minskim buffer->pid ? "[" : "", 2153 1.92 minskim buffer->pid ? buffer->pid : "", 2154 1.87 christos buffer->pid ? "]" : "", ascii_sd, 2155 1.87 christos (buffer->sd && buffer->msg ? " ": ""), ascii_msg); 2156 1.87 christos } else 2157 1.87 christos msglen = snprintf(NULL, 0, "<%d>1 %s%s %s %s %s %s %s%s%s", 2158 1.87 christos buffer->pri, fp_buf, buffer->timestamp, 2159 1.87 christos hostname, OUT(buffer->prog), OUT(buffer->pid), 2160 1.87 christos OUT(buffer->msgid), OUT(buffer->sd), 2161 1.87 christos (buffer->msg ? " ": ""), 2162 1.87 christos (buffer->msg ? buffer->msg: "")); 2163 1.87 christos /* add space for length prefix */ 2164 1.87 christos tlsprefixlen = 0; 2165 1.87 christos for (j = msglen; j; j /= 10) 2166 1.87 christos tlsprefixlen++; 2167 1.87 christos /* one more for the space */ 2168 1.87 christos tlsprefixlen++; 2169 1.87 christos 2170 1.87 christos prilen = snprintf(NULL, 0, "<%d>", buffer->pri); 2171 1.87 christos if (!BSDOutputFormat) 2172 1.87 christos prilen += 2; /* version char and space */ 2173 1.87 christos MALLOC(*line, msglen + tlsprefixlen + 1); 2174 1.87 christos if (BSDOutputFormat) 2175 1.87 christos linelen = snprintf(*line, 2176 1.87 christos msglen + tlsprefixlen + 1, 2177 1.87 christos "%zu <%d>%s%.15s %s %s%s%s%s: %s%s%s", 2178 1.92 minskim msglen, buffer->pri, fp_buf, buffer->timestamp, 2179 1.87 christos hostname, OUT(buffer->prog), 2180 1.87 christos (buffer->pid ? "[" : ""), 2181 1.87 christos (buffer->pid ? buffer->pid : ""), 2182 1.87 christos (buffer->pid ? "]" : ""), ascii_sd, 2183 1.87 christos (buffer->sd && buffer->msg ? " ": ""), ascii_msg); 2184 1.87 christos else 2185 1.87 christos linelen = snprintf(*line, 2186 1.87 christos msglen + tlsprefixlen + 1, 2187 1.87 christos "%zu <%d>1 %s%s %s %s %s %s %s%s%s", 2188 1.87 christos msglen, buffer->pri, fp_buf, buffer->timestamp, 2189 1.87 christos hostname, OUT(buffer->prog), OUT(buffer->pid), 2190 1.87 christos OUT(buffer->msgid), OUT(buffer->sd), 2191 1.87 christos (buffer->msg ? " ": ""), 2192 1.87 christos (buffer->msg ? buffer->msg: "")); 2193 1.87 christos DPRINTF(D_DATA, "formatted %zu octets to: '%.*s' (linelen %zu, " 2194 1.87 christos "msglen %zu, tlsprefixlen %zu, prilen %zu)\n", linelen, 2195 1.87 christos (int)linelen, *line, linelen, msglen, tlsprefixlen, prilen); 2196 1.87 christos 2197 1.87 christos FREEPTR(shorthostname); 2198 1.87 christos if (ascii_sd != ascii_empty) 2199 1.87 christos FREEPTR(ascii_sd); 2200 1.87 christos if (ascii_msg != ascii_empty && ascii_msg != buffer->msg) 2201 1.87 christos FREEPTR(ascii_msg); 2202 1.87 christos 2203 1.87 christos if (ptr_linelen) *ptr_linelen = linelen; 2204 1.87 christos if (ptr_msglen) *ptr_msglen = msglen; 2205 1.87 christos if (ptr_tlsprefixlen) *ptr_tlsprefixlen = tlsprefixlen; 2206 1.87 christos if (ptr_prilen) *ptr_prilen = prilen; 2207 1.87 christos return true; 2208 1.87 christos } 2209 1.87 christos 2210 1.87 christos /* 2211 1.87 christos * if qentry == NULL: new message, if temporarily undeliverable it will be enqueued 2212 1.87 christos * if qentry != NULL: a temporarily undeliverable message will not be enqueued, 2213 1.87 christos * but after delivery be removed from the queue 2214 1.87 christos */ 2215 1.87 christos void 2216 1.87 christos fprintlog(struct filed *f, struct buf_msg *passedbuffer, struct buf_queue *qentry) 2217 1.87 christos { 2218 1.87 christos static char crnl[] = "\r\n"; 2219 1.87 christos struct buf_msg *buffer = passedbuffer; 2220 1.87 christos struct iovec iov[4]; 2221 1.87 christos struct iovec *v = iov; 2222 1.87 christos bool error = false; 2223 1.87 christos int e = 0, len = 0; 2224 1.87 christos size_t msglen, linelen, tlsprefixlen, prilen; 2225 1.87 christos char *p, *line = NULL, *lineptr = NULL; 2226 1.100 riz #ifndef DISABLE_SIGN 2227 1.87 christos bool newhash = false; 2228 1.87 christos #endif 2229 1.87 christos #define REPBUFSIZE 80 2230 1.87 christos char greetings[200]; 2231 1.96 lukem #define ADDEV() do { v++; assert((size_t)(v - iov) < A_CNT(iov)); } while(/*CONSTCOND*/0) 2232 1.87 christos 2233 1.87 christos DPRINTF(D_CALL, "fprintlog(%p, %p, %p)\n", f, buffer, qentry); 2234 1.87 christos 2235 1.87 christos f->f_time = now; 2236 1.87 christos 2237 1.87 christos /* increase refcount here and lower again at return. 2238 1.87 christos * this enables the buffer in the else branch to be freed 2239 1.92 minskim * --> every branch needs one NEWREF() or buf_msg_new()! */ 2240 1.87 christos if (buffer) { 2241 1.102 joerg (void)NEWREF(buffer); 2242 1.70 thorpej } else { 2243 1.87 christos if (f->f_prevcount > 1) { 2244 1.87 christos /* possible syslog-sign incompatibility: 2245 1.87 christos * assume destinations f1 and f2 share one SG and 2246 1.87 christos * get the same message sequence. 2247 1.92 minskim * 2248 1.87 christos * now both f1 and f2 generate "repeated" messages 2249 1.87 christos * "repeated" messages are different due to different 2250 1.87 christos * timestamps 2251 1.87 christos * the SG will get hashes for the two "repeated" messages 2252 1.92 minskim * 2253 1.87 christos * now both f1 and f2 are just fine, but a verification 2254 1.87 christos * will report that each 'lost' a message, i.e. the 2255 1.87 christos * other's "repeated" message 2256 1.92 minskim * 2257 1.87 christos * conditions for 'safe configurations': 2258 1.87 christos * - use NoRepeat option, 2259 1.87 christos * - use SG 3, or 2260 1.87 christos * - have exactly one destination for every PRI 2261 1.87 christos */ 2262 1.87 christos buffer = buf_msg_new(REPBUFSIZE); 2263 1.87 christos buffer->msglen = snprintf(buffer->msg, REPBUFSIZE, 2264 1.87 christos "last message repeated %d times", f->f_prevcount); 2265 1.121 christos buffer->timestamp = make_timestamp(NULL, 2266 1.121 christos !BSDOutputFormat, 0); 2267 1.87 christos buffer->pri = f->f_prevmsg->pri; 2268 1.87 christos buffer->host = LocalFQDN; 2269 1.87 christos buffer->prog = appname; 2270 1.87 christos buffer->pid = include_pid; 2271 1.92 minskim 2272 1.87 christos } else { 2273 1.87 christos buffer = NEWREF(f->f_prevmsg); 2274 1.87 christos } 2275 1.70 thorpej } 2276 1.70 thorpej 2277 1.87 christos /* no syslog-sign messages to tty/console/... */ 2278 1.87 christos if ((buffer->flags & SIGN_MSG) 2279 1.87 christos && ((f->f_type == F_UNUSED) 2280 1.87 christos || (f->f_type == F_TTY) 2281 1.87 christos || (f->f_type == F_CONSOLE) 2282 1.87 christos || (f->f_type == F_USERS) 2283 1.117 christos || (f->f_type == F_WALL) 2284 1.117 christos || (f->f_type == F_FIFO))) { 2285 1.87 christos DELREF(buffer); 2286 1.87 christos return; 2287 1.87 christos } 2288 1.1 cgd 2289 1.87 christos /* buffering works only for few types */ 2290 1.87 christos if (qentry 2291 1.87 christos && (f->f_type != F_TLS) 2292 1.87 christos && (f->f_type != F_PIPE) 2293 1.117 christos && (f->f_type != F_FILE) 2294 1.117 christos && (f->f_type != F_FIFO)) { 2295 1.107 christos errno = 0; 2296 1.107 christos logerror("Warning: unexpected message type %d in buffer", 2297 1.107 christos f->f_type); 2298 1.87 christos DELREF(buffer); 2299 1.87 christos return; 2300 1.1 cgd } 2301 1.1 cgd 2302 1.87 christos if (!format_buffer(buffer, &line, 2303 1.87 christos &linelen, &msglen, &tlsprefixlen, &prilen)) { 2304 1.87 christos DPRINTF(D_CALL, "format_buffer() failed, skip message\n"); 2305 1.87 christos DELREF(buffer); 2306 1.87 christos return; 2307 1.87 christos } 2308 1.87 christos /* assert maximum message length */ 2309 1.87 christos if (TypeInfo[f->f_type].max_msg_length != -1 2310 1.96 lukem && (size_t)TypeInfo[f->f_type].max_msg_length 2311 1.87 christos < linelen - tlsprefixlen - prilen) { 2312 1.87 christos linelen = TypeInfo[f->f_type].max_msg_length 2313 1.87 christos + tlsprefixlen + prilen; 2314 1.87 christos DPRINTF(D_DATA, "truncating oversized message to %zu octets\n", 2315 1.87 christos linelen); 2316 1.87 christos } 2317 1.87 christos 2318 1.87 christos #ifndef DISABLE_SIGN 2319 1.87 christos /* keep state between appending the hash (before buffer is sent) 2320 1.87 christos * and possibly sending a SB (after buffer is sent): */ 2321 1.87 christos /* get hash */ 2322 1.87 christos if (!(buffer->flags & SIGN_MSG) && !qentry) { 2323 1.87 christos char *hash = NULL; 2324 1.87 christos struct signature_group_t *sg; 2325 1.87 christos 2326 1.87 christos if ((sg = sign_get_sg(buffer->pri, f)) != NULL) { 2327 1.87 christos if (sign_msg_hash(line + tlsprefixlen, &hash)) 2328 1.87 christos newhash = sign_append_hash(hash, sg); 2329 1.87 christos else 2330 1.87 christos DPRINTF(D_SIGN, 2331 1.87 christos "Unable to hash line \"%s\"\n", line); 2332 1.87 christos } 2333 1.87 christos } 2334 1.87 christos #endif /* !DISABLE_SIGN */ 2335 1.1 cgd 2336 1.87 christos /* set start and length of buffer and/or fill iovec */ 2337 1.1 cgd switch (f->f_type) { 2338 1.1 cgd case F_UNUSED: 2339 1.87 christos /* nothing */ 2340 1.87 christos break; 2341 1.87 christos case F_TLS: 2342 1.87 christos /* nothing, as TLS uses whole buffer to send */ 2343 1.87 christos lineptr = line; 2344 1.87 christos len = linelen; 2345 1.1 cgd break; 2346 1.1 cgd case F_FORW: 2347 1.87 christos lineptr = line + tlsprefixlen; 2348 1.87 christos len = linelen - tlsprefixlen; 2349 1.87 christos break; 2350 1.87 christos case F_PIPE: 2351 1.117 christos case F_FIFO: 2352 1.87 christos case F_FILE: /* fallthrough */ 2353 1.87 christos if (f->f_flags & FFLAG_FULL) { 2354 1.87 christos v->iov_base = line + tlsprefixlen; 2355 1.87 christos v->iov_len = linelen - tlsprefixlen; 2356 1.21 tron } else { 2357 1.87 christos v->iov_base = line + tlsprefixlen + prilen; 2358 1.87 christos v->iov_len = linelen - tlsprefixlen - prilen; 2359 1.87 christos } 2360 1.87 christos ADDEV(); 2361 1.87 christos v->iov_base = &crnl[1]; 2362 1.87 christos v->iov_len = 1; 2363 1.87 christos ADDEV(); 2364 1.87 christos break; 2365 1.87 christos case F_CONSOLE: 2366 1.87 christos case F_TTY: 2367 1.87 christos /* filter non-ASCII */ 2368 1.87 christos p = line; 2369 1.87 christos while (*p) { 2370 1.87 christos *p = FORCE2ASCII(*p); 2371 1.87 christos p++; 2372 1.1 cgd } 2373 1.88 christos v->iov_base = line + tlsprefixlen + prilen; 2374 1.87 christos v->iov_len = linelen - tlsprefixlen - prilen; 2375 1.87 christos ADDEV(); 2376 1.87 christos v->iov_base = crnl; 2377 1.87 christos v->iov_len = 2; 2378 1.87 christos ADDEV(); 2379 1.1 cgd break; 2380 1.87 christos case F_WALL: 2381 1.87 christos v->iov_base = greetings; 2382 1.87 christos v->iov_len = snprintf(greetings, sizeof(greetings), 2383 1.87 christos "\r\n\7Message from syslogd@%s at %s ...\r\n", 2384 1.87 christos (buffer->host ? buffer->host : buffer->recvhost), 2385 1.87 christos buffer->timestamp); 2386 1.87 christos ADDEV(); 2387 1.131 mrg /* FALLTHROUGH */ 2388 1.88 christos case F_USERS: /* fallthrough */ 2389 1.87 christos /* filter non-ASCII */ 2390 1.87 christos p = line; 2391 1.87 christos while (*p) { 2392 1.87 christos *p = FORCE2ASCII(*p); 2393 1.87 christos p++; 2394 1.87 christos } 2395 1.88 christos v->iov_base = line + tlsprefixlen + prilen; 2396 1.87 christos v->iov_len = linelen - tlsprefixlen - prilen; 2397 1.87 christos ADDEV(); 2398 1.87 christos v->iov_base = &crnl[1]; 2399 1.87 christos v->iov_len = 1; 2400 1.87 christos ADDEV(); 2401 1.87 christos break; 2402 1.87 christos } 2403 1.87 christos 2404 1.87 christos /* send */ 2405 1.87 christos switch (f->f_type) { 2406 1.87 christos case F_UNUSED: 2407 1.87 christos DPRINTF(D_MISC, "Logging to %s\n", TypeInfo[f->f_type].name); 2408 1.87 christos break; 2409 1.87 christos 2410 1.87 christos case F_FORW: 2411 1.87 christos DPRINTF(D_MISC, "Logging to %s %s\n", 2412 1.87 christos TypeInfo[f->f_type].name, f->f_un.f_forw.f_hname); 2413 1.87 christos udp_send(f, lineptr, len); 2414 1.87 christos break; 2415 1.92 minskim 2416 1.87 christos #ifndef DISABLE_TLS 2417 1.87 christos case F_TLS: 2418 1.87 christos DPRINTF(D_MISC, "Logging to %s %s\n", 2419 1.87 christos TypeInfo[f->f_type].name, 2420 1.87 christos f->f_un.f_tls.tls_conn->hostname); 2421 1.87 christos /* make sure every message gets queued once 2422 1.87 christos * it will be removed when sendmsg is sent and free()d */ 2423 1.87 christos if (!qentry) 2424 1.87 christos qentry = message_queue_add(f, NEWREF(buffer)); 2425 1.87 christos (void)tls_send(f, lineptr, len, qentry); 2426 1.87 christos break; 2427 1.87 christos #endif /* !DISABLE_TLS */ 2428 1.1 cgd 2429 1.70 thorpej case F_PIPE: 2430 1.87 christos DPRINTF(D_MISC, "Logging to %s %s\n", 2431 1.87 christos TypeInfo[f->f_type].name, f->f_un.f_pipe.f_pname); 2432 1.70 thorpej if (f->f_un.f_pipe.f_pid == 0) { 2433 1.87 christos /* (re-)open */ 2434 1.70 thorpej if ((f->f_file = p_open(f->f_un.f_pipe.f_pname, 2435 1.87 christos &f->f_un.f_pipe.f_pid)) < 0) { 2436 1.70 thorpej f->f_type = F_UNUSED; 2437 1.107 christos logerror("%s", f->f_un.f_pipe.f_pname); 2438 1.87 christos message_queue_freeall(f); 2439 1.70 thorpej break; 2440 1.87 christos } else if (!qentry) /* prevent recursion */ 2441 1.87 christos SEND_QUEUE(f); 2442 1.70 thorpej } 2443 1.75 christos if (writev(f->f_file, iov, v - iov) < 0) { 2444 1.87 christos e = errno; 2445 1.70 thorpej if (f->f_un.f_pipe.f_pid > 0) { 2446 1.70 thorpej (void) close(f->f_file); 2447 1.70 thorpej deadq_enter(f->f_un.f_pipe.f_pid, 2448 1.87 christos f->f_un.f_pipe.f_pname); 2449 1.70 thorpej } 2450 1.70 thorpej f->f_un.f_pipe.f_pid = 0; 2451 1.70 thorpej /* 2452 1.70 thorpej * If the error was EPIPE, then what is likely 2453 1.70 thorpej * has happened is we have a command that is 2454 1.70 thorpej * designed to take a single message line and 2455 1.70 thorpej * then exit, but we tried to feed it another 2456 1.70 thorpej * one before we reaped the child and thus 2457 1.70 thorpej * reset our state. 2458 1.70 thorpej * 2459 1.70 thorpej * Well, now we've reset our state, so try opening 2460 1.70 thorpej * the pipe and sending the message again if EPIPE 2461 1.70 thorpej * was the error. 2462 1.70 thorpej */ 2463 1.70 thorpej if (e == EPIPE) { 2464 1.70 thorpej if ((f->f_file = p_open(f->f_un.f_pipe.f_pname, 2465 1.70 thorpej &f->f_un.f_pipe.f_pid)) < 0) { 2466 1.70 thorpej f->f_type = F_UNUSED; 2467 1.107 christos logerror("%s", f->f_un.f_pipe.f_pname); 2468 1.87 christos message_queue_freeall(f); 2469 1.70 thorpej break; 2470 1.70 thorpej } 2471 1.75 christos if (writev(f->f_file, iov, v - iov) < 0) { 2472 1.70 thorpej e = errno; 2473 1.70 thorpej if (f->f_un.f_pipe.f_pid > 0) { 2474 1.70 thorpej (void) close(f->f_file); 2475 1.70 thorpej deadq_enter(f->f_un.f_pipe.f_pid, 2476 1.87 christos f->f_un.f_pipe.f_pname); 2477 1.70 thorpej } 2478 1.70 thorpej f->f_un.f_pipe.f_pid = 0; 2479 1.87 christos error = true; /* enqueue on return */ 2480 1.70 thorpej } else 2481 1.70 thorpej e = 0; 2482 1.70 thorpej } 2483 1.87 christos if (e != 0 && !error) { 2484 1.70 thorpej errno = e; 2485 1.101 joerg logerror("%s", f->f_un.f_pipe.f_pname); 2486 1.70 thorpej } 2487 1.70 thorpej } 2488 1.87 christos if (e == 0 && qentry) { /* sent buffered msg */ 2489 1.87 christos message_queue_remove(f, qentry); 2490 1.87 christos } 2491 1.70 thorpej break; 2492 1.70 thorpej 2493 1.1 cgd case F_CONSOLE: 2494 1.87 christos if (buffer->flags & IGN_CONS) { 2495 1.92 minskim DPRINTF(D_MISC, "Logging to %s (ignored)\n", 2496 1.87 christos TypeInfo[f->f_type].name); 2497 1.1 cgd break; 2498 1.1 cgd } 2499 1.1 cgd /* FALLTHROUGH */ 2500 1.1 cgd 2501 1.1 cgd case F_TTY: 2502 1.1 cgd case F_FILE: 2503 1.87 christos DPRINTF(D_MISC, "Logging to %s %s\n", 2504 1.87 christos TypeInfo[f->f_type].name, f->f_un.f_fname); 2505 1.1 cgd again: 2506 1.108 christos if ((f->f_type == F_FILE ? writev(f->f_file, iov, v - iov) : 2507 1.108 christos writev1(f->f_file, iov, v - iov)) < 0) { 2508 1.87 christos e = errno; 2509 1.74 matt if (f->f_type == F_FILE && e == ENOSPC) { 2510 1.74 matt int lasterror = f->f_lasterror; 2511 1.74 matt f->f_lasterror = e; 2512 1.74 matt if (lasterror != e) 2513 1.101 joerg logerror("%s", f->f_un.f_fname); 2514 1.87 christos error = true; /* enqueue on return */ 2515 1.74 matt } 2516 1.5 perry (void)close(f->f_file); 2517 1.1 cgd /* 2518 1.1 cgd * Check for errors on TTY's due to loss of tty 2519 1.1 cgd */ 2520 1.1 cgd if ((e == EIO || e == EBADF) && f->f_type != F_FILE) { 2521 1.1 cgd f->f_file = open(f->f_un.f_fname, 2522 1.112 christos O_WRONLY|O_APPEND|O_NONBLOCK, 0); 2523 1.1 cgd if (f->f_file < 0) { 2524 1.1 cgd f->f_type = F_UNUSED; 2525 1.101 joerg logerror("%s", f->f_un.f_fname); 2526 1.87 christos message_queue_freeall(f); 2527 1.1 cgd } else 2528 1.1 cgd goto again; 2529 1.1 cgd } else { 2530 1.1 cgd f->f_type = F_UNUSED; 2531 1.1 cgd errno = e; 2532 1.74 matt f->f_lasterror = e; 2533 1.101 joerg logerror("%s", f->f_un.f_fname); 2534 1.87 christos message_queue_freeall(f); 2535 1.1 cgd } 2536 1.74 matt } else { 2537 1.74 matt f->f_lasterror = 0; 2538 1.87 christos if ((buffer->flags & SYNC_FILE) 2539 1.87 christos && (f->f_flags & FFLAG_SYNC)) 2540 1.74 matt (void)fsync(f->f_file); 2541 1.87 christos /* Problem with files: We cannot check beforehand if 2542 1.87 christos * they would be writeable and call send_queue() first. 2543 1.87 christos * So we call send_queue() after a successful write, 2544 1.87 christos * which means the first message will be out of order. 2545 1.87 christos */ 2546 1.87 christos if (!qentry) /* prevent recursion */ 2547 1.87 christos SEND_QUEUE(f); 2548 1.87 christos else if (qentry) /* sent buffered msg */ 2549 1.87 christos message_queue_remove(f, qentry); 2550 1.74 matt } 2551 1.1 cgd break; 2552 1.1 cgd 2553 1.117 christos case F_FIFO: 2554 1.117 christos DPRINTF(D_MISC, "Logging to %s %s\n", 2555 1.117 christos TypeInfo[f->f_type].name, f->f_un.f_fname); 2556 1.117 christos if (f->f_file < 0) { 2557 1.117 christos f->f_file = 2558 1.117 christos open(f->f_un.f_fname, O_WRONLY|O_NONBLOCK, 0); 2559 1.117 christos e = errno; 2560 1.117 christos if (f->f_file < 0 && e == ENXIO) { 2561 1.117 christos /* Drop messages with no reader */ 2562 1.117 christos if (qentry) 2563 1.117 christos message_queue_remove(f, qentry); 2564 1.117 christos break; 2565 1.117 christos } 2566 1.117 christos } 2567 1.117 christos 2568 1.117 christos if (f->f_file >= 0 && writev(f->f_file, iov, v - iov) < 0) { 2569 1.117 christos e = errno; 2570 1.117 christos 2571 1.117 christos /* Enqueue if the fifo buffer is full */ 2572 1.117 christos if (e == EAGAIN) { 2573 1.117 christos if (f->f_lasterror != e) 2574 1.117 christos logerror("%s", f->f_un.f_fname); 2575 1.117 christos f->f_lasterror = e; 2576 1.117 christos error = true; /* enqueue on return */ 2577 1.117 christos break; 2578 1.117 christos } 2579 1.117 christos 2580 1.117 christos close(f->f_file); 2581 1.117 christos f->f_file = -1; 2582 1.117 christos 2583 1.117 christos /* Drop messages with no reader */ 2584 1.117 christos if (e == EPIPE) { 2585 1.117 christos if (qentry) 2586 1.117 christos message_queue_remove(f, qentry); 2587 1.117 christos break; 2588 1.117 christos } 2589 1.117 christos } 2590 1.117 christos 2591 1.117 christos if (f->f_file < 0) { 2592 1.117 christos f->f_type = F_UNUSED; 2593 1.117 christos errno = e; 2594 1.117 christos f->f_lasterror = e; 2595 1.117 christos logerror("%s", f->f_un.f_fname); 2596 1.117 christos message_queue_freeall(f); 2597 1.117 christos break; 2598 1.117 christos } 2599 1.117 christos 2600 1.117 christos f->f_lasterror = 0; 2601 1.117 christos if (!qentry) /* prevent recursion (see comment for F_FILE) */ 2602 1.117 christos SEND_QUEUE(f); 2603 1.117 christos if (qentry) /* sent buffered msg */ 2604 1.117 christos message_queue_remove(f, qentry); 2605 1.117 christos break; 2606 1.117 christos 2607 1.1 cgd case F_USERS: 2608 1.1 cgd case F_WALL: 2609 1.87 christos DPRINTF(D_MISC, "Logging to %s\n", TypeInfo[f->f_type].name); 2610 1.75 christos wallmsg(f, iov, v - iov); 2611 1.1 cgd break; 2612 1.1 cgd } 2613 1.1 cgd f->f_prevcount = 0; 2614 1.92 minskim 2615 1.87 christos if (error && !qentry) 2616 1.87 christos message_queue_add(f, NEWREF(buffer)); 2617 1.87 christos #ifndef DISABLE_SIGN 2618 1.87 christos if (newhash) { 2619 1.87 christos struct signature_group_t *sg; 2620 1.87 christos sg = sign_get_sg(buffer->pri, f); 2621 1.87 christos (void)sign_send_signature_block(sg, false); 2622 1.87 christos } 2623 1.87 christos #endif /* !DISABLE_SIGN */ 2624 1.87 christos /* this belongs to the ad-hoc buffer at the first if(buffer) */ 2625 1.87 christos DELREF(buffer); 2626 1.87 christos /* TLS frees on its own */ 2627 1.87 christos if (f->f_type != F_TLS) 2628 1.87 christos FREEPTR(line); 2629 1.87 christos } 2630 1.87 christos 2631 1.87 christos /* send one line by UDP */ 2632 1.87 christos void 2633 1.87 christos udp_send(struct filed *f, char *line, size_t len) 2634 1.87 christos { 2635 1.87 christos int lsent, fail, retry, j; 2636 1.87 christos struct addrinfo *r; 2637 1.87 christos 2638 1.87 christos DPRINTF((D_NET|D_CALL), "udp_send(f=%p, line=\"%s\", " 2639 1.87 christos "len=%zu) to dest.\n", f, line, len); 2640 1.87 christos 2641 1.87 christos if (!finet) 2642 1.87 christos return; 2643 1.87 christos 2644 1.87 christos lsent = -1; 2645 1.87 christos fail = 0; 2646 1.87 christos assert(f->f_type == F_FORW); 2647 1.87 christos for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) { 2648 1.87 christos retry = 0; 2649 1.87 christos for (j = 0; j < finet->fd; j++) { 2650 1.115 christos if (finet[j+1].af != r->ai_family) 2651 1.115 christos continue; 2652 1.87 christos sendagain: 2653 1.87 christos lsent = sendto(finet[j+1].fd, line, len, 0, 2654 1.87 christos r->ai_addr, r->ai_addrlen); 2655 1.87 christos if (lsent == -1) { 2656 1.87 christos switch (errno) { 2657 1.87 christos case ENOBUFS: 2658 1.87 christos /* wait/retry/drop */ 2659 1.87 christos if (++retry < 5) { 2660 1.87 christos usleep(1000); 2661 1.87 christos goto sendagain; 2662 1.87 christos } 2663 1.87 christos break; 2664 1.87 christos case EHOSTDOWN: 2665 1.87 christos case EHOSTUNREACH: 2666 1.87 christos case ENETDOWN: 2667 1.87 christos /* drop */ 2668 1.87 christos break; 2669 1.87 christos default: 2670 1.87 christos /* busted */ 2671 1.87 christos fail++; 2672 1.87 christos break; 2673 1.87 christos } 2674 1.96 lukem } else if ((size_t)lsent == len) 2675 1.87 christos break; 2676 1.87 christos } 2677 1.96 lukem if ((size_t)lsent != len && fail) { 2678 1.87 christos f->f_type = F_UNUSED; 2679 1.87 christos logerror("sendto() failed"); 2680 1.87 christos } 2681 1.87 christos } 2682 1.1 cgd } 2683 1.1 cgd 2684 1.1 cgd /* 2685 1.1 cgd * WALLMSG -- Write a message to the world at large 2686 1.1 cgd * 2687 1.1 cgd * Write the specified message to either the entire 2688 1.1 cgd * world, or a list of approved users. 2689 1.1 cgd */ 2690 1.5 perry void 2691 1.75 christos wallmsg(struct filed *f, struct iovec *iov, size_t iovcnt) 2692 1.1 cgd { 2693 1.87 christos #ifdef __NetBSD_Version__ 2694 1.1 cgd static int reenter; /* avoid calling ourselves */ 2695 1.5 perry int i; 2696 1.5 perry char *p; 2697 1.55 christos struct utmpentry *ep; 2698 1.1 cgd 2699 1.1 cgd if (reenter++) 2700 1.1 cgd return; 2701 1.55 christos 2702 1.55 christos (void)getutentries(NULL, &ep); 2703 1.1 cgd /* NOSTRICT */ 2704 1.55 christos for (; ep; ep = ep->next) { 2705 1.1 cgd if (f->f_type == F_WALL) { 2706 1.75 christos if ((p = ttymsg(iov, iovcnt, ep->line, TTYMSGTIME)) 2707 1.55 christos != NULL) { 2708 1.1 cgd errno = 0; /* already in msg */ 2709 1.101 joerg logerror("%s", p); 2710 1.1 cgd } 2711 1.1 cgd continue; 2712 1.1 cgd } 2713 1.1 cgd /* should we send the message to this user? */ 2714 1.1 cgd for (i = 0; i < MAXUNAMES; i++) { 2715 1.1 cgd if (!f->f_un.f_uname[i][0]) 2716 1.1 cgd break; 2717 1.55 christos if (strcmp(f->f_un.f_uname[i], ep->name) == 0) { 2718 1.113 christos struct stat st; 2719 1.114 christos char tty[MAXPATHLEN]; 2720 1.114 christos snprintf(tty, sizeof(tty), "%s/%s", _PATH_DEV, 2721 1.114 christos ep->line); 2722 1.114 christos if (stat(tty, &st) != -1 && 2723 1.113 christos (st.st_mode & S_IWGRP) == 0) 2724 1.113 christos break; 2725 1.113 christos 2726 1.75 christos if ((p = ttymsg(iov, iovcnt, ep->line, 2727 1.75 christos TTYMSGTIME)) != NULL) { 2728 1.1 cgd errno = 0; /* already in msg */ 2729 1.101 joerg logerror("%s", p); 2730 1.1 cgd } 2731 1.1 cgd break; 2732 1.1 cgd } 2733 1.1 cgd } 2734 1.1 cgd } 2735 1.1 cgd reenter = 0; 2736 1.87 christos #endif /* __NetBSD_Version__ */ 2737 1.1 cgd } 2738 1.1 cgd 2739 1.1 cgd void 2740 1.87 christos /*ARGSUSED*/ 2741 1.87 christos reapchild(int fd, short event, void *ev) 2742 1.64 itojun { 2743 1.70 thorpej int status; 2744 1.70 thorpej pid_t pid; 2745 1.70 thorpej struct filed *f; 2746 1.64 itojun 2747 1.70 thorpej while ((pid = wait3(&status, WNOHANG, NULL)) > 0) { 2748 1.70 thorpej if (!Initialized || ShuttingDown) { 2749 1.70 thorpej /* 2750 1.70 thorpej * Be silent while we are initializing or 2751 1.70 thorpej * shutting down. 2752 1.70 thorpej */ 2753 1.70 thorpej continue; 2754 1.70 thorpej } 2755 1.64 itojun 2756 1.70 thorpej if (deadq_remove(pid)) 2757 1.70 thorpej continue; 2758 1.1 cgd 2759 1.70 thorpej /* Now, look in the list of active processes. */ 2760 1.70 thorpej for (f = Files; f != NULL; f = f->f_next) { 2761 1.70 thorpej if (f->f_type == F_PIPE && 2762 1.70 thorpej f->f_un.f_pipe.f_pid == pid) { 2763 1.70 thorpej (void) close(f->f_file); 2764 1.70 thorpej f->f_un.f_pipe.f_pid = 0; 2765 1.70 thorpej log_deadchild(pid, status, 2766 1.87 christos f->f_un.f_pipe.f_pname); 2767 1.70 thorpej break; 2768 1.70 thorpej } 2769 1.70 thorpej } 2770 1.70 thorpej } 2771 1.1 cgd } 2772 1.1 cgd 2773 1.1 cgd /* 2774 1.87 christos * Return a printable representation of a host address (FQDN if available) 2775 1.1 cgd */ 2776 1.87 christos const char * 2777 1.53 wiz cvthname(struct sockaddr_storage *f) 2778 1.1 cgd { 2779 1.30 itojun int error; 2780 1.87 christos int niflag = NI_DGRAM; 2781 1.30 itojun static char host[NI_MAXHOST], ip[NI_MAXHOST]; 2782 1.1 cgd 2783 1.30 itojun error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len, 2784 1.87 christos ip, sizeof ip, NULL, 0, NI_NUMERICHOST|niflag); 2785 1.1 cgd 2786 1.87 christos DPRINTF(D_CALL, "cvthname(%s)\n", ip); 2787 1.30 itojun 2788 1.30 itojun if (error) { 2789 1.87 christos DPRINTF(D_NET, "Malformed from address %s\n", 2790 1.87 christos gai_strerror(error)); 2791 1.87 christos return "???"; 2792 1.1 cgd } 2793 1.45 mrg 2794 1.45 mrg if (!UseNameService) 2795 1.87 christos return ip; 2796 1.30 itojun 2797 1.30 itojun error = getnameinfo((struct sockaddr*)f, ((struct sockaddr*)f)->sa_len, 2798 1.87 christos host, sizeof host, NULL, 0, niflag); 2799 1.30 itojun if (error) { 2800 1.87 christos DPRINTF(D_NET, "Host name for your address (%s) unknown\n", ip); 2801 1.87 christos return ip; 2802 1.1 cgd } 2803 1.70 thorpej 2804 1.87 christos return host; 2805 1.1 cgd } 2806 1.1 cgd 2807 1.1 cgd void 2808 1.87 christos trim_anydomain(char *host) 2809 1.70 thorpej { 2810 1.87 christos bool onlydigits = true; 2811 1.87 christos int i; 2812 1.70 thorpej 2813 1.87 christos if (!BSDOutputFormat) 2814 1.87 christos return; 2815 1.70 thorpej 2816 1.87 christos /* if non-digits found, then assume hostname and cut at first dot (this 2817 1.92 minskim * case also covers IPv6 addresses which should not contain dots), 2818 1.87 christos * if only digits then assume IPv4 address and do not cut at all */ 2819 1.87 christos for (i = 0; host[i]; i++) { 2820 1.87 christos if (host[i] == '.' && !onlydigits) 2821 1.87 christos host[i] = '\0'; 2822 1.87 christos else if (!isdigit((unsigned char)host[i]) && host[i] != '.') 2823 1.87 christos onlydigits = false; 2824 1.87 christos } 2825 1.70 thorpej } 2826 1.70 thorpej 2827 1.87 christos static void 2828 1.87 christos /*ARGSUSED*/ 2829 1.87 christos domark(int fd, short event, void *ev) 2830 1.1 cgd { 2831 1.87 christos struct event *ev_pass = (struct event *)ev; 2832 1.5 perry struct filed *f; 2833 1.70 thorpej dq_t q, nextq; 2834 1.87 christos sigset_t newmask, omask; 2835 1.70 thorpej 2836 1.87 christos schedule_event(&ev_pass, 2837 1.87 christos &((struct timeval){TIMERINTVL, 0}), 2838 1.87 christos domark, ev_pass); 2839 1.87 christos DPRINTF((D_CALL|D_EVENT), "domark()\n"); 2840 1.1 cgd 2841 1.87 christos BLOCK_SIGNALS(omask, newmask); 2842 1.105 plunky now = time(NULL); 2843 1.1 cgd MarkSeq += TIMERINTVL; 2844 1.1 cgd if (MarkSeq >= MarkInterval) { 2845 1.87 christos logmsg_async(LOG_INFO, NULL, "-- MARK --", ADDDATE|MARK); 2846 1.1 cgd MarkSeq = 0; 2847 1.1 cgd } 2848 1.1 cgd 2849 1.1 cgd for (f = Files; f; f = f->f_next) { 2850 1.1 cgd if (f->f_prevcount && now >= REPEATTIME(f)) { 2851 1.87 christos DPRINTF(D_DATA, "Flush %s: repeated %d times, %d sec.\n", 2852 1.87 christos TypeInfo[f->f_type].name, f->f_prevcount, 2853 1.1 cgd repeatinterval[f->f_repeatcount]); 2854 1.87 christos fprintlog(f, NULL, NULL); 2855 1.1 cgd BACKOFF(f); 2856 1.1 cgd } 2857 1.1 cgd } 2858 1.87 christos message_allqueues_check(); 2859 1.87 christos RESTORE_SIGNALS(omask); 2860 1.70 thorpej 2861 1.70 thorpej /* Walk the dead queue, and see if we should signal somebody. */ 2862 1.70 thorpej for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = nextq) { 2863 1.70 thorpej nextq = TAILQ_NEXT(q, dq_entries); 2864 1.70 thorpej switch (q->dq_timeout) { 2865 1.70 thorpej case 0: 2866 1.70 thorpej /* Already signalled once, try harder now. */ 2867 1.70 thorpej if (kill(q->dq_pid, SIGKILL) != 0) 2868 1.70 thorpej (void) deadq_remove(q->dq_pid); 2869 1.70 thorpej break; 2870 1.70 thorpej 2871 1.70 thorpej case 1: 2872 1.70 thorpej /* 2873 1.70 thorpej * Timed out on the dead queue, send terminate 2874 1.70 thorpej * signal. Note that we leave the removal from 2875 1.70 thorpej * the dead queue to reapchild(), which will 2876 1.70 thorpej * also log the event (unless the process 2877 1.70 thorpej * didn't even really exist, in case we simply 2878 1.70 thorpej * drop it from the dead queue). 2879 1.70 thorpej */ 2880 1.70 thorpej if (kill(q->dq_pid, SIGTERM) != 0) { 2881 1.70 thorpej (void) deadq_remove(q->dq_pid); 2882 1.70 thorpej break; 2883 1.70 thorpej } 2884 1.70 thorpej /* FALLTHROUGH */ 2885 1.70 thorpej 2886 1.70 thorpej default: 2887 1.70 thorpej q->dq_timeout--; 2888 1.70 thorpej } 2889 1.70 thorpej } 2890 1.87 christos #ifndef DISABLE_SIGN 2891 1.87 christos if (GlobalSign.rsid) { /* check if initialized */ 2892 1.87 christos struct signature_group_t *sg; 2893 1.87 christos STAILQ_FOREACH(sg, &GlobalSign.SigGroups, entries) { 2894 1.87 christos sign_send_certificate_block(sg); 2895 1.87 christos } 2896 1.87 christos } 2897 1.87 christos #endif /* !DISABLE_SIGN */ 2898 1.1 cgd } 2899 1.1 cgd 2900 1.1 cgd /* 2901 1.1 cgd * Print syslogd errors some place. 2902 1.1 cgd */ 2903 1.5 perry void 2904 1.47 manu logerror(const char *fmt, ...) 2905 1.1 cgd { 2906 1.70 thorpej static int logerror_running; 2907 1.47 manu va_list ap; 2908 1.47 manu char tmpbuf[BUFSIZ]; 2909 1.47 manu char buf[BUFSIZ]; 2910 1.87 christos char *outbuf; 2911 1.47 manu 2912 1.70 thorpej /* If there's an error while trying to log an error, give up. */ 2913 1.70 thorpej if (logerror_running) 2914 1.70 thorpej return; 2915 1.70 thorpej logerror_running = 1; 2916 1.70 thorpej 2917 1.47 manu va_start(ap, fmt); 2918 1.47 manu (void)vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap); 2919 1.47 manu va_end(ap); 2920 1.1 cgd 2921 1.87 christos if (errno) { 2922 1.92 minskim (void)snprintf(buf, sizeof(buf), "%s: %s", 2923 1.47 manu tmpbuf, strerror(errno)); 2924 1.87 christos outbuf = buf; 2925 1.87 christos } else { 2926 1.87 christos (void)snprintf(buf, sizeof(buf), "%s", tmpbuf); 2927 1.87 christos outbuf = tmpbuf; 2928 1.87 christos } 2929 1.92 minskim 2930 1.92 minskim if (daemonized) 2931 1.87 christos logmsg_async(LOG_SYSLOG|LOG_ERR, NULL, outbuf, ADDDATE); 2932 1.47 manu if (!daemonized && Debug) 2933 1.87 christos DPRINTF(D_MISC, "%s\n", outbuf); 2934 1.47 manu if (!daemonized && !Debug) 2935 1.133 gson printf("%s: %s\n", getprogname(), outbuf); 2936 1.47 manu 2937 1.70 thorpej logerror_running = 0; 2938 1.1 cgd } 2939 1.1 cgd 2940 1.87 christos /* 2941 1.87 christos * Print syslogd info some place. 2942 1.87 christos */ 2943 1.1 cgd void 2944 1.87 christos loginfo(const char *fmt, ...) 2945 1.1 cgd { 2946 1.87 christos va_list ap; 2947 1.87 christos char buf[BUFSIZ]; 2948 1.87 christos 2949 1.87 christos va_start(ap, fmt); 2950 1.87 christos (void)vsnprintf(buf, sizeof(buf), fmt, ap); 2951 1.87 christos va_end(ap); 2952 1.87 christos 2953 1.87 christos DPRINTF(D_MISC, "%s\n", buf); 2954 1.87 christos logmsg_async(LOG_SYSLOG|LOG_INFO, NULL, buf, ADDDATE); 2955 1.87 christos } 2956 1.87 christos 2957 1.87 christos #ifndef DISABLE_TLS 2958 1.87 christos static inline void 2959 1.87 christos free_incoming_tls_sockets(void) 2960 1.87 christos { 2961 1.87 christos struct TLS_Incoming_Conn *tls_in; 2962 1.87 christos int i; 2963 1.92 minskim 2964 1.92 minskim /* 2965 1.87 christos * close all listening and connected TLS sockets 2966 1.87 christos */ 2967 1.87 christos if (TLS_Listen_Set) 2968 1.87 christos for (i = 0; i < TLS_Listen_Set->fd; i++) { 2969 1.87 christos if (close(TLS_Listen_Set[i+1].fd) == -1) 2970 1.87 christos logerror("close() failed"); 2971 1.87 christos DEL_EVENT(TLS_Listen_Set[i+1].ev); 2972 1.87 christos FREEPTR(TLS_Listen_Set[i+1].ev); 2973 1.87 christos } 2974 1.87 christos FREEPTR(TLS_Listen_Set); 2975 1.87 christos /* close/free incoming TLS connections */ 2976 1.87 christos while (!SLIST_EMPTY(&TLS_Incoming_Head)) { 2977 1.87 christos tls_in = SLIST_FIRST(&TLS_Incoming_Head); 2978 1.87 christos SLIST_REMOVE_HEAD(&TLS_Incoming_Head, entries); 2979 1.87 christos FREEPTR(tls_in->inbuf); 2980 1.87 christos free_tls_conn(tls_in->tls_conn); 2981 1.87 christos free(tls_in); 2982 1.87 christos } 2983 1.87 christos } 2984 1.87 christos #endif /* !DISABLE_TLS */ 2985 1.87 christos 2986 1.87 christos void 2987 1.87 christos /*ARGSUSED*/ 2988 1.87 christos die(int fd, short event, void *ev) 2989 1.87 christos { 2990 1.87 christos struct filed *f, *next; 2991 1.47 manu char **p; 2992 1.87 christos sigset_t newmask, omask; 2993 1.87 christos int i; 2994 1.96 lukem size_t j; 2995 1.1 cgd 2996 1.70 thorpej ShuttingDown = 1; /* Don't log SIGCHLDs. */ 2997 1.87 christos /* prevent recursive signals */ 2998 1.87 christos BLOCK_SIGNALS(omask, newmask); 2999 1.87 christos 3000 1.99 mschuett errno = 0; 3001 1.99 mschuett if (ev != NULL) 3002 1.99 mschuett logerror("Exiting on signal %d", fd); 3003 1.99 mschuett else 3004 1.99 mschuett logerror("Fatal error, exiting"); 3005 1.99 mschuett 3006 1.87 christos /* 3007 1.87 christos * flush any pending output 3008 1.87 christos */ 3009 1.1 cgd for (f = Files; f != NULL; f = f->f_next) { 3010 1.1 cgd /* flush any pending output */ 3011 1.1 cgd if (f->f_prevcount) 3012 1.87 christos fprintlog(f, NULL, NULL); 3013 1.87 christos SEND_QUEUE(f); 3014 1.87 christos } 3015 1.87 christos 3016 1.87 christos #ifndef DISABLE_TLS 3017 1.87 christos free_incoming_tls_sockets(); 3018 1.87 christos #endif /* !DISABLE_TLS */ 3019 1.87 christos #ifndef DISABLE_SIGN 3020 1.87 christos sign_global_free(); 3021 1.87 christos #endif /* !DISABLE_SIGN */ 3022 1.87 christos 3023 1.87 christos /* 3024 1.87 christos * Close all open log files. 3025 1.87 christos */ 3026 1.87 christos for (f = Files; f != NULL; f = next) { 3027 1.87 christos message_queue_freeall(f); 3028 1.87 christos 3029 1.87 christos switch (f->f_type) { 3030 1.87 christos case F_FILE: 3031 1.87 christos case F_TTY: 3032 1.87 christos case F_CONSOLE: 3033 1.117 christos case F_FIFO: 3034 1.117 christos if (f->f_file >= 0) 3035 1.117 christos (void)close(f->f_file); 3036 1.87 christos break; 3037 1.87 christos case F_PIPE: 3038 1.87 christos if (f->f_un.f_pipe.f_pid > 0) { 3039 1.87 christos (void)close(f->f_file); 3040 1.87 christos } 3041 1.70 thorpej f->f_un.f_pipe.f_pid = 0; 3042 1.87 christos break; 3043 1.87 christos case F_FORW: 3044 1.87 christos if (f->f_un.f_forw.f_addr) 3045 1.87 christos freeaddrinfo(f->f_un.f_forw.f_addr); 3046 1.87 christos break; 3047 1.87 christos #ifndef DISABLE_TLS 3048 1.87 christos case F_TLS: 3049 1.87 christos free_tls_conn(f->f_un.f_tls.tls_conn); 3050 1.87 christos break; 3051 1.87 christos #endif /* !DISABLE_TLS */ 3052 1.87 christos } 3053 1.87 christos next = f->f_next; 3054 1.87 christos DELREF(f->f_prevmsg); 3055 1.87 christos FREEPTR(f->f_program); 3056 1.87 christos FREEPTR(f->f_host); 3057 1.87 christos DEL_EVENT(f->f_sq_event); 3058 1.87 christos free((char *)f); 3059 1.87 christos } 3060 1.87 christos 3061 1.87 christos /* 3062 1.87 christos * Close all open UDP sockets 3063 1.87 christos */ 3064 1.87 christos if (finet) { 3065 1.87 christos for (i = 0; i < finet->fd; i++) { 3066 1.136 dholland (void)close(finet[i+1].fd); 3067 1.87 christos DEL_EVENT(finet[i+1].ev); 3068 1.87 christos FREEPTR(finet[i+1].ev); 3069 1.70 thorpej } 3070 1.87 christos FREEPTR(finet); 3071 1.1 cgd } 3072 1.87 christos 3073 1.87 christos /* free config options */ 3074 1.96 lukem for (j = 0; j < A_CNT(TypeInfo); j++) { 3075 1.96 lukem FREEPTR(TypeInfo[j].queue_length_string); 3076 1.96 lukem FREEPTR(TypeInfo[j].queue_size_string); 3077 1.87 christos } 3078 1.87 christos 3079 1.87 christos #ifndef DISABLE_TLS 3080 1.87 christos FREEPTR(tls_opt.CAdir); 3081 1.87 christos FREEPTR(tls_opt.CAfile); 3082 1.87 christos FREEPTR(tls_opt.keyfile); 3083 1.87 christos FREEPTR(tls_opt.certfile); 3084 1.87 christos FREEPTR(tls_opt.x509verify); 3085 1.87 christos FREEPTR(tls_opt.bindhost); 3086 1.87 christos FREEPTR(tls_opt.bindport); 3087 1.87 christos FREEPTR(tls_opt.server); 3088 1.87 christos FREEPTR(tls_opt.gen_cert); 3089 1.87 christos free_cred_SLIST(&tls_opt.cert_head); 3090 1.87 christos free_cred_SLIST(&tls_opt.fprint_head); 3091 1.87 christos FREE_SSL_CTX(tls_opt.global_TLS_CTX); 3092 1.87 christos #endif /* !DISABLE_TLS */ 3093 1.87 christos 3094 1.87 christos FREEPTR(funix); 3095 1.22 mrg for (p = LogPaths; p && *p; p++) 3096 1.22 mrg unlink(*p); 3097 1.1 cgd exit(0); 3098 1.1 cgd } 3099 1.1 cgd 3100 1.87 christos #ifndef DISABLE_SIGN 3101 1.1 cgd /* 3102 1.87 christos * get one "sign_delim_sg2" item, convert and store in ordered queue 3103 1.87 christos */ 3104 1.87 christos void 3105 1.87 christos store_sign_delim_sg2(char *tmp_buf) 3106 1.87 christos { 3107 1.87 christos struct string_queue *sqentry, *sqe1, *sqe2; 3108 1.87 christos 3109 1.87 christos if(!(sqentry = malloc(sizeof(*sqentry)))) { 3110 1.87 christos logerror("Unable to allocate memory"); 3111 1.87 christos return; 3112 1.87 christos } 3113 1.87 christos /*LINTED constcond/null effect */ 3114 1.87 christos assert(sizeof(int64_t) == sizeof(uint_fast64_t)); 3115 1.87 christos if (dehumanize_number(tmp_buf, (int64_t*) &(sqentry->key)) == -1 3116 1.87 christos || sqentry->key > (LOG_NFACILITIES<<3)) { 3117 1.87 christos DPRINTF(D_PARSE, "invalid sign_delim_sg2: %s\n", tmp_buf); 3118 1.87 christos free(sqentry); 3119 1.87 christos FREEPTR(tmp_buf); 3120 1.87 christos return; 3121 1.87 christos } 3122 1.87 christos sqentry->data = tmp_buf; 3123 1.92 minskim 3124 1.87 christos if (STAILQ_EMPTY(&GlobalSign.sig2_delims)) { 3125 1.87 christos STAILQ_INSERT_HEAD(&GlobalSign.sig2_delims, 3126 1.87 christos sqentry, entries); 3127 1.87 christos return; 3128 1.87 christos } 3129 1.87 christos 3130 1.87 christos /* keep delimiters sorted */ 3131 1.87 christos sqe1 = sqe2 = STAILQ_FIRST(&GlobalSign.sig2_delims); 3132 1.87 christos if (sqe1->key > sqentry->key) { 3133 1.87 christos STAILQ_INSERT_HEAD(&GlobalSign.sig2_delims, 3134 1.87 christos sqentry, entries); 3135 1.87 christos return; 3136 1.87 christos } 3137 1.92 minskim 3138 1.87 christos while ((sqe1 = sqe2) 3139 1.87 christos && (sqe2 = STAILQ_NEXT(sqe1, entries))) { 3140 1.87 christos if (sqe2->key > sqentry->key) { 3141 1.87 christos break; 3142 1.87 christos } else if (sqe2->key == sqentry->key) { 3143 1.87 christos DPRINTF(D_PARSE, "duplicate sign_delim_sg2: %s\n", 3144 1.87 christos tmp_buf); 3145 1.92 minskim FREEPTR(sqentry); 3146 1.87 christos FREEPTR(tmp_buf); 3147 1.87 christos return; 3148 1.87 christos } 3149 1.87 christos } 3150 1.87 christos STAILQ_INSERT_AFTER(&GlobalSign.sig2_delims, sqe1, sqentry, entries); 3151 1.87 christos } 3152 1.87 christos #endif /* !DISABLE_SIGN */ 3153 1.87 christos 3154 1.87 christos /* 3155 1.87 christos * read syslog.conf 3156 1.1 cgd */ 3157 1.1 cgd void 3158 1.87 christos read_config_file(FILE *cf, struct filed **f_ptr) 3159 1.1 cgd { 3160 1.87 christos size_t linenum = 0; 3161 1.82 christos size_t i; 3162 1.87 christos struct filed *f, **nextp; 3163 1.5 perry char cline[LINE_MAX]; 3164 1.70 thorpej char prog[NAME_MAX + 1]; 3165 1.70 thorpej char host[MAXHOSTNAMELEN]; 3166 1.87 christos const char *p; 3167 1.87 christos char *q; 3168 1.87 christos bool found_keyword; 3169 1.87 christos #ifndef DISABLE_TLS 3170 1.87 christos struct peer_cred *cred = NULL; 3171 1.87 christos struct peer_cred_head *credhead = NULL; 3172 1.87 christos #endif /* !DISABLE_TLS */ 3173 1.87 christos #ifndef DISABLE_SIGN 3174 1.87 christos char *sign_sg_str = NULL; 3175 1.87 christos #endif /* !DISABLE_SIGN */ 3176 1.87 christos #if (!defined(DISABLE_TLS) || !defined(DISABLE_SIGN)) 3177 1.87 christos char *tmp_buf = NULL; 3178 1.87 christos #endif /* (!defined(DISABLE_TLS) || !defined(DISABLE_SIGN)) */ 3179 1.87 christos /* central list of recognized configuration keywords 3180 1.87 christos * and an address for their values as strings */ 3181 1.87 christos const struct config_keywords { 3182 1.87 christos const char *keyword; 3183 1.87 christos char **variable; 3184 1.87 christos } config_keywords[] = { 3185 1.87 christos #ifndef DISABLE_TLS 3186 1.87 christos /* TLS settings */ 3187 1.87 christos {"tls_ca", &tls_opt.CAfile}, 3188 1.87 christos {"tls_cadir", &tls_opt.CAdir}, 3189 1.87 christos {"tls_cert", &tls_opt.certfile}, 3190 1.87 christos {"tls_key", &tls_opt.keyfile}, 3191 1.87 christos {"tls_verify", &tls_opt.x509verify}, 3192 1.87 christos {"tls_bindport", &tls_opt.bindport}, 3193 1.87 christos {"tls_bindhost", &tls_opt.bindhost}, 3194 1.87 christos {"tls_server", &tls_opt.server}, 3195 1.87 christos {"tls_gen_cert", &tls_opt.gen_cert}, 3196 1.87 christos /* special cases in parsing */ 3197 1.87 christos {"tls_allow_fingerprints",&tmp_buf}, 3198 1.87 christos {"tls_allow_clientcerts", &tmp_buf}, 3199 1.87 christos /* buffer settings */ 3200 1.87 christos {"tls_queue_length", &TypeInfo[F_TLS].queue_length_string}, 3201 1.87 christos {"tls_queue_size", &TypeInfo[F_TLS].queue_size_string}, 3202 1.87 christos #endif /* !DISABLE_TLS */ 3203 1.87 christos {"file_queue_length", &TypeInfo[F_FILE].queue_length_string}, 3204 1.87 christos {"pipe_queue_length", &TypeInfo[F_PIPE].queue_length_string}, 3205 1.117 christos {"fifo_queue_length", &TypeInfo[F_FIFO].queue_length_string}, 3206 1.87 christos {"file_queue_size", &TypeInfo[F_FILE].queue_size_string}, 3207 1.87 christos {"pipe_queue_size", &TypeInfo[F_PIPE].queue_size_string}, 3208 1.117 christos {"fifo_queue_size", &TypeInfo[F_FIFO].queue_size_string}, 3209 1.87 christos #ifndef DISABLE_SIGN 3210 1.87 christos /* syslog-sign setting */ 3211 1.87 christos {"sign_sg", &sign_sg_str}, 3212 1.87 christos /* also special case in parsing */ 3213 1.87 christos {"sign_delim_sg2", &tmp_buf}, 3214 1.87 christos #endif /* !DISABLE_SIGN */ 3215 1.87 christos }; 3216 1.87 christos 3217 1.87 christos DPRINTF(D_CALL, "read_config_file()\n"); 3218 1.87 christos 3219 1.87 christos /* free all previous config options */ 3220 1.87 christos for (i = 0; i < A_CNT(TypeInfo); i++) { 3221 1.87 christos if (TypeInfo[i].queue_length_string 3222 1.87 christos && TypeInfo[i].queue_length_string 3223 1.87 christos != TypeInfo[i].default_length_string) { 3224 1.87 christos FREEPTR(TypeInfo[i].queue_length_string); 3225 1.87 christos TypeInfo[i].queue_length_string = 3226 1.87 christos strdup(TypeInfo[i].default_length_string); 3227 1.87 christos } 3228 1.87 christos if (TypeInfo[i].queue_size_string 3229 1.87 christos && TypeInfo[i].queue_size_string 3230 1.87 christos != TypeInfo[i].default_size_string) { 3231 1.87 christos FREEPTR(TypeInfo[i].queue_size_string); 3232 1.87 christos TypeInfo[i].queue_size_string = 3233 1.87 christos strdup(TypeInfo[i].default_size_string); 3234 1.87 christos } 3235 1.87 christos } 3236 1.87 christos for (i = 0; i < A_CNT(config_keywords); i++) 3237 1.87 christos FREEPTR(*config_keywords[i].variable); 3238 1.92 minskim /* 3239 1.87 christos * global settings 3240 1.87 christos */ 3241 1.87 christos while (fgets(cline, sizeof(cline), cf) != NULL) { 3242 1.87 christos linenum++; 3243 1.87 christos for (p = cline; isspace((unsigned char)*p); ++p) 3244 1.87 christos continue; 3245 1.87 christos if ((*p == '\0') || (*p == '#')) 3246 1.87 christos continue; 3247 1.1 cgd 3248 1.87 christos for (i = 0; i < A_CNT(config_keywords); i++) { 3249 1.87 christos if (copy_config_value(config_keywords[i].keyword, 3250 1.87 christos config_keywords[i].variable, &p, ConfFile, 3251 1.87 christos linenum)) { 3252 1.87 christos DPRINTF((D_PARSE|D_MEM), 3253 1.87 christos "found option %s, saved @%p\n", 3254 1.87 christos config_keywords[i].keyword, 3255 1.87 christos *config_keywords[i].variable); 3256 1.87 christos #ifndef DISABLE_SIGN 3257 1.87 christos if (!strcmp("sign_delim_sg2", 3258 1.87 christos config_keywords[i].keyword)) 3259 1.87 christos do { 3260 1.87 christos store_sign_delim_sg2(tmp_buf); 3261 1.87 christos } while (copy_config_value_word( 3262 1.87 christos &tmp_buf, &p)); 3263 1.92 minskim 3264 1.87 christos #endif /* !DISABLE_SIGN */ 3265 1.87 christos 3266 1.87 christos #ifndef DISABLE_TLS 3267 1.87 christos /* special cases with multiple parameters */ 3268 1.87 christos if (!strcmp("tls_allow_fingerprints", 3269 1.87 christos config_keywords[i].keyword)) 3270 1.87 christos credhead = &tls_opt.fprint_head; 3271 1.87 christos else if (!strcmp("tls_allow_clientcerts", 3272 1.87 christos config_keywords[i].keyword)) 3273 1.87 christos credhead = &tls_opt.cert_head; 3274 1.87 christos 3275 1.87 christos if (credhead) do { 3276 1.87 christos if(!(cred = malloc(sizeof(*cred)))) { 3277 1.87 christos logerror("Unable to " 3278 1.87 christos "allocate memory"); 3279 1.87 christos break; 3280 1.87 christos } 3281 1.87 christos cred->data = tmp_buf; 3282 1.87 christos tmp_buf = NULL; 3283 1.87 christos SLIST_INSERT_HEAD(credhead, 3284 1.87 christos cred, entries); 3285 1.87 christos } while /* additional values? */ 3286 1.87 christos (copy_config_value_word(&tmp_buf, &p)); 3287 1.87 christos credhead = NULL; 3288 1.87 christos break; 3289 1.87 christos #endif /* !DISABLE_TLS */ 3290 1.87 christos } 3291 1.87 christos } 3292 1.87 christos } 3293 1.87 christos /* convert strings to integer values */ 3294 1.87 christos for (i = 0; i < A_CNT(TypeInfo); i++) { 3295 1.87 christos if (!TypeInfo[i].queue_length_string 3296 1.87 christos || dehumanize_number(TypeInfo[i].queue_length_string, 3297 1.87 christos &TypeInfo[i].queue_length) == -1) 3298 1.119 christos if (dehumanize_number(TypeInfo[i].default_length_string, 3299 1.119 christos &TypeInfo[i].queue_length) == -1) 3300 1.119 christos abort(); 3301 1.87 christos if (!TypeInfo[i].queue_size_string 3302 1.87 christos || dehumanize_number(TypeInfo[i].queue_size_string, 3303 1.87 christos &TypeInfo[i].queue_size) == -1) 3304 1.119 christos if (dehumanize_number(TypeInfo[i].default_size_string, 3305 1.119 christos &TypeInfo[i].queue_size) == -1) 3306 1.119 christos abort(); 3307 1.87 christos } 3308 1.87 christos 3309 1.87 christos #ifndef DISABLE_SIGN 3310 1.87 christos if (sign_sg_str) { 3311 1.87 christos if (sign_sg_str[1] == '\0' 3312 1.87 christos && (sign_sg_str[0] == '0' || sign_sg_str[0] == '1' 3313 1.87 christos || sign_sg_str[0] == '2' || sign_sg_str[0] == '3')) 3314 1.87 christos GlobalSign.sg = sign_sg_str[0] - '0'; 3315 1.87 christos else { 3316 1.87 christos GlobalSign.sg = SIGN_SG; 3317 1.87 christos DPRINTF(D_MISC, "Invalid sign_sg value `%s', " 3318 1.87 christos "use default value `%d'\n", 3319 1.87 christos sign_sg_str, GlobalSign.sg); 3320 1.87 christos } 3321 1.87 christos } else /* disable syslog-sign */ 3322 1.87 christos GlobalSign.sg = -1; 3323 1.87 christos #endif /* !DISABLE_SIGN */ 3324 1.1 cgd 3325 1.87 christos rewind(cf); 3326 1.87 christos linenum = 0; 3327 1.87 christos /* 3328 1.87 christos * Foreach line in the conf table, open that file. 3329 1.87 christos */ 3330 1.87 christos f = NULL; 3331 1.87 christos nextp = &f; 3332 1.87 christos 3333 1.87 christos strcpy(prog, "*"); 3334 1.87 christos strcpy(host, "*"); 3335 1.87 christos while (fgets(cline, sizeof(cline), cf) != NULL) { 3336 1.87 christos linenum++; 3337 1.87 christos found_keyword = false; 3338 1.87 christos /* 3339 1.87 christos * check for end-of-section, comments, strip off trailing 3340 1.87 christos * spaces and newline character. #!prog is treated specially: 3341 1.87 christos * following lines apply only to that program. 3342 1.87 christos */ 3343 1.87 christos for (p = cline; isspace((unsigned char)*p); ++p) 3344 1.87 christos continue; 3345 1.87 christos if (*p == '\0') 3346 1.87 christos continue; 3347 1.87 christos if (*p == '#') { 3348 1.87 christos p++; 3349 1.87 christos if (*p != '!' && *p != '+' && *p != '-') 3350 1.87 christos continue; 3351 1.87 christos } 3352 1.87 christos 3353 1.87 christos for (i = 0; i < A_CNT(config_keywords); i++) { 3354 1.87 christos if (!strncasecmp(p, config_keywords[i].keyword, 3355 1.87 christos strlen(config_keywords[i].keyword))) { 3356 1.87 christos DPRINTF(D_PARSE, 3357 1.87 christos "skip cline %zu with keyword %s\n", 3358 1.87 christos linenum, config_keywords[i].keyword); 3359 1.87 christos found_keyword = true; 3360 1.87 christos } 3361 1.87 christos } 3362 1.87 christos if (found_keyword) 3363 1.87 christos continue; 3364 1.87 christos 3365 1.87 christos if (*p == '+' || *p == '-') { 3366 1.87 christos host[0] = *p++; 3367 1.87 christos while (isspace((unsigned char)*p)) 3368 1.87 christos p++; 3369 1.87 christos if (*p == '\0' || *p == '*') { 3370 1.87 christos strcpy(host, "*"); 3371 1.87 christos continue; 3372 1.87 christos } 3373 1.87 christos /* the +hostname expression will continue 3374 1.87 christos * to use the LocalHostName, not the FQDN */ 3375 1.87 christos for (i = 1; i < MAXHOSTNAMELEN - 1; i++) { 3376 1.87 christos if (*p == '@') { 3377 1.87 christos (void)strncpy(&host[i], LocalHostName, 3378 1.87 christos sizeof(host) - 1 - i); 3379 1.87 christos host[sizeof(host) - 1] = '\0'; 3380 1.87 christos i = strlen(host) - 1; 3381 1.87 christos p++; 3382 1.87 christos continue; 3383 1.87 christos } 3384 1.87 christos if (!isalnum((unsigned char)*p) && 3385 1.87 christos *p != '.' && *p != '-' && *p != ',') 3386 1.87 christos break; 3387 1.87 christos host[i] = *p++; 3388 1.87 christos } 3389 1.87 christos host[i] = '\0'; 3390 1.87 christos continue; 3391 1.87 christos } 3392 1.87 christos if (*p == '!') { 3393 1.87 christos p++; 3394 1.87 christos while (isspace((unsigned char)*p)) 3395 1.87 christos p++; 3396 1.87 christos if (*p == '\0' || *p == '*') { 3397 1.87 christos strcpy(prog, "*"); 3398 1.87 christos continue; 3399 1.87 christos } 3400 1.87 christos for (i = 0; i < NAME_MAX; i++) { 3401 1.87 christos if (!isprint((unsigned char)p[i])) 3402 1.87 christos break; 3403 1.87 christos prog[i] = p[i]; 3404 1.87 christos } 3405 1.87 christos prog[i] = '\0'; 3406 1.87 christos continue; 3407 1.87 christos } 3408 1.87 christos for (q = strchr(cline, '\0'); isspace((unsigned char)*--q);) 3409 1.87 christos continue; 3410 1.87 christos *++q = '\0'; 3411 1.87 christos if ((f = calloc(1, sizeof(*f))) == NULL) { 3412 1.87 christos logerror("alloc failed"); 3413 1.87 christos die(0, 0, NULL); 3414 1.87 christos } 3415 1.87 christos if (!*f_ptr) *f_ptr = f; /* return first node */ 3416 1.87 christos *nextp = f; 3417 1.87 christos nextp = &f->f_next; 3418 1.87 christos cfline(linenum, cline, f, prog, host); 3419 1.87 christos } 3420 1.87 christos } 3421 1.87 christos 3422 1.87 christos /* 3423 1.87 christos * INIT -- Initialize syslogd from configuration table 3424 1.87 christos */ 3425 1.87 christos void 3426 1.87 christos /*ARGSUSED*/ 3427 1.87 christos init(int fd, short event, void *ev) 3428 1.87 christos { 3429 1.87 christos FILE *cf; 3430 1.96 lukem int i; 3431 1.87 christos struct filed *f, *newf, **nextp, *f2; 3432 1.87 christos char *p; 3433 1.87 christos sigset_t newmask, omask; 3434 1.100 riz #ifndef DISABLE_TLS 3435 1.87 christos char *tls_status_msg = NULL; 3436 1.87 christos struct peer_cred *cred = NULL; 3437 1.87 christos #endif /* !DISABLE_TLS */ 3438 1.87 christos 3439 1.87 christos /* prevent recursive signals */ 3440 1.87 christos BLOCK_SIGNALS(omask, newmask); 3441 1.92 minskim 3442 1.87 christos DPRINTF((D_EVENT|D_CALL), "init\n"); 3443 1.87 christos 3444 1.92 minskim /* 3445 1.87 christos * be careful about dependencies and order of actions: 3446 1.87 christos * 1. flush buffer queues 3447 1.87 christos * 2. flush -sign SBs 3448 1.87 christos * 3. flush/delete buffer queue again, in case an SB got there 3449 1.87 christos * 4. close files/connections 3450 1.87 christos */ 3451 1.70 thorpej 3452 1.1 cgd /* 3453 1.87 christos * flush any pending output 3454 1.1 cgd */ 3455 1.87 christos for (f = Files; f != NULL; f = f->f_next) { 3456 1.1 cgd /* flush any pending output */ 3457 1.1 cgd if (f->f_prevcount) 3458 1.87 christos fprintlog(f, NULL, NULL); 3459 1.87 christos SEND_QUEUE(f); 3460 1.87 christos } 3461 1.87 christos /* some actions only on SIGHUP and not on first start */ 3462 1.87 christos if (Initialized) { 3463 1.87 christos #ifndef DISABLE_SIGN 3464 1.87 christos sign_global_free(); 3465 1.87 christos #endif /* !DISABLE_SIGN */ 3466 1.87 christos #ifndef DISABLE_TLS 3467 1.87 christos free_incoming_tls_sockets(); 3468 1.87 christos #endif /* !DISABLE_TLS */ 3469 1.87 christos Initialized = 0; 3470 1.87 christos } 3471 1.87 christos /* 3472 1.87 christos * Close all open log files. 3473 1.87 christos */ 3474 1.87 christos for (f = Files; f != NULL; f = f->f_next) { 3475 1.1 cgd switch (f->f_type) { 3476 1.5 perry case F_FILE: 3477 1.5 perry case F_TTY: 3478 1.5 perry case F_CONSOLE: 3479 1.5 perry (void)close(f->f_file); 3480 1.44 itojun break; 3481 1.70 thorpej case F_PIPE: 3482 1.70 thorpej if (f->f_un.f_pipe.f_pid > 0) { 3483 1.70 thorpej (void)close(f->f_file); 3484 1.70 thorpej deadq_enter(f->f_un.f_pipe.f_pid, 3485 1.87 christos f->f_un.f_pipe.f_pname); 3486 1.70 thorpej } 3487 1.70 thorpej f->f_un.f_pipe.f_pid = 0; 3488 1.70 thorpej break; 3489 1.44 itojun case F_FORW: 3490 1.44 itojun if (f->f_un.f_forw.f_addr) 3491 1.44 itojun freeaddrinfo(f->f_un.f_forw.f_addr); 3492 1.1 cgd break; 3493 1.87 christos #ifndef DISABLE_TLS 3494 1.87 christos case F_TLS: 3495 1.87 christos free_tls_sslptr(f->f_un.f_tls.tls_conn); 3496 1.87 christos break; 3497 1.87 christos #endif /* !DISABLE_TLS */ 3498 1.1 cgd } 3499 1.1 cgd } 3500 1.92 minskim 3501 1.38 jwise /* 3502 1.87 christos * Close all open UDP sockets 3503 1.38 jwise */ 3504 1.38 jwise if (finet) { 3505 1.87 christos for (i = 0; i < finet->fd; i++) { 3506 1.87 christos if (close(finet[i+1].fd) < 0) { 3507 1.47 manu logerror("close() failed"); 3508 1.87 christos die(0, 0, NULL); 3509 1.38 jwise } 3510 1.87 christos DEL_EVENT(finet[i+1].ev); 3511 1.87 christos FREEPTR(finet[i+1].ev); 3512 1.38 jwise } 3513 1.87 christos FREEPTR(finet); 3514 1.38 jwise } 3515 1.39 jwise 3516 1.87 christos /* get FQDN and hostname/domain */ 3517 1.87 christos FREEPTR(oldLocalFQDN); 3518 1.87 christos oldLocalFQDN = LocalFQDN; 3519 1.87 christos LocalFQDN = getLocalFQDN(); 3520 1.87 christos if ((p = strchr(LocalFQDN, '.')) != NULL) 3521 1.87 christos (void)strlcpy(LocalHostName, LocalFQDN, 1+p-LocalFQDN); 3522 1.87 christos else 3523 1.87 christos (void)strlcpy(LocalHostName, LocalFQDN, sizeof(LocalHostName)); 3524 1.87 christos 3525 1.39 jwise /* 3526 1.39 jwise * Reset counter of forwarding actions 3527 1.39 jwise */ 3528 1.39 jwise 3529 1.39 jwise NumForwards=0; 3530 1.92 minskim 3531 1.87 christos /* new destination list to replace Files */ 3532 1.87 christos newf = NULL; 3533 1.87 christos nextp = &newf; 3534 1.38 jwise 3535 1.1 cgd /* open the configuration file */ 3536 1.1 cgd if ((cf = fopen(ConfFile, "r")) == NULL) { 3537 1.87 christos DPRINTF(D_FILE, "Cannot open `%s'\n", ConfFile); 3538 1.1 cgd *nextp = (struct filed *)calloc(1, sizeof(*f)); 3539 1.87 christos cfline(0, "*.ERR\t/dev/console", *nextp, "*", "*"); 3540 1.1 cgd (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); 3541 1.87 christos cfline(0, "*.PANIC\t*", (*nextp)->f_next, "*", "*"); 3542 1.1 cgd Initialized = 1; 3543 1.87 christos RESTORE_SIGNALS(omask); 3544 1.1 cgd return; 3545 1.1 cgd } 3546 1.1 cgd 3547 1.87 christos #ifndef DISABLE_TLS 3548 1.87 christos /* init with new TLS_CTX 3549 1.87 christos * as far as I see one cannot change the cert/key of an existing CTX 3550 1.1 cgd */ 3551 1.87 christos FREE_SSL_CTX(tls_opt.global_TLS_CTX); 3552 1.1 cgd 3553 1.87 christos free_cred_SLIST(&tls_opt.cert_head); 3554 1.87 christos free_cred_SLIST(&tls_opt.fprint_head); 3555 1.87 christos #endif /* !DISABLE_TLS */ 3556 1.87 christos 3557 1.87 christos /* read and close configuration file */ 3558 1.87 christos read_config_file(cf, &newf); 3559 1.87 christos newf = *nextp; 3560 1.5 perry (void)fclose(cf); 3561 1.87 christos DPRINTF(D_MISC, "read_config_file() returned newf=%p\n", newf); 3562 1.1 cgd 3563 1.87 christos #define MOVE_QUEUE(dst, src) do { \ 3564 1.87 christos struct buf_queue *buf; \ 3565 1.87 christos STAILQ_CONCAT(&dst->f_qhead, &src->f_qhead); \ 3566 1.87 christos STAILQ_FOREACH(buf, &dst->f_qhead, entries) { \ 3567 1.87 christos dst->f_qelements++; \ 3568 1.87 christos dst->f_qsize += buf_queue_obj_size(buf); \ 3569 1.87 christos } \ 3570 1.87 christos src->f_qsize = 0; \ 3571 1.87 christos src->f_qelements = 0; \ 3572 1.138 rillig } while (0) 3573 1.87 christos 3574 1.87 christos /* 3575 1.87 christos * Free old log files. 3576 1.87 christos */ 3577 1.98 mschuett for (f = Files; f != NULL;) { 3578 1.98 mschuett struct filed *ftmp; 3579 1.98 mschuett 3580 1.87 christos /* check if a new logfile is equal, if so pass the queue */ 3581 1.87 christos for (f2 = newf; f2 != NULL; f2 = f2->f_next) { 3582 1.87 christos if (f->f_type == f2->f_type 3583 1.92 minskim && ((f->f_type == F_PIPE 3584 1.87 christos && !strcmp(f->f_un.f_pipe.f_pname, 3585 1.87 christos f2->f_un.f_pipe.f_pname)) 3586 1.87 christos #ifndef DISABLE_TLS 3587 1.92 minskim || (f->f_type == F_TLS 3588 1.87 christos && !strcmp(f->f_un.f_tls.tls_conn->hostname, 3589 1.87 christos f2->f_un.f_tls.tls_conn->hostname) 3590 1.87 christos && !strcmp(f->f_un.f_tls.tls_conn->port, 3591 1.87 christos f2->f_un.f_tls.tls_conn->port)) 3592 1.87 christos #endif /* !DISABLE_TLS */ 3593 1.87 christos || (f->f_type == F_FORW 3594 1.87 christos && !strcmp(f->f_un.f_forw.f_hname, 3595 1.87 christos f2->f_un.f_forw.f_hname)))) { 3596 1.87 christos DPRINTF(D_BUFFER, "move queue from f@%p " 3597 1.87 christos "to f2@%p\n", f, f2); 3598 1.87 christos MOVE_QUEUE(f2, f); 3599 1.87 christos } 3600 1.87 christos } 3601 1.87 christos message_queue_freeall(f); 3602 1.87 christos DELREF(f->f_prevmsg); 3603 1.87 christos #ifndef DISABLE_TLS 3604 1.87 christos if (f->f_type == F_TLS) 3605 1.87 christos free_tls_conn(f->f_un.f_tls.tls_conn); 3606 1.87 christos #endif /* !DISABLE_TLS */ 3607 1.87 christos FREEPTR(f->f_program); 3608 1.87 christos FREEPTR(f->f_host); 3609 1.87 christos DEL_EVENT(f->f_sq_event); 3610 1.98 mschuett 3611 1.98 mschuett ftmp = f->f_next; 3612 1.87 christos free((char *)f); 3613 1.98 mschuett f = ftmp; 3614 1.87 christos } 3615 1.87 christos Files = newf; 3616 1.1 cgd Initialized = 1; 3617 1.1 cgd 3618 1.1 cgd if (Debug) { 3619 1.1 cgd for (f = Files; f; f = f->f_next) { 3620 1.1 cgd for (i = 0; i <= LOG_NFACILITIES; i++) 3621 1.1 cgd if (f->f_pmask[i] == INTERNAL_NOPRI) 3622 1.1 cgd printf("X "); 3623 1.1 cgd else 3624 1.1 cgd printf("%d ", f->f_pmask[i]); 3625 1.87 christos printf("%s: ", TypeInfo[f->f_type].name); 3626 1.1 cgd switch (f->f_type) { 3627 1.1 cgd case F_FILE: 3628 1.1 cgd case F_TTY: 3629 1.1 cgd case F_CONSOLE: 3630 1.117 christos case F_FIFO: 3631 1.1 cgd printf("%s", f->f_un.f_fname); 3632 1.1 cgd break; 3633 1.1 cgd 3634 1.1 cgd case F_FORW: 3635 1.1 cgd printf("%s", f->f_un.f_forw.f_hname); 3636 1.1 cgd break; 3637 1.87 christos #ifndef DISABLE_TLS 3638 1.87 christos case F_TLS: 3639 1.87 christos printf("[%s]", f->f_un.f_tls.tls_conn->hostname); 3640 1.87 christos break; 3641 1.87 christos #endif /* !DISABLE_TLS */ 3642 1.70 thorpej case F_PIPE: 3643 1.70 thorpej printf("%s", f->f_un.f_pipe.f_pname); 3644 1.70 thorpej break; 3645 1.70 thorpej 3646 1.1 cgd case F_USERS: 3647 1.34 lukem for (i = 0; 3648 1.34 lukem i < MAXUNAMES && *f->f_un.f_uname[i]; i++) 3649 1.1 cgd printf("%s, ", f->f_un.f_uname[i]); 3650 1.1 cgd break; 3651 1.1 cgd } 3652 1.70 thorpej if (f->f_program != NULL) 3653 1.70 thorpej printf(" (%s)", f->f_program); 3654 1.1 cgd printf("\n"); 3655 1.1 cgd } 3656 1.38 jwise } 3657 1.38 jwise 3658 1.79 christos finet = socksetup(PF_UNSPEC, bindhostname); 3659 1.38 jwise if (finet) { 3660 1.38 jwise if (SecureMode) { 3661 1.87 christos for (i = 0; i < finet->fd; i++) { 3662 1.87 christos if (shutdown(finet[i+1].fd, SHUT_RD) < 0) { 3663 1.47 manu logerror("shutdown() failed"); 3664 1.87 christos die(0, 0, NULL); 3665 1.38 jwise } 3666 1.38 jwise } 3667 1.38 jwise } else 3668 1.87 christos DPRINTF(D_NET, "Listening on inet and/or inet6 socket\n"); 3669 1.87 christos DPRINTF(D_NET, "Sending on inet and/or inet6 socket\n"); 3670 1.87 christos } 3671 1.87 christos 3672 1.87 christos #ifndef DISABLE_TLS 3673 1.87 christos /* TLS setup -- after all local destinations opened */ 3674 1.87 christos DPRINTF(D_PARSE, "Parsed options: tls_ca: %s, tls_cadir: %s, " 3675 1.87 christos "tls_cert: %s, tls_key: %s, tls_verify: %s, " 3676 1.87 christos "bind: %s:%s, max. queue_lengths: %" 3677 1.87 christos PRId64 ", %" PRId64 ", %" PRId64 ", " 3678 1.87 christos "max. queue_sizes: %" 3679 1.87 christos PRId64 ", %" PRId64 ", %" PRId64 "\n", 3680 1.87 christos tls_opt.CAfile, tls_opt.CAdir, 3681 1.87 christos tls_opt.certfile, tls_opt.keyfile, tls_opt.x509verify, 3682 1.87 christos tls_opt.bindhost, tls_opt.bindport, 3683 1.87 christos TypeInfo[F_TLS].queue_length, TypeInfo[F_FILE].queue_length, 3684 1.87 christos TypeInfo[F_PIPE].queue_length, 3685 1.87 christos TypeInfo[F_TLS].queue_size, TypeInfo[F_FILE].queue_size, 3686 1.87 christos TypeInfo[F_PIPE].queue_size); 3687 1.87 christos SLIST_FOREACH(cred, &tls_opt.cert_head, entries) { 3688 1.87 christos DPRINTF(D_PARSE, "Accepting peer certificate " 3689 1.87 christos "from file: \"%s\"\n", cred->data); 3690 1.87 christos } 3691 1.87 christos SLIST_FOREACH(cred, &tls_opt.fprint_head, entries) { 3692 1.87 christos DPRINTF(D_PARSE, "Accepting peer certificate with " 3693 1.87 christos "fingerprint: \"%s\"\n", cred->data); 3694 1.87 christos } 3695 1.87 christos 3696 1.87 christos /* Note: The order of initialization is important because syslog-sign 3697 1.87 christos * should use the TLS cert for signing. -- So we check first if TLS 3698 1.87 christos * will be used and initialize it before starting -sign. 3699 1.92 minskim * 3700 1.87 christos * This means that if we are a client without TLS destinations TLS 3701 1.87 christos * will not be initialized and syslog-sign will generate a new key. 3702 1.87 christos * -- Even if the user has set a usable tls_cert. 3703 1.87 christos * Is this the expected behaviour? The alternative would be to always 3704 1.87 christos * initialize the TLS structures, even if they will not be needed 3705 1.87 christos * (or only needed to read the DSA key for -sign). 3706 1.87 christos */ 3707 1.87 christos 3708 1.92 minskim /* Initialize TLS only if used */ 3709 1.87 christos if (tls_opt.server) 3710 1.87 christos tls_status_msg = init_global_TLS_CTX(); 3711 1.92 minskim else 3712 1.87 christos for (f = Files; f; f = f->f_next) { 3713 1.87 christos if (f->f_type != F_TLS) 3714 1.87 christos continue; 3715 1.87 christos tls_status_msg = init_global_TLS_CTX(); 3716 1.87 christos break; 3717 1.87 christos } 3718 1.87 christos 3719 1.87 christos #endif /* !DISABLE_TLS */ 3720 1.87 christos 3721 1.87 christos #ifndef DISABLE_SIGN 3722 1.87 christos /* only initialize -sign if actually used */ 3723 1.87 christos if (GlobalSign.sg == 0 || GlobalSign.sg == 1 || GlobalSign.sg == 2) 3724 1.87 christos (void)sign_global_init(Files); 3725 1.87 christos else if (GlobalSign.sg == 3) 3726 1.87 christos for (f = Files; f; f = f->f_next) 3727 1.87 christos if (f->f_flags & FFLAG_SIGN) { 3728 1.87 christos (void)sign_global_init(Files); 3729 1.87 christos break; 3730 1.87 christos } 3731 1.87 christos #endif /* !DISABLE_SIGN */ 3732 1.87 christos 3733 1.87 christos #ifndef DISABLE_TLS 3734 1.87 christos if (tls_status_msg) { 3735 1.101 joerg loginfo("%s", tls_status_msg); 3736 1.87 christos free(tls_status_msg); 3737 1.87 christos } 3738 1.87 christos DPRINTF((D_NET|D_TLS), "Preparing sockets for TLS\n"); 3739 1.87 christos TLS_Listen_Set = 3740 1.87 christos socksetup_tls(PF_UNSPEC, tls_opt.bindhost, tls_opt.bindport); 3741 1.87 christos 3742 1.87 christos for (f = Files; f; f = f->f_next) { 3743 1.87 christos if (f->f_type != F_TLS) 3744 1.87 christos continue; 3745 1.87 christos if (!tls_connect(f->f_un.f_tls.tls_conn)) { 3746 1.87 christos logerror("Unable to connect to TLS server %s", 3747 1.87 christos f->f_un.f_tls.tls_conn->hostname); 3748 1.87 christos /* Reconnect after x seconds */ 3749 1.87 christos schedule_event(&f->f_un.f_tls.tls_conn->event, 3750 1.87 christos &((struct timeval){TLS_RECONNECT_SEC, 0}), 3751 1.87 christos tls_reconnect, f->f_un.f_tls.tls_conn); 3752 1.87 christos } 3753 1.1 cgd } 3754 1.87 christos #endif /* !DISABLE_TLS */ 3755 1.1 cgd 3756 1.87 christos loginfo("restart"); 3757 1.70 thorpej /* 3758 1.70 thorpej * Log a change in hostname, but only on a restart (we detect this 3759 1.70 thorpej * by checking to see if we're passed a kevent). 3760 1.70 thorpej */ 3761 1.87 christos if (oldLocalFQDN && strcmp(oldLocalFQDN, LocalFQDN) != 0) 3762 1.87 christos loginfo("host name changed, \"%s\" to \"%s\"", 3763 1.87 christos oldLocalFQDN, LocalFQDN); 3764 1.87 christos 3765 1.87 christos RESTORE_SIGNALS(omask); 3766 1.1 cgd } 3767 1.1 cgd 3768 1.1 cgd /* 3769 1.1 cgd * Crack a configuration file line 3770 1.1 cgd */ 3771 1.5 perry void 3772 1.87 christos cfline(size_t linenum, const char *line, struct filed *f, const char *prog, 3773 1.87 christos const char *host) 3774 1.1 cgd { 3775 1.30 itojun struct addrinfo hints, *res; 3776 1.110 christos int error, i, pri, syncfile; 3777 1.87 christos const char *p, *q; 3778 1.87 christos char *bp; 3779 1.47 manu char buf[MAXLINE]; 3780 1.117 christos struct stat sb; 3781 1.1 cgd 3782 1.87 christos DPRINTF((D_CALL|D_PARSE), 3783 1.87 christos "cfline(%zu, \"%s\", f, \"%s\", \"%s\")\n", 3784 1.87 christos linenum, line, prog, host); 3785 1.1 cgd 3786 1.1 cgd errno = 0; /* keep strerror() stuff out of logerror messages */ 3787 1.1 cgd 3788 1.1 cgd /* clear out file entry */ 3789 1.5 perry memset(f, 0, sizeof(*f)); 3790 1.1 cgd for (i = 0; i <= LOG_NFACILITIES; i++) 3791 1.1 cgd f->f_pmask[i] = INTERNAL_NOPRI; 3792 1.92 minskim STAILQ_INIT(&f->f_qhead); 3793 1.92 minskim 3794 1.92 minskim /* 3795 1.47 manu * There should not be any space before the log facility. 3796 1.47 manu * Check this is okay, complain and fix if it is not. 3797 1.47 manu */ 3798 1.47 manu q = line; 3799 1.47 manu if (isblank((unsigned char)*line)) { 3800 1.47 manu errno = 0; 3801 1.87 christos logerror("Warning: `%s' space or tab before the log facility", 3802 1.47 manu line); 3803 1.47 manu /* Fix: strip all spaces/tabs before the log facility */ 3804 1.70 thorpej while (*q++ && isblank((unsigned char)*q)) 3805 1.70 thorpej /* skip blanks */; 3806 1.92 minskim line = q; 3807 1.47 manu } 3808 1.47 manu 3809 1.92 minskim /* 3810 1.47 manu * q is now at the first char of the log facility 3811 1.92 minskim * There should be at least one tab after the log facility 3812 1.47 manu * Check this is okay, and complain and fix if it is not. 3813 1.47 manu */ 3814 1.47 manu q = line + strlen(line); 3815 1.47 manu while (!isblank((unsigned char)*q) && (q != line)) 3816 1.47 manu q--; 3817 1.92 minskim if ((q == line) && strlen(line)) { 3818 1.47 manu /* No tabs or space in a non empty line: complain */ 3819 1.47 manu errno = 0; 3820 1.47 manu logerror( 3821 1.47 manu "Error: `%s' log facility or log target missing", 3822 1.47 manu line); 3823 1.70 thorpej return; 3824 1.47 manu } 3825 1.92 minskim 3826 1.70 thorpej /* save host name, if any */ 3827 1.70 thorpej if (*host == '*') 3828 1.70 thorpej f->f_host = NULL; 3829 1.70 thorpej else { 3830 1.70 thorpej f->f_host = strdup(host); 3831 1.120 jnemeth trim_anydomain(&f->f_host[1]); /* skip +/- at beginning */ 3832 1.70 thorpej } 3833 1.70 thorpej 3834 1.70 thorpej /* save program name, if any */ 3835 1.70 thorpej if (*prog == '*') 3836 1.70 thorpej f->f_program = NULL; 3837 1.70 thorpej else 3838 1.70 thorpej f->f_program = strdup(prog); 3839 1.1 cgd 3840 1.1 cgd /* scan through the list of selectors */ 3841 1.70 thorpej for (p = line; *p && !isblank((unsigned char)*p);) { 3842 1.70 thorpej int pri_done, pri_cmp, pri_invert; 3843 1.1 cgd 3844 1.1 cgd /* find the end of this facility name list */ 3845 1.70 thorpej for (q = p; *q && !isblank((unsigned char)*q) && *q++ != '.'; ) 3846 1.1 cgd continue; 3847 1.1 cgd 3848 1.70 thorpej /* get the priority comparison */ 3849 1.70 thorpej pri_cmp = 0; 3850 1.70 thorpej pri_done = 0; 3851 1.70 thorpej pri_invert = 0; 3852 1.70 thorpej if (*q == '!') { 3853 1.70 thorpej pri_invert = 1; 3854 1.70 thorpej q++; 3855 1.70 thorpej } 3856 1.70 thorpej while (! pri_done) { 3857 1.70 thorpej switch (*q) { 3858 1.70 thorpej case '<': 3859 1.70 thorpej pri_cmp = PRI_LT; 3860 1.70 thorpej q++; 3861 1.70 thorpej break; 3862 1.70 thorpej case '=': 3863 1.70 thorpej pri_cmp = PRI_EQ; 3864 1.70 thorpej q++; 3865 1.70 thorpej break; 3866 1.70 thorpej case '>': 3867 1.70 thorpej pri_cmp = PRI_GT; 3868 1.70 thorpej q++; 3869 1.70 thorpej break; 3870 1.70 thorpej default: 3871 1.70 thorpej pri_done = 1; 3872 1.70 thorpej break; 3873 1.70 thorpej } 3874 1.70 thorpej } 3875 1.70 thorpej 3876 1.1 cgd /* collect priority name */ 3877 1.70 thorpej for (bp = buf; *q && !strchr("\t ,;", *q); ) 3878 1.1 cgd *bp++ = *q++; 3879 1.1 cgd *bp = '\0'; 3880 1.1 cgd 3881 1.1 cgd /* skip cruft */ 3882 1.70 thorpej while (strchr(",;", *q)) 3883 1.1 cgd q++; 3884 1.1 cgd 3885 1.1 cgd /* decode priority name */ 3886 1.70 thorpej if (*buf == '*') { 3887 1.1 cgd pri = LOG_PRIMASK + 1; 3888 1.70 thorpej pri_cmp = PRI_LT | PRI_EQ | PRI_GT; 3889 1.70 thorpej } else { 3890 1.1 cgd pri = decode(buf, prioritynames); 3891 1.1 cgd if (pri < 0) { 3892 1.47 manu errno = 0; 3893 1.47 manu logerror("Unknown priority name `%s'", buf); 3894 1.1 cgd return; 3895 1.1 cgd } 3896 1.1 cgd } 3897 1.70 thorpej if (pri_cmp == 0) 3898 1.70 thorpej pri_cmp = UniquePriority ? PRI_EQ 3899 1.70 thorpej : PRI_EQ | PRI_GT; 3900 1.70 thorpej if (pri_invert) 3901 1.70 thorpej pri_cmp ^= PRI_LT | PRI_EQ | PRI_GT; 3902 1.1 cgd 3903 1.1 cgd /* scan facilities */ 3904 1.70 thorpej while (*p && !strchr("\t .;", *p)) { 3905 1.70 thorpej for (bp = buf; *p && !strchr("\t ,;.", *p); ) 3906 1.1 cgd *bp++ = *p++; 3907 1.1 cgd *bp = '\0'; 3908 1.1 cgd if (*buf == '*') 3909 1.70 thorpej for (i = 0; i < LOG_NFACILITIES; i++) { 3910 1.1 cgd f->f_pmask[i] = pri; 3911 1.70 thorpej f->f_pcmp[i] = pri_cmp; 3912 1.70 thorpej } 3913 1.1 cgd else { 3914 1.1 cgd i = decode(buf, facilitynames); 3915 1.1 cgd if (i < 0) { 3916 1.47 manu errno = 0; 3917 1.47 manu logerror("Unknown facility name `%s'", 3918 1.1 cgd buf); 3919 1.1 cgd return; 3920 1.1 cgd } 3921 1.1 cgd f->f_pmask[i >> 3] = pri; 3922 1.73 thorpej f->f_pcmp[i >> 3] = pri_cmp; 3923 1.1 cgd } 3924 1.1 cgd while (*p == ',' || *p == ' ') 3925 1.1 cgd p++; 3926 1.1 cgd } 3927 1.1 cgd 3928 1.1 cgd p = q; 3929 1.1 cgd } 3930 1.1 cgd 3931 1.1 cgd /* skip to action part */ 3932 1.70 thorpej while (isblank((unsigned char)*p)) 3933 1.1 cgd p++; 3934 1.1 cgd 3935 1.92 minskim /* 3936 1.87 christos * should this be "#ifndef DISABLE_SIGN" or is it a general option? 3937 1.87 christos * '+' before file destination: write with PRI field for later 3938 1.87 christos * verification 3939 1.92 minskim */ 3940 1.87 christos if (*p == '+') { 3941 1.87 christos f->f_flags |= FFLAG_FULL; 3942 1.87 christos p++; 3943 1.87 christos } 3944 1.70 thorpej if (*p == '-') { 3945 1.70 thorpej syncfile = 0; 3946 1.70 thorpej p++; 3947 1.70 thorpej } else 3948 1.70 thorpej syncfile = 1; 3949 1.70 thorpej 3950 1.70 thorpej switch (*p) { 3951 1.1 cgd case '@': 3952 1.87 christos #ifndef DISABLE_SIGN 3953 1.87 christos if (GlobalSign.sg == 3) 3954 1.87 christos f->f_flags |= FFLAG_SIGN; 3955 1.87 christos #endif /* !DISABLE_SIGN */ 3956 1.87 christos #ifndef DISABLE_TLS 3957 1.87 christos if (*(p+1) == '[') { 3958 1.87 christos /* TLS destination */ 3959 1.87 christos if (!parse_tls_destination(p, f, linenum)) { 3960 1.87 christos logerror("Unable to parse action %s", p); 3961 1.87 christos break; 3962 1.87 christos } 3963 1.87 christos f->f_type = F_TLS; 3964 1.87 christos break; 3965 1.87 christos } 3966 1.87 christos #endif /* !DISABLE_TLS */ 3967 1.58 itojun (void)strlcpy(f->f_un.f_forw.f_hname, ++p, 3968 1.58 itojun sizeof(f->f_un.f_forw.f_hname)); 3969 1.30 itojun memset(&hints, 0, sizeof(hints)); 3970 1.30 itojun hints.ai_family = AF_UNSPEC; 3971 1.30 itojun hints.ai_socktype = SOCK_DGRAM; 3972 1.30 itojun hints.ai_protocol = 0; 3973 1.34 lukem error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints, 3974 1.34 lukem &res); 3975 1.30 itojun if (error) { 3976 1.107 christos errno = 0; 3977 1.101 joerg logerror("%s", gai_strerror(error)); 3978 1.1 cgd break; 3979 1.1 cgd } 3980 1.30 itojun f->f_un.f_forw.f_addr = res; 3981 1.1 cgd f->f_type = F_FORW; 3982 1.36 jwise NumForwards++; 3983 1.1 cgd break; 3984 1.1 cgd 3985 1.1 cgd case '/': 3986 1.87 christos #ifndef DISABLE_SIGN 3987 1.87 christos if (GlobalSign.sg == 3) 3988 1.87 christos f->f_flags |= FFLAG_SIGN; 3989 1.87 christos #endif /* !DISABLE_SIGN */ 3990 1.58 itojun (void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname)); 3991 1.118 christos if ((f->f_file = open(p, O_WRONLY|O_APPEND|O_NONBLOCK, 0)) < 0) 3992 1.118 christos { 3993 1.118 christos f->f_type = F_UNUSED; 3994 1.118 christos logerror("%s", p); 3995 1.118 christos break; 3996 1.118 christos } 3997 1.118 christos if (!fstat(f->f_file, &sb) && S_ISFIFO(sb.st_mode)) { 3998 1.117 christos f->f_file = -1; 3999 1.117 christos f->f_type = F_FIFO; 4000 1.117 christos break; 4001 1.117 christos } 4002 1.117 christos 4003 1.108 christos if (isatty(f->f_file)) { 4004 1.108 christos f->f_type = F_TTY; 4005 1.108 christos if (strcmp(p, ctty) == 0) 4006 1.108 christos f->f_type = F_CONSOLE; 4007 1.110 christos } else 4008 1.108 christos f->f_type = F_FILE; 4009 1.118 christos 4010 1.70 thorpej if (syncfile) 4011 1.70 thorpej f->f_flags |= FFLAG_SYNC; 4012 1.1 cgd break; 4013 1.1 cgd 4014 1.70 thorpej case '|': 4015 1.100 riz #ifndef DISABLE_SIGN 4016 1.87 christos if (GlobalSign.sg == 3) 4017 1.87 christos f->f_flags |= FFLAG_SIGN; 4018 1.100 riz #endif 4019 1.70 thorpej f->f_un.f_pipe.f_pid = 0; 4020 1.70 thorpej (void) strlcpy(f->f_un.f_pipe.f_pname, p + 1, 4021 1.70 thorpej sizeof(f->f_un.f_pipe.f_pname)); 4022 1.70 thorpej f->f_type = F_PIPE; 4023 1.70 thorpej break; 4024 1.70 thorpej 4025 1.1 cgd case '*': 4026 1.1 cgd f->f_type = F_WALL; 4027 1.1 cgd break; 4028 1.1 cgd 4029 1.1 cgd default: 4030 1.1 cgd for (i = 0; i < MAXUNAMES && *p; i++) { 4031 1.1 cgd for (q = p; *q && *q != ','; ) 4032 1.1 cgd q++; 4033 1.5 perry (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); 4034 1.1 cgd if ((q - p) > UT_NAMESIZE) 4035 1.1 cgd f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; 4036 1.1 cgd else 4037 1.1 cgd f->f_un.f_uname[i][q - p] = '\0'; 4038 1.1 cgd while (*q == ',' || *q == ' ') 4039 1.1 cgd q++; 4040 1.1 cgd p = q; 4041 1.1 cgd } 4042 1.1 cgd f->f_type = F_USERS; 4043 1.1 cgd break; 4044 1.1 cgd } 4045 1.1 cgd } 4046 1.1 cgd 4047 1.1 cgd 4048 1.1 cgd /* 4049 1.1 cgd * Decode a symbolic name to a numeric value 4050 1.1 cgd */ 4051 1.5 perry int 4052 1.53 wiz decode(const char *name, CODE *codetab) 4053 1.1 cgd { 4054 1.5 perry CODE *c; 4055 1.5 perry char *p, buf[40]; 4056 1.1 cgd 4057 1.69 dsl if (isdigit((unsigned char)*name)) 4058 1.87 christos return atoi(name); 4059 1.1 cgd 4060 1.5 perry for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) { 4061 1.69 dsl if (isupper((unsigned char)*name)) 4062 1.69 dsl *p = tolower((unsigned char)*name); 4063 1.5 perry else 4064 1.5 perry *p = *name; 4065 1.5 perry } 4066 1.5 perry *p = '\0'; 4067 1.1 cgd for (c = codetab; c->c_name; c++) 4068 1.1 cgd if (!strcmp(buf, c->c_name)) 4069 1.87 christos return c->c_val; 4070 1.1 cgd 4071 1.87 christos return -1; 4072 1.15 leo } 4073 1.15 leo 4074 1.15 leo /* 4075 1.15 leo * Retrieve the size of the kernel message buffer, via sysctl. 4076 1.15 leo */ 4077 1.15 leo int 4078 1.53 wiz getmsgbufsize(void) 4079 1.15 leo { 4080 1.87 christos #ifdef __NetBSD_Version__ 4081 1.15 leo int msgbufsize, mib[2]; 4082 1.15 leo size_t size; 4083 1.15 leo 4084 1.15 leo mib[0] = CTL_KERN; 4085 1.15 leo mib[1] = KERN_MSGBUFSIZE; 4086 1.15 leo size = sizeof msgbufsize; 4087 1.15 leo if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) { 4088 1.87 christos DPRINTF(D_MISC, "Couldn't get kern.msgbufsize\n"); 4089 1.87 christos return 0; 4090 1.87 christos } 4091 1.87 christos return msgbufsize; 4092 1.87 christos #else 4093 1.87 christos return MAXLINE; 4094 1.87 christos #endif /* __NetBSD_Version__ */ 4095 1.87 christos } 4096 1.87 christos 4097 1.87 christos /* 4098 1.87 christos * Retrieve the hostname, via sysctl. 4099 1.87 christos */ 4100 1.87 christos char * 4101 1.87 christos getLocalFQDN(void) 4102 1.87 christos { 4103 1.87 christos int mib[2]; 4104 1.87 christos char *hostname; 4105 1.87 christos size_t len; 4106 1.87 christos 4107 1.87 christos mib[0] = CTL_KERN; 4108 1.87 christos mib[1] = KERN_HOSTNAME; 4109 1.87 christos sysctl(mib, 2, NULL, &len, NULL, 0); 4110 1.87 christos 4111 1.87 christos if (!(hostname = malloc(len))) { 4112 1.87 christos logerror("Unable to allocate memory"); 4113 1.87 christos die(0,0,NULL); 4114 1.87 christos } else if (sysctl(mib, 2, hostname, &len, NULL, 0) == -1) { 4115 1.87 christos DPRINTF(D_MISC, "Couldn't get kern.hostname\n"); 4116 1.87 christos (void)gethostname(hostname, sizeof(len)); 4117 1.15 leo } 4118 1.87 christos return hostname; 4119 1.30 itojun } 4120 1.30 itojun 4121 1.87 christos struct socketEvent * 4122 1.79 christos socksetup(int af, const char *hostname) 4123 1.30 itojun { 4124 1.31 itojun struct addrinfo hints, *res, *r; 4125 1.87 christos int error, maxs; 4126 1.87 christos int on = 1; 4127 1.87 christos struct socketEvent *s, *socks; 4128 1.35 jwise 4129 1.36 jwise if(SecureMode && !NumForwards) 4130 1.87 christos return NULL; 4131 1.30 itojun 4132 1.30 itojun memset(&hints, 0, sizeof(hints)); 4133 1.30 itojun hints.ai_flags = AI_PASSIVE; 4134 1.30 itojun hints.ai_family = af; 4135 1.30 itojun hints.ai_socktype = SOCK_DGRAM; 4136 1.79 christos error = getaddrinfo(hostname, "syslog", &hints, &res); 4137 1.30 itojun if (error) { 4138 1.107 christos errno = 0; 4139 1.101 joerg logerror("%s", gai_strerror(error)); 4140 1.87 christos die(0, 0, NULL); 4141 1.30 itojun } 4142 1.31 itojun 4143 1.31 itojun /* Count max number of sockets we may open */ 4144 1.34 lukem for (maxs = 0, r = res; r; r = r->ai_next, maxs++) 4145 1.34 lukem continue; 4146 1.87 christos socks = calloc(maxs+1, sizeof(*socks)); 4147 1.31 itojun if (!socks) { 4148 1.47 manu logerror("Couldn't allocate memory for sockets"); 4149 1.87 christos die(0, 0, NULL); 4150 1.31 itojun } 4151 1.31 itojun 4152 1.87 christos socks->fd = 0; /* num of sockets counter at start of array */ 4153 1.56 itojun s = socks + 1; 4154 1.31 itojun for (r = res; r; r = r->ai_next) { 4155 1.87 christos s->fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol); 4156 1.87 christos if (s->fd < 0) { 4157 1.47 manu logerror("socket() failed"); 4158 1.56 itojun continue; 4159 1.56 itojun } 4160 1.115 christos s->af = r->ai_family; 4161 1.87 christos if (r->ai_family == AF_INET6 && setsockopt(s->fd, IPPROTO_IPV6, 4162 1.56 itojun IPV6_V6ONLY, &on, sizeof(on)) < 0) { 4163 1.56 itojun logerror("setsockopt(IPV6_V6ONLY) failed"); 4164 1.87 christos close(s->fd); 4165 1.31 itojun continue; 4166 1.31 itojun } 4167 1.70 thorpej 4168 1.70 thorpej if (!SecureMode) { 4169 1.87 christos if (bind(s->fd, r->ai_addr, r->ai_addrlen) < 0) { 4170 1.70 thorpej logerror("bind() failed"); 4171 1.87 christos close(s->fd); 4172 1.70 thorpej continue; 4173 1.70 thorpej } 4174 1.87 christos s->ev = allocev(); 4175 1.87 christos event_set(s->ev, s->fd, EV_READ | EV_PERSIST, 4176 1.87 christos dispatch_read_finet, s->ev); 4177 1.87 christos if (event_add(s->ev, NULL) == -1) { 4178 1.87 christos DPRINTF((D_EVENT|D_NET), 4179 1.87 christos "Failure in event_add()\n"); 4180 1.87 christos } else { 4181 1.87 christos DPRINTF((D_EVENT|D_NET), 4182 1.87 christos "Listen on UDP port " 4183 1.87 christos "(event@%p)\n", s->ev); 4184 1.87 christos } 4185 1.31 itojun } 4186 1.31 itojun 4187 1.87 christos socks->fd++; /* num counter */ 4188 1.31 itojun s++; 4189 1.31 itojun } 4190 1.31 itojun 4191 1.87 christos if (res) 4192 1.87 christos freeaddrinfo(res); 4193 1.87 christos if (socks->fd == 0) { 4194 1.31 itojun free (socks); 4195 1.31 itojun if(Debug) 4196 1.87 christos return NULL; 4197 1.31 itojun else 4198 1.87 christos die(0, 0, NULL); 4199 1.30 itojun } 4200 1.87 christos return socks; 4201 1.1 cgd } 4202 1.70 thorpej 4203 1.70 thorpej /* 4204 1.70 thorpej * Fairly similar to popen(3), but returns an open descriptor, as opposed 4205 1.70 thorpej * to a FILE *. 4206 1.70 thorpej */ 4207 1.70 thorpej int 4208 1.70 thorpej p_open(char *prog, pid_t *rpid) 4209 1.70 thorpej { 4210 1.87 christos static char sh[] = "sh", mc[] = "-c"; 4211 1.70 thorpej int pfd[2], nulldesc, i; 4212 1.70 thorpej pid_t pid; 4213 1.70 thorpej char *argv[4]; /* sh -c cmd NULL */ 4214 1.70 thorpej 4215 1.70 thorpej if (pipe(pfd) == -1) 4216 1.87 christos return -1; 4217 1.70 thorpej if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1) { 4218 1.70 thorpej /* We are royally screwed anyway. */ 4219 1.87 christos return -1; 4220 1.70 thorpej } 4221 1.70 thorpej 4222 1.70 thorpej switch ((pid = fork())) { 4223 1.70 thorpej case -1: 4224 1.70 thorpej (void) close(nulldesc); 4225 1.87 christos return -1; 4226 1.70 thorpej 4227 1.70 thorpej case 0: 4228 1.87 christos argv[0] = sh; 4229 1.87 christos argv[1] = mc; 4230 1.70 thorpej argv[2] = prog; 4231 1.70 thorpej argv[3] = NULL; 4232 1.70 thorpej 4233 1.70 thorpej (void) setsid(); /* avoid catching SIGHUPs. */ 4234 1.70 thorpej 4235 1.70 thorpej /* 4236 1.70 thorpej * Reset ignored signals to their default behavior. 4237 1.70 thorpej */ 4238 1.70 thorpej (void)signal(SIGTERM, SIG_DFL); 4239 1.70 thorpej (void)signal(SIGINT, SIG_DFL); 4240 1.70 thorpej (void)signal(SIGQUIT, SIG_DFL); 4241 1.70 thorpej (void)signal(SIGPIPE, SIG_DFL); 4242 1.70 thorpej (void)signal(SIGHUP, SIG_DFL); 4243 1.70 thorpej 4244 1.70 thorpej dup2(pfd[0], STDIN_FILENO); 4245 1.70 thorpej dup2(nulldesc, STDOUT_FILENO); 4246 1.70 thorpej dup2(nulldesc, STDERR_FILENO); 4247 1.70 thorpej for (i = getdtablesize(); i > 2; i--) 4248 1.70 thorpej (void) close(i); 4249 1.70 thorpej 4250 1.70 thorpej (void) execvp(_PATH_BSHELL, argv); 4251 1.70 thorpej _exit(255); 4252 1.70 thorpej } 4253 1.70 thorpej 4254 1.70 thorpej (void) close(nulldesc); 4255 1.70 thorpej (void) close(pfd[0]); 4256 1.70 thorpej 4257 1.70 thorpej /* 4258 1.70 thorpej * Avoid blocking on a hung pipe. With O_NONBLOCK, we are 4259 1.70 thorpej * supposed to get an EWOULDBLOCK on writev(2), which is 4260 1.70 thorpej * caught by the logic above anyway, which will in turn 4261 1.70 thorpej * close the pipe, and fork a new logging subprocess if 4262 1.70 thorpej * necessary. The stale subprocess will be killed some 4263 1.70 thorpej * time later unless it terminated itself due to closing 4264 1.70 thorpej * its input pipe. 4265 1.70 thorpej */ 4266 1.70 thorpej if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) { 4267 1.70 thorpej /* This is bad. */ 4268 1.107 christos logerror("Warning: cannot change pipe to pid %d to " 4269 1.70 thorpej "non-blocking.", (int) pid); 4270 1.70 thorpej } 4271 1.70 thorpej *rpid = pid; 4272 1.87 christos return pfd[1]; 4273 1.70 thorpej } 4274 1.70 thorpej 4275 1.70 thorpej void 4276 1.70 thorpej deadq_enter(pid_t pid, const char *name) 4277 1.70 thorpej { 4278 1.70 thorpej dq_t p; 4279 1.70 thorpej int status; 4280 1.70 thorpej 4281 1.70 thorpej /* 4282 1.70 thorpej * Be paranoid: if we can't signal the process, don't enter it 4283 1.70 thorpej * into the dead queue (perhaps it's already dead). If possible, 4284 1.70 thorpej * we try to fetch and log the child's status. 4285 1.70 thorpej */ 4286 1.70 thorpej if (kill(pid, 0) != 0) { 4287 1.70 thorpej if (waitpid(pid, &status, WNOHANG) > 0) 4288 1.70 thorpej log_deadchild(pid, status, name); 4289 1.70 thorpej return; 4290 1.70 thorpej } 4291 1.70 thorpej 4292 1.70 thorpej p = malloc(sizeof(*p)); 4293 1.70 thorpej if (p == NULL) { 4294 1.70 thorpej logerror("panic: out of memory!"); 4295 1.70 thorpej exit(1); 4296 1.70 thorpej } 4297 1.70 thorpej 4298 1.70 thorpej p->dq_pid = pid; 4299 1.70 thorpej p->dq_timeout = DQ_TIMO_INIT; 4300 1.70 thorpej TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries); 4301 1.70 thorpej } 4302 1.70 thorpej 4303 1.70 thorpej int 4304 1.70 thorpej deadq_remove(pid_t pid) 4305 1.70 thorpej { 4306 1.70 thorpej dq_t q; 4307 1.70 thorpej 4308 1.70 thorpej for (q = TAILQ_FIRST(&deadq_head); q != NULL; 4309 1.70 thorpej q = TAILQ_NEXT(q, dq_entries)) { 4310 1.70 thorpej if (q->dq_pid == pid) { 4311 1.70 thorpej TAILQ_REMOVE(&deadq_head, q, dq_entries); 4312 1.70 thorpej free(q); 4313 1.87 christos return 1; 4314 1.70 thorpej } 4315 1.70 thorpej } 4316 1.87 christos return 0; 4317 1.70 thorpej } 4318 1.70 thorpej 4319 1.70 thorpej void 4320 1.70 thorpej log_deadchild(pid_t pid, int status, const char *name) 4321 1.70 thorpej { 4322 1.70 thorpej int code; 4323 1.70 thorpej char buf[256]; 4324 1.70 thorpej const char *reason; 4325 1.70 thorpej 4326 1.70 thorpej /* Keep strerror() struff out of logerror messages. */ 4327 1.70 thorpej errno = 0; 4328 1.70 thorpej if (WIFSIGNALED(status)) { 4329 1.70 thorpej reason = "due to signal"; 4330 1.70 thorpej code = WTERMSIG(status); 4331 1.70 thorpej } else { 4332 1.70 thorpej reason = "with status"; 4333 1.70 thorpej code = WEXITSTATUS(status); 4334 1.70 thorpej if (code == 0) 4335 1.70 thorpej return; 4336 1.70 thorpej } 4337 1.70 thorpej (void) snprintf(buf, sizeof(buf), 4338 1.70 thorpej "Logging subprocess %d (%s) exited %s %d.", 4339 1.70 thorpej pid, name, reason, code); 4340 1.101 joerg logerror("%s", buf); 4341 1.70 thorpej } 4342 1.70 thorpej 4343 1.87 christos struct event * 4344 1.87 christos allocev(void) 4345 1.87 christos { 4346 1.87 christos struct event *ev; 4347 1.87 christos 4348 1.87 christos if (!(ev = calloc(1, sizeof(*ev)))) 4349 1.87 christos logerror("Unable to allocate memory"); 4350 1.87 christos return ev; 4351 1.87 christos } 4352 1.87 christos 4353 1.87 christos /* *ev is allocated if necessary */ 4354 1.92 minskim void 4355 1.87 christos schedule_event(struct event **ev, struct timeval *tv, 4356 1.87 christos void (*cb)(int, short, void *), void *arg) 4357 1.87 christos { 4358 1.87 christos if (!*ev && !(*ev = allocev())) { 4359 1.87 christos return; 4360 1.87 christos } 4361 1.87 christos event_set(*ev, 0, 0, cb, arg); 4362 1.87 christos DPRINTF(D_EVENT, "event_add(%s@%p)\n", "schedule_ev", *ev); \ 4363 1.87 christos if (event_add(*ev, tv) == -1) { 4364 1.87 christos DPRINTF(D_EVENT, "Failure in event_add()\n"); 4365 1.87 christos } 4366 1.87 christos } 4367 1.87 christos 4368 1.87 christos #ifndef DISABLE_TLS 4369 1.87 christos /* abbreviation for freeing credential lists */ 4370 1.87 christos void 4371 1.87 christos free_cred_SLIST(struct peer_cred_head *head) 4372 1.87 christos { 4373 1.87 christos struct peer_cred *cred; 4374 1.92 minskim 4375 1.87 christos while (!SLIST_EMPTY(head)) { 4376 1.87 christos cred = SLIST_FIRST(head); 4377 1.87 christos SLIST_REMOVE_HEAD(head, entries); 4378 1.87 christos FREEPTR(cred->data); 4379 1.87 christos free(cred); 4380 1.87 christos } 4381 1.87 christos } 4382 1.87 christos #endif /* !DISABLE_TLS */ 4383 1.87 christos 4384 1.92 minskim /* 4385 1.92 minskim * send message queue after reconnect 4386 1.87 christos */ 4387 1.87 christos /*ARGSUSED*/ 4388 1.87 christos void 4389 1.87 christos send_queue(int fd, short event, void *arg) 4390 1.87 christos { 4391 1.87 christos struct filed *f = (struct filed *) arg; 4392 1.87 christos struct buf_queue *qentry; 4393 1.87 christos #define SQ_CHUNK_SIZE 250 4394 1.87 christos size_t cnt = 0; 4395 1.92 minskim 4396 1.100 riz #ifndef DISABLE_TLS 4397 1.87 christos if (f->f_type == F_TLS) { 4398 1.87 christos /* use a flag to prevent recursive calls to send_queue() */ 4399 1.87 christos if (f->f_un.f_tls.tls_conn->send_queue) 4400 1.87 christos return; 4401 1.87 christos else 4402 1.87 christos f->f_un.f_tls.tls_conn->send_queue = true; 4403 1.87 christos } 4404 1.87 christos DPRINTF((D_DATA|D_CALL), "send_queue(f@%p with %zu msgs, " 4405 1.87 christos "cnt@%p = %zu)\n", f, f->f_qelements, &cnt, cnt); 4406 1.100 riz #endif /* !DISABLE_TLS */ 4407 1.87 christos 4408 1.87 christos while ((qentry = STAILQ_FIRST(&f->f_qhead))) { 4409 1.87 christos #ifndef DISABLE_TLS 4410 1.87 christos /* send_queue() might be called with an unconnected destination 4411 1.87 christos * from init() or die() or one message might take longer, 4412 1.87 christos * leaving the connection in state ST_WAITING and thus not 4413 1.92 minskim * ready for the next message. 4414 1.87 christos * this check is a shortcut to skip these unnecessary calls */ 4415 1.87 christos if (f->f_type == F_TLS 4416 1.87 christos && f->f_un.f_tls.tls_conn->state != ST_TLS_EST) { 4417 1.87 christos DPRINTF(D_TLS, "abort send_queue(cnt@%p = %zu) " 4418 1.87 christos "on TLS connection in state %d\n", 4419 1.87 christos &cnt, cnt, f->f_un.f_tls.tls_conn->state); 4420 1.87 christos return; 4421 1.87 christos } 4422 1.87 christos #endif /* !DISABLE_TLS */ 4423 1.87 christos fprintlog(f, qentry->msg, qentry); 4424 1.87 christos 4425 1.87 christos /* Sending a long queue can take some time during which 4426 1.87 christos * SIGHUP and SIGALRM are blocked and no events are handled. 4427 1.87 christos * To avoid that we only send SQ_CHUNK_SIZE messages at once 4428 1.87 christos * and then reschedule ourselves to continue. Thus the control 4429 1.87 christos * will return first from all signal-protected functions so a 4430 1.87 christos * possible SIGHUP/SIGALRM is handled and then back to the 4431 1.87 christos * main loop which can handle possible input. 4432 1.87 christos */ 4433 1.87 christos if (++cnt >= SQ_CHUNK_SIZE) { 4434 1.87 christos if (!f->f_sq_event) { /* alloc on demand */ 4435 1.87 christos f->f_sq_event = allocev(); 4436 1.87 christos event_set(f->f_sq_event, 0, 0, send_queue, f); 4437 1.87 christos } 4438 1.87 christos if (event_add(f->f_sq_event, &((struct timeval){0, 1})) == -1) { 4439 1.87 christos DPRINTF(D_EVENT, "Failure in event_add()\n"); 4440 1.87 christos } 4441 1.87 christos break; 4442 1.87 christos } 4443 1.87 christos } 4444 1.100 riz #ifndef DISABLE_TLS 4445 1.87 christos if (f->f_type == F_TLS) 4446 1.87 christos f->f_un.f_tls.tls_conn->send_queue = false; 4447 1.100 riz #endif 4448 1.100 riz 4449 1.87 christos } 4450 1.87 christos 4451 1.92 minskim /* 4452 1.87 christos * finds the next queue element to delete 4453 1.92 minskim * 4454 1.87 christos * has stateful behaviour, before using it call once with reset = true 4455 1.87 christos * after that every call will return one next queue elemen to delete, 4456 1.87 christos * depending on strategy either the oldest or the one with the lowest priority 4457 1.87 christos */ 4458 1.87 christos static struct buf_queue * 4459 1.87 christos find_qentry_to_delete(const struct buf_queue_head *head, int strategy, 4460 1.87 christos bool reset) 4461 1.87 christos { 4462 1.87 christos static int pri; 4463 1.87 christos static struct buf_queue *qentry_static; 4464 1.92 minskim 4465 1.87 christos struct buf_queue *qentry_tmp; 4466 1.92 minskim 4467 1.87 christos if (reset || STAILQ_EMPTY(head)) { 4468 1.87 christos pri = LOG_DEBUG; 4469 1.87 christos qentry_static = STAILQ_FIRST(head); 4470 1.87 christos return NULL; 4471 1.87 christos } 4472 1.87 christos 4473 1.87 christos /* find elements to delete */ 4474 1.87 christos if (strategy == PURGE_BY_PRIORITY) { 4475 1.87 christos qentry_tmp = qentry_static; 4476 1.117 christos if (!qentry_tmp) return NULL; 4477 1.87 christos while ((qentry_tmp = STAILQ_NEXT(qentry_tmp, entries)) != NULL) 4478 1.87 christos { 4479 1.87 christos if (LOG_PRI(qentry_tmp->msg->pri) == pri) { 4480 1.87 christos /* save the successor, because qentry_tmp 4481 1.87 christos * is probably deleted by the caller */ 4482 1.87 christos qentry_static = STAILQ_NEXT(qentry_tmp, entries); 4483 1.87 christos return qentry_tmp; 4484 1.87 christos } 4485 1.87 christos } 4486 1.87 christos /* nothing found in while loop --> next pri */ 4487 1.87 christos if (--pri) 4488 1.87 christos return find_qentry_to_delete(head, strategy, false); 4489 1.87 christos else 4490 1.87 christos return NULL; 4491 1.87 christos } else /* strategy == PURGE_OLDEST or other value */ { 4492 1.87 christos qentry_tmp = qentry_static; 4493 1.87 christos qentry_static = STAILQ_NEXT(qentry_tmp, entries); 4494 1.87 christos return qentry_tmp; /* is NULL on empty queue */ 4495 1.87 christos } 4496 1.87 christos } 4497 1.87 christos 4498 1.87 christos /* note on TAILQ: newest message added at TAIL, 4499 1.87 christos * oldest to be removed is FIRST 4500 1.87 christos */ 4501 1.87 christos /* 4502 1.87 christos * checks length of a destination's message queue 4503 1.87 christos * if del_entries == 0 then assert queue length is 4504 1.87 christos * less or equal to configured number of queue elements 4505 1.87 christos * otherwise del_entries tells how many entries to delete 4506 1.92 minskim * 4507 1.87 christos * returns the number of removed queue elements 4508 1.87 christos * (which not necessarily means free'd messages) 4509 1.92 minskim * 4510 1.87 christos * strategy PURGE_OLDEST to delete oldest entry, e.g. after it was resent 4511 1.87 christos * strategy PURGE_BY_PRIORITY to delete messages with lowest priority first, 4512 1.87 christos * this is much slower but might be desirable when unsent messages have 4513 1.92 minskim * to be deleted, e.g. in call from domark() 4514 1.87 christos */ 4515 1.87 christos size_t 4516 1.87 christos message_queue_purge(struct filed *f, size_t del_entries, int strategy) 4517 1.87 christos { 4518 1.96 lukem size_t removed = 0; 4519 1.87 christos struct buf_queue *qentry = NULL; 4520 1.87 christos 4521 1.87 christos DPRINTF((D_CALL|D_BUFFER), "purge_message_queue(%p, %zu, %d) with " 4522 1.87 christos "f_qelements=%zu and f_qsize=%zu\n", 4523 1.87 christos f, del_entries, strategy, 4524 1.87 christos f->f_qelements, f->f_qsize); 4525 1.87 christos 4526 1.87 christos /* reset state */ 4527 1.87 christos (void)find_qentry_to_delete(&f->f_qhead, strategy, true); 4528 1.87 christos 4529 1.87 christos while (removed < del_entries 4530 1.87 christos || (TypeInfo[f->f_type].queue_length != -1 4531 1.116 christos && (size_t)TypeInfo[f->f_type].queue_length <= f->f_qelements) 4532 1.87 christos || (TypeInfo[f->f_type].queue_size != -1 4533 1.116 christos && (size_t)TypeInfo[f->f_type].queue_size <= f->f_qsize)) { 4534 1.87 christos qentry = find_qentry_to_delete(&f->f_qhead, strategy, 0); 4535 1.87 christos if (message_queue_remove(f, qentry)) 4536 1.87 christos removed++; 4537 1.87 christos else 4538 1.87 christos break; 4539 1.87 christos } 4540 1.87 christos return removed; 4541 1.87 christos } 4542 1.87 christos 4543 1.87 christos /* run message_queue_purge() for all destinations to free memory */ 4544 1.87 christos size_t 4545 1.87 christos message_allqueues_purge(void) 4546 1.87 christos { 4547 1.87 christos size_t sum = 0; 4548 1.87 christos struct filed *f; 4549 1.87 christos 4550 1.87 christos for (f = Files; f; f = f->f_next) 4551 1.87 christos sum += message_queue_purge(f, 4552 1.87 christos f->f_qelements/10, PURGE_BY_PRIORITY); 4553 1.87 christos 4554 1.87 christos DPRINTF(D_BUFFER, 4555 1.87 christos "message_allqueues_purge(): removed %zu buffer entries\n", sum); 4556 1.87 christos return sum; 4557 1.87 christos } 4558 1.87 christos 4559 1.87 christos /* run message_queue_purge() for all destinations to check limits */ 4560 1.87 christos size_t 4561 1.87 christos message_allqueues_check(void) 4562 1.87 christos { 4563 1.87 christos size_t sum = 0; 4564 1.87 christos struct filed *f; 4565 1.87 christos 4566 1.87 christos for (f = Files; f; f = f->f_next) 4567 1.87 christos sum += message_queue_purge(f, 0, PURGE_BY_PRIORITY); 4568 1.87 christos DPRINTF(D_BUFFER, 4569 1.87 christos "message_allqueues_check(): removed %zu buffer entries\n", sum); 4570 1.87 christos return sum; 4571 1.87 christos } 4572 1.87 christos 4573 1.87 christos struct buf_msg * 4574 1.87 christos buf_msg_new(const size_t len) 4575 1.87 christos { 4576 1.87 christos struct buf_msg *newbuf; 4577 1.87 christos 4578 1.87 christos CALLOC(newbuf, sizeof(*newbuf)); 4579 1.87 christos 4580 1.87 christos if (len) { /* len = 0 is valid */ 4581 1.87 christos MALLOC(newbuf->msg, len); 4582 1.87 christos newbuf->msgorig = newbuf->msg; 4583 1.87 christos newbuf->msgsize = len; 4584 1.87 christos } 4585 1.87 christos return NEWREF(newbuf); 4586 1.87 christos } 4587 1.87 christos 4588 1.87 christos void 4589 1.87 christos buf_msg_free(struct buf_msg *buf) 4590 1.87 christos { 4591 1.87 christos if (!buf) 4592 1.87 christos return; 4593 1.87 christos 4594 1.87 christos buf->refcount--; 4595 1.87 christos if (buf->refcount == 0) { 4596 1.87 christos FREEPTR(buf->timestamp); 4597 1.87 christos /* small optimizations: the host/recvhost may point to the 4598 1.87 christos * global HostName/FQDN. of course this must not be free()d 4599 1.87 christos * same goes for appname and include_pid 4600 1.87 christos */ 4601 1.87 christos if (buf->recvhost != buf->host 4602 1.87 christos && buf->recvhost != LocalHostName 4603 1.87 christos && buf->recvhost != LocalFQDN 4604 1.87 christos && buf->recvhost != oldLocalFQDN) 4605 1.87 christos FREEPTR(buf->recvhost); 4606 1.87 christos if (buf->host != LocalHostName 4607 1.87 christos && buf->host != LocalFQDN 4608 1.87 christos && buf->host != oldLocalFQDN) 4609 1.87 christos FREEPTR(buf->host); 4610 1.87 christos if (buf->prog != appname) 4611 1.87 christos FREEPTR(buf->prog); 4612 1.87 christos if (buf->pid != include_pid) 4613 1.87 christos FREEPTR(buf->pid); 4614 1.87 christos FREEPTR(buf->msgid); 4615 1.87 christos FREEPTR(buf->sd); 4616 1.87 christos FREEPTR(buf->msgorig); /* instead of msg */ 4617 1.87 christos FREEPTR(buf); 4618 1.87 christos } 4619 1.87 christos } 4620 1.87 christos 4621 1.87 christos size_t 4622 1.87 christos buf_queue_obj_size(struct buf_queue *qentry) 4623 1.87 christos { 4624 1.87 christos size_t sum = 0; 4625 1.92 minskim 4626 1.87 christos if (!qentry) 4627 1.87 christos return 0; 4628 1.87 christos sum += sizeof(*qentry) 4629 1.87 christos + sizeof(*qentry->msg) 4630 1.87 christos + qentry->msg->msgsize 4631 1.87 christos + SAFEstrlen(qentry->msg->timestamp)+1 4632 1.87 christos + SAFEstrlen(qentry->msg->msgid)+1; 4633 1.87 christos if (qentry->msg->prog 4634 1.87 christos && qentry->msg->prog != include_pid) 4635 1.87 christos sum += strlen(qentry->msg->prog)+1; 4636 1.87 christos if (qentry->msg->pid 4637 1.87 christos && qentry->msg->pid != appname) 4638 1.87 christos sum += strlen(qentry->msg->pid)+1; 4639 1.87 christos if (qentry->msg->recvhost 4640 1.87 christos && qentry->msg->recvhost != LocalHostName 4641 1.87 christos && qentry->msg->recvhost != LocalFQDN 4642 1.87 christos && qentry->msg->recvhost != oldLocalFQDN) 4643 1.87 christos sum += strlen(qentry->msg->recvhost)+1; 4644 1.87 christos if (qentry->msg->host 4645 1.87 christos && qentry->msg->host != LocalHostName 4646 1.87 christos && qentry->msg->host != LocalFQDN 4647 1.87 christos && qentry->msg->host != oldLocalFQDN) 4648 1.87 christos sum += strlen(qentry->msg->host)+1; 4649 1.87 christos 4650 1.87 christos return sum; 4651 1.87 christos } 4652 1.87 christos 4653 1.87 christos bool 4654 1.87 christos message_queue_remove(struct filed *f, struct buf_queue *qentry) 4655 1.87 christos { 4656 1.87 christos if (!f || !qentry || !qentry->msg) 4657 1.87 christos return false; 4658 1.87 christos 4659 1.87 christos assert(!STAILQ_EMPTY(&f->f_qhead)); 4660 1.87 christos STAILQ_REMOVE(&f->f_qhead, qentry, buf_queue, entries); 4661 1.87 christos f->f_qelements--; 4662 1.87 christos f->f_qsize -= buf_queue_obj_size(qentry); 4663 1.87 christos 4664 1.87 christos DPRINTF(D_BUFFER, "msg @%p removed from queue @%p, new qlen = %zu\n", 4665 1.87 christos qentry->msg, f, f->f_qelements); 4666 1.87 christos DELREF(qentry->msg); 4667 1.87 christos FREEPTR(qentry); 4668 1.87 christos return true; 4669 1.87 christos } 4670 1.87 christos 4671 1.87 christos /* 4672 1.87 christos * returns *qentry on success and NULL on error 4673 1.87 christos */ 4674 1.87 christos struct buf_queue * 4675 1.87 christos message_queue_add(struct filed *f, struct buf_msg *buffer) 4676 1.87 christos { 4677 1.87 christos struct buf_queue *qentry; 4678 1.92 minskim 4679 1.87 christos /* check on every call or only every n-th time? */ 4680 1.87 christos message_queue_purge(f, 0, PURGE_BY_PRIORITY); 4681 1.92 minskim 4682 1.87 christos while (!(qentry = malloc(sizeof(*qentry))) 4683 1.87 christos && message_queue_purge(f, 1, PURGE_OLDEST)) 4684 1.87 christos continue; 4685 1.87 christos if (!qentry) { 4686 1.87 christos logerror("Unable to allocate memory"); 4687 1.87 christos DPRINTF(D_BUFFER, "queue empty, no memory, msg dropped\n"); 4688 1.87 christos return NULL; 4689 1.87 christos } else { 4690 1.87 christos qentry->msg = buffer; 4691 1.87 christos f->f_qelements++; 4692 1.87 christos f->f_qsize += buf_queue_obj_size(qentry); 4693 1.87 christos STAILQ_INSERT_TAIL(&f->f_qhead, qentry, entries); 4694 1.87 christos 4695 1.87 christos DPRINTF(D_BUFFER, "msg @%p queued @%p, qlen = %zu\n", 4696 1.87 christos buffer, f, f->f_qelements); 4697 1.87 christos return qentry; 4698 1.87 christos } 4699 1.87 christos } 4700 1.87 christos 4701 1.87 christos void 4702 1.87 christos message_queue_freeall(struct filed *f) 4703 1.87 christos { 4704 1.87 christos struct buf_queue *qentry; 4705 1.87 christos 4706 1.87 christos if (!f) return; 4707 1.87 christos DPRINTF(D_MEM, "message_queue_freeall(f@%p) with f_qhead@%p\n", f, 4708 1.87 christos &f->f_qhead); 4709 1.87 christos 4710 1.87 christos while (!STAILQ_EMPTY(&f->f_qhead)) { 4711 1.87 christos qentry = STAILQ_FIRST(&f->f_qhead); 4712 1.87 christos STAILQ_REMOVE(&f->f_qhead, qentry, buf_queue, entries); 4713 1.87 christos DELREF(qentry->msg); 4714 1.92 minskim FREEPTR(qentry); 4715 1.87 christos } 4716 1.87 christos 4717 1.87 christos f->f_qelements = 0; 4718 1.87 christos f->f_qsize = 0; 4719 1.87 christos } 4720 1.87 christos 4721 1.87 christos #ifndef DISABLE_TLS 4722 1.87 christos /* utility function for tls_reconnect() */ 4723 1.87 christos struct filed * 4724 1.87 christos get_f_by_conninfo(struct tls_conn_settings *conn_info) 4725 1.87 christos { 4726 1.87 christos struct filed *f; 4727 1.87 christos 4728 1.87 christos for (f = Files; f; f = f->f_next) { 4729 1.87 christos if ((f->f_type == F_TLS) && f->f_un.f_tls.tls_conn == conn_info) 4730 1.87 christos return f; 4731 1.87 christos } 4732 1.87 christos DPRINTF(D_TLS, "get_f_by_conninfo() called on invalid conn_info\n"); 4733 1.87 christos return NULL; 4734 1.87 christos } 4735 1.87 christos 4736 1.87 christos /* 4737 1.87 christos * Called on signal. 4738 1.87 christos * Lets the admin reconnect without waiting for the reconnect timer expires. 4739 1.87 christos */ 4740 1.87 christos /*ARGSUSED*/ 4741 1.87 christos void 4742 1.87 christos dispatch_force_tls_reconnect(int fd, short event, void *ev) 4743 1.87 christos { 4744 1.87 christos struct filed *f; 4745 1.87 christos DPRINTF((D_TLS|D_CALL|D_EVENT), "dispatch_force_tls_reconnect()\n"); 4746 1.87 christos for (f = Files; f; f = f->f_next) { 4747 1.87 christos if (f->f_type == F_TLS && 4748 1.87 christos f->f_un.f_tls.tls_conn->state == ST_NONE) 4749 1.87 christos tls_reconnect(fd, event, f->f_un.f_tls.tls_conn); 4750 1.87 christos } 4751 1.87 christos } 4752 1.87 christos #endif /* !DISABLE_TLS */ 4753 1.70 thorpej 4754 1.87 christos /* 4755 1.87 christos * return a timestamp in a static buffer, 4756 1.87 christos * either format the timestamp given by parameter in_now 4757 1.87 christos * or use the current time if in_now is NULL. 4758 1.87 christos */ 4759 1.87 christos char * 4760 1.121 christos make_timestamp(time_t *in_now, bool iso, size_t tlen) 4761 1.70 thorpej { 4762 1.87 christos int frac_digits = 6; 4763 1.87 christos struct timeval tv; 4764 1.87 christos time_t mytime; 4765 1.91 christos struct tm ltime; 4766 1.87 christos int len = 0; 4767 1.87 christos int tzlen = 0; 4768 1.87 christos /* uses global var: time_t now; */ 4769 1.87 christos 4770 1.87 christos if (in_now) { 4771 1.87 christos mytime = *in_now; 4772 1.87 christos } else { 4773 1.87 christos gettimeofday(&tv, NULL); 4774 1.121 christos mytime = now = tv.tv_sec; 4775 1.87 christos } 4776 1.87 christos 4777 1.87 christos if (!iso) { 4778 1.121 christos strlcpy(timestamp, ctime(&mytime) + 4, sizeof(timestamp)); 4779 1.87 christos timestamp[BSD_TIMESTAMPLEN] = '\0'; 4780 1.121 christos } else { 4781 1.121 christos localtime_r(&mytime, <ime); 4782 1.121 christos len += strftime(timestamp, sizeof(timestamp), "%FT%T", <ime); 4783 1.121 christos snprintf(×tamp[len], frac_digits + 2, ".%.*jd", 4784 1.121 christos frac_digits, (intmax_t)tv.tv_usec); 4785 1.121 christos len += frac_digits + 1; 4786 1.121 christos tzlen = strftime(×tamp[len], sizeof(timestamp) - len, "%z", 4787 1.121 christos <ime); 4788 1.121 christos len += tzlen; 4789 1.121 christos 4790 1.121 christos if (tzlen == 5) { 4791 1.121 christos /* strftime gives "+0200", but we need "+02:00" */ 4792 1.121 christos timestamp[len + 2] = '\0'; 4793 1.121 christos timestamp[len + 1] = timestamp[len]; 4794 1.121 christos timestamp[len] = timestamp[len - 1]; 4795 1.121 christos timestamp[len - 1] = timestamp[len - 2]; 4796 1.121 christos timestamp[len - 2] = ':'; 4797 1.121 christos } 4798 1.87 christos } 4799 1.87 christos 4800 1.121 christos switch (tlen) { 4801 1.121 christos case (size_t)-1: 4802 1.121 christos return timestamp; 4803 1.121 christos case 0: 4804 1.121 christos return strdup(timestamp); 4805 1.121 christos default: 4806 1.121 christos return strndup(timestamp, tlen); 4807 1.87 christos } 4808 1.87 christos } 4809 1.70 thorpej 4810 1.139 andvar /* auxiliary code to allocate memory and copy a string */ 4811 1.87 christos bool 4812 1.87 christos copy_string(char **mem, const char *p, const char *q) 4813 1.87 christos { 4814 1.87 christos const size_t len = 1 + q - p; 4815 1.87 christos if (!(*mem = malloc(len))) { 4816 1.87 christos logerror("Unable to allocate memory for config"); 4817 1.87 christos return false; 4818 1.70 thorpej } 4819 1.87 christos strlcpy(*mem, p, len); 4820 1.87 christos return true; 4821 1.87 christos } 4822 1.70 thorpej 4823 1.87 christos /* keyword has to end with ", everything until next " is copied */ 4824 1.87 christos bool 4825 1.87 christos copy_config_value_quoted(const char *keyword, char **mem, const char **p) 4826 1.87 christos { 4827 1.87 christos const char *q; 4828 1.87 christos if (strncasecmp(*p, keyword, strlen(keyword))) 4829 1.87 christos return false; 4830 1.87 christos q = *p += strlen(keyword); 4831 1.87 christos if (!(q = strchr(*p, '"'))) { 4832 1.107 christos errno = 0; 4833 1.87 christos logerror("unterminated \"\n"); 4834 1.87 christos return false; 4835 1.87 christos } 4836 1.87 christos if (!(copy_string(mem, *p, q))) 4837 1.87 christos return false; 4838 1.87 christos *p = ++q; 4839 1.87 christos return true; 4840 1.87 christos } 4841 1.87 christos 4842 1.87 christos /* for config file: 4843 1.87 christos * following = required but whitespace allowed, quotes optional 4844 1.92 minskim * if numeric, then conversion to integer and no memory allocation 4845 1.87 christos */ 4846 1.87 christos bool 4847 1.87 christos copy_config_value(const char *keyword, char **mem, 4848 1.87 christos const char **p, const char *file, int line) 4849 1.87 christos { 4850 1.87 christos if (strncasecmp(*p, keyword, strlen(keyword))) 4851 1.87 christos return false; 4852 1.87 christos *p += strlen(keyword); 4853 1.87 christos 4854 1.87 christos while (isspace((unsigned char)**p)) 4855 1.87 christos *p += 1; 4856 1.87 christos if (**p != '=') { 4857 1.107 christos errno = 0; 4858 1.87 christos logerror("expected \"=\" in file %s, line %d", file, line); 4859 1.87 christos return false; 4860 1.87 christos } 4861 1.87 christos *p += 1; 4862 1.92 minskim 4863 1.87 christos return copy_config_value_word(mem, p); 4864 1.70 thorpej } 4865 1.70 thorpej 4866 1.87 christos /* copy next parameter from a config line */ 4867 1.87 christos bool 4868 1.87 christos copy_config_value_word(char **mem, const char **p) 4869 1.70 thorpej { 4870 1.87 christos const char *q; 4871 1.87 christos while (isspace((unsigned char)**p)) 4872 1.87 christos *p += 1; 4873 1.87 christos if (**p == '"') 4874 1.87 christos return copy_config_value_quoted("\"", mem, p); 4875 1.87 christos 4876 1.87 christos /* without quotes: find next whitespace or end of line */ 4877 1.87 christos (void)((q = strchr(*p, ' ')) || (q = strchr(*p, '\t')) 4878 1.87 christos || (q = strchr(*p, '\n')) || (q = strchr(*p, '\0'))); 4879 1.87 christos 4880 1.87 christos if (q-*p == 0 || !(copy_string(mem, *p, q))) 4881 1.87 christos return false; 4882 1.70 thorpej 4883 1.87 christos *p = ++q; 4884 1.87 christos return true; 4885 1.70 thorpej } 4886 1.108 christos 4887 1.108 christos static int 4888 1.108 christos writev1(int fd, struct iovec *iov, size_t count) 4889 1.108 christos { 4890 1.108 christos ssize_t nw = 0, tot = 0; 4891 1.108 christos size_t ntries = 5; 4892 1.108 christos 4893 1.111 christos if (count == 0) 4894 1.111 christos return 0; 4895 1.108 christos while (ntries--) { 4896 1.108 christos switch ((nw = writev(fd, iov, count))) { 4897 1.108 christos case -1: 4898 1.108 christos if (errno == EAGAIN || errno == EWOULDBLOCK) { 4899 1.108 christos struct pollfd pfd; 4900 1.108 christos pfd.fd = fd; 4901 1.108 christos pfd.events = POLLOUT; 4902 1.108 christos pfd.revents = 0; 4903 1.108 christos (void)poll(&pfd, 1, 500); 4904 1.108 christos continue; 4905 1.111 christos } 4906 1.111 christos return -1; 4907 1.108 christos case 0: 4908 1.108 christos return 0; 4909 1.108 christos default: 4910 1.108 christos tot += nw; 4911 1.108 christos while (nw > 0) { 4912 1.109 christos if (iov->iov_len > (size_t)nw) { 4913 1.108 christos iov->iov_len -= nw; 4914 1.111 christos iov->iov_base = 4915 1.111 christos (char *)iov->iov_base + nw; 4916 1.108 christos break; 4917 1.108 christos } else { 4918 1.111 christos if (--count == 0) 4919 1.108 christos return tot; 4920 1.108 christos nw -= iov->iov_len; 4921 1.108 christos iov++; 4922 1.108 christos } 4923 1.108 christos } 4924 1.108 christos } 4925 1.108 christos } 4926 1.108 christos return tot == 0 ? nw : tot; 4927 1.108 christos } 4928 1.121 christos 4929 1.140 uwe 4930 1.140 uwe #ifdef NDEBUG 4931 1.140 uwe /* 4932 1.140 uwe * -d also controls daemoniziation, so it makes sense even with 4933 1.140 uwe * NDEBUG, but if the user also tries to specify the logging details 4934 1.140 uwe * with an argument, warn them it's not compiled into this binary. 4935 1.140 uwe */ 4936 1.140 uwe void 4937 1.140 uwe set_debug(const char *level) 4938 1.140 uwe { 4939 1.140 uwe Debug = D_DEFAULT; 4940 1.140 uwe if (level == NULL) 4941 1.140 uwe return; 4942 1.140 uwe 4943 1.140 uwe /* don't bother parsing the argument */ 4944 1.140 uwe fprintf(stderr, 4945 1.140 uwe "%s: debug logging is not compiled\n", 4946 1.140 uwe getprogname()); 4947 1.140 uwe } 4948 1.140 uwe 4949 1.140 uwe #else /* !NDEBUG */ 4950 1.140 uwe void 4951 1.140 uwe set_debug(const char *level) 4952 1.140 uwe { 4953 1.140 uwe if (level == NULL) { 4954 1.140 uwe Debug = D_DEFAULT; /* compat */ 4955 1.140 uwe return; 4956 1.140 uwe } 4957 1.140 uwe 4958 1.140 uwe /* skip initial whitespace for consistency with strto*l */ 4959 1.140 uwe while (isspace((unsigned char)*level)) 4960 1.140 uwe ++level; 4961 1.140 uwe 4962 1.140 uwe /* accept ~num to mean "all except num" */ 4963 1.140 uwe bool invert = level[0] == '~'; 4964 1.140 uwe if (invert) 4965 1.140 uwe ++level; 4966 1.140 uwe 4967 1.140 uwe errno = 0; 4968 1.140 uwe char *endp = NULL; 4969 1.140 uwe unsigned long bits = strtoul(level, &endp, 0); 4970 1.140 uwe if (errno || endp == level || *endp != '\0') { 4971 1.140 uwe fprintf(stderr, "%s: bad argument to -d\n", getprogname()); 4972 1.140 uwe usage(); 4973 1.140 uwe } 4974 1.140 uwe if (invert) 4975 1.140 uwe bits = ~bits; 4976 1.140 uwe 4977 1.140 uwe Debug = bits & D_ALL; 4978 1.140 uwe 4979 1.140 uwe /* 4980 1.140 uwe * make it possible to use -d to stay in the foreground but 4981 1.140 uwe * suppress all dbprintf output (there better be free bits in 4982 1.140 uwe * typeof(Debug) that are not in D_ALL). 4983 1.140 uwe */ 4984 1.140 uwe if (Debug == 0) 4985 1.140 uwe Debug = ~D_ALL; 4986 1.140 uwe } 4987 1.140 uwe #endif /* !NDEBUG */ 4988 1.140 uwe 4989 1.140 uwe 4990 1.121 christos #ifndef NDEBUG 4991 1.121 christos void 4992 1.121 christos dbprintf(const char *fname, const char *funname, 4993 1.121 christos size_t lnum, const char *fmt, ...) 4994 1.121 christos { 4995 1.121 christos va_list ap; 4996 1.121 christos char *ts; 4997 1.121 christos 4998 1.121 christos ts = make_timestamp(NULL, true, (size_t)-1); 4999 1.121 christos printf("%s:%s:%s:%.4zu\t", ts, fname, funname, lnum); 5000 1.121 christos 5001 1.121 christos va_start(ap, fmt); 5002 1.121 christos vprintf(fmt, ap); 5003 1.121 christos va_end(ap); 5004 1.121 christos } 5005 1.121 christos #endif 5006