Bug Summary

File:src/usr.sbin/syslogd/syslogd.c
Warning:line 561, column 6
Potential leak of memory pointed to by 'path_unix'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name syslogd.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/syslogd/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/syslogd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/syslogd/syslogd.c
1/* $OpenBSD: syslogd.c,v 1.272 2021/11/10 21:59:47 bluhm Exp $ */
2
3/*
4 * Copyright (c) 2014-2021 Alexander Bluhm <bluhm@genua.de>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/*
20 * Copyright (c) 1983, 1988, 1993, 1994
21 * The Regents of the University of California. All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 3. Neither the name of the University nor the names of its contributors
32 * may be used to endorse or promote products derived from this software
33 * without specific prior written permission.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 * SUCH DAMAGE.
46 */
47
48/*
49 * syslogd -- log system messages
50 *
51 * This program implements a system log. It takes a series of lines.
52 * Each line may have a priority, signified as "<n>" as
53 * the first characters of the line. If this is
54 * not present, a default priority is used.
55 *
56 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
57 * cause it to reread its configuration file.
58 *
59 * Defined Constants:
60 *
61 * MAXLINE -- the maximum line length that can be handled.
62 * DEFUPRI -- the default priority for user messages
63 * DEFSPRI -- the default priority for kernel messages
64 *
65 * Author: Eric Allman
66 * extensive changes by Ralph Campbell
67 * more extensive changes by Eric Allman (again)
68 * memory buffer logging by Damien Miller
69 * IPv6, libevent, syslog over TCP and TLS by Alexander Bluhm
70 */
71
72#define MAX_UDPMSG1180 1180 /* maximum UDP send size */
73#define MIN_MEMBUF(8192 * 4) (LOG_MAXLINE8192 * 4) /* Minimum memory buffer size */
74#define MAX_MEMBUF(256 * 1024) (256 * 1024) /* Maximum memory buffer size */
75#define MAX_MEMBUF_NAME64 64 /* Max length of membuf log name */
76#define MAX_TCPBUF(256 * 1024) (256 * 1024) /* Maximum tcp event buffer size */
77#define MAXSVLINE120 120 /* maximum saved line length */
78#define FD_RESERVE5 5 /* file descriptors not accepted */
79#define DEFUPRI((1<<3)|5) (LOG_USER(1<<3)|LOG_NOTICE5)
80#define DEFSPRI((0<<3)|2) (LOG_KERN(0<<3)|LOG_CRIT2)
81#define TIMERINTVL30 30 /* interval for checking flush, mark */
82
83#include <sys/ioctl.h>
84#include <sys/stat.h>
85#include <sys/msgbuf.h>
86#include <sys/queue.h>
87#include <sys/sysctl.h>
88#include <sys/un.h>
89#include <sys/time.h>
90#include <sys/resource.h>
91
92#include <netinet/in.h>
93#include <netdb.h>
94#include <arpa/inet.h>
95
96#include <ctype.h>
97#include <err.h>
98#include <errno(*__errno()).h>
99#include <event.h>
100#include <fcntl.h>
101#include <fnmatch.h>
102#include <limits.h>
103#include <paths.h>
104#include <signal.h>
105#include <stdio.h>
106#include <stdlib.h>
107#include <string.h>
108#include <tls.h>
109#include <unistd.h>
110#include <utmp.h>
111#include <vis.h>
112
113#define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b))
114#define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b))
115
116#define SYSLOG_NAMES
117#include <sys/syslog.h>
118
119#include "log.h"
120#include "syslogd.h"
121#include "evbuffer_tls.h"
122
123char *ConfFile = _PATH_LOGCONF"/etc/syslog.conf";
124const char ctty[] = _PATH_CONSOLE"/dev/console";
125
126#define MAXUNAMES20 20 /* maximum number of user names */
127
128
129/*
130 * Flags to logline().
131 */
132
133#define IGN_CONS0x001 0x001 /* don't print on console */
134#define SYNC_FILE0x002 0x002 /* do fsync on file after printing */
135#define ADDDATE0x004 0x004 /* add a date to the message */
136#define MARK0x008 0x008 /* this message is a mark */
137
138/*
139 * This structure represents the files that will have log
140 * copies printed.
141 */
142
143struct filed {
144 SIMPLEQ_ENTRY(filed)struct { struct filed *sqe_next; } f_next; /* next in linked list */
145 int f_type; /* entry type, see below */
146 int f_file; /* file descriptor */
147 time_t f_time; /* time this was last written */
148 u_char f_pmask[LOG_NFACILITIES24+1]; /* priority mask */
149 char *f_program; /* program this applies to */
150 char *f_hostname; /* host this applies to */
151 union {
152 char f_uname[MAXUNAMES20][UT_NAMESIZE32+1];
153 struct {
154 char f_loghost[1+4+3+1+NI_MAXHOST256+1+NI_MAXSERV32];
155 /* @proto46://[hostname]:servname\0 */
156 struct sockaddr_storage f_addr;
157 struct buffertls f_buftls;
158 struct bufferevent *f_bufev;
159 struct tls *f_ctx;
160 char *f_host;
161 int f_reconnectwait;
162 } f_forw; /* forwarding address */
163 char f_fname[PATH_MAX1024];
164 struct {
165 char f_mname[MAX_MEMBUF_NAME64];
166 struct ringbuf *f_rb;
167 int f_overflow;
168 int f_attached;
169 size_t f_len;
170 } f_mb; /* Memory buffer */
171 } f_un;
172 char f_prevline[MAXSVLINE120]; /* last message logged */
173 char f_lasttime[33]; /* time of last occurrence */
174 char f_prevhost[HOST_NAME_MAX255+1]; /* host from which recd. */
175 int f_prevpri; /* pri of f_prevline */
176 int f_prevlen; /* length of f_prevline */
177 int f_prevcount; /* repetition cnt of prevline */
178 unsigned int f_repeatcount; /* number of "repeated" msgs */
179 int f_quick; /* abort when matched */
180 int f_dropped; /* warn, dropped message */
181 time_t f_lasterrtime; /* last error was reported */
182};
183
184/*
185 * Intervals at which we flush out "message repeated" messages,
186 * in seconds after previous message is logged. After each flush,
187 * we move to the next interval until we reach the largest.
188 */
189int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */
190#define MAXREPEAT((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
191#define REPEATTIME(f)((f)->f_time + repeatinterval[(f)->f_repeatcount]) ((f)->f_time + repeatinterval[(f)->f_repeatcount])
192#define BACKOFF(f){ if (++(f)->f_repeatcount > ((sizeof(repeatinterval) /
sizeof(repeatinterval[0])) - 1)) (f)->f_repeatcount = ((sizeof
(repeatinterval) / sizeof(repeatinterval[0])) - 1); }
{ if (++(f)->f_repeatcount > MAXREPEAT((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)) \
193 (f)->f_repeatcount = MAXREPEAT((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1); \
194 }
195
196/* values for f_type */
197#define F_UNUSED0 0 /* unused entry */
198#define F_FILE1 1 /* regular file */
199#define F_TTY2 2 /* terminal */
200#define F_CONSOLE3 3 /* console terminal */
201#define F_FORWUDP4 4 /* remote machine via UDP */
202#define F_USERS5 5 /* list of users */
203#define F_WALL6 6 /* everyone logged on */
204#define F_MEMBUF7 7 /* memory buffer */
205#define F_PIPE8 8 /* pipe to external program */
206#define F_FORWTCP9 9 /* remote machine via TCP */
207#define F_FORWTLS10 10 /* remote machine via TLS */
208
209char *TypeNames[] = {
210 "UNUSED", "FILE", "TTY", "CONSOLE",
211 "FORWUDP", "USERS", "WALL", "MEMBUF",
212 "PIPE", "FORWTCP", "FORWTLS",
213};
214
215SIMPLEQ_HEAD(filed_list, filed)struct filed_list { struct filed *sqh_first; struct filed **sqh_last
; }
Files;
216struct filed consfile;
217
218int Debug; /* debug flag */
219int Foreground; /* run in foreground, instead of daemonizing */
220char LocalHostName[HOST_NAME_MAX255+1]; /* our hostname */
221int Started = 0; /* set after privsep */
222int Initialized = 0; /* set when we have initialized ourselves */
223
224int MarkInterval = 20 * 60; /* interval between marks in seconds */
225int MarkSeq = 0; /* mark sequence number */
226int PrivChild = 0; /* Exec the privileged parent process */
227int Repeat = 0; /* 0 msg repeated, 1 in files only, 2 never */
228int SecureMode = 1; /* when true, speak only unix domain socks */
229int NoDNS = 0; /* when true, refrain from doing DNS lookups */
230int ZuluTime = 0; /* display date and time in UTC ISO format */
231int IncludeHostname = 0; /* include RFC 3164 hostnames when forwarding */
232int Family = PF_UNSPEC0; /* protocol family, may disable IPv4 or IPv6 */
233
234struct tls *server_ctx;
235struct tls_config *client_config, *server_config;
236const char *CAfile = "/etc/ssl/cert.pem"; /* file containing CA certificates */
237int NoVerify = 0; /* do not verify TLS server x509 certificate */
238const char *ClientCertfile = NULL((void*)0);
239const char *ClientKeyfile = NULL((void*)0);
240const char *ServerCAfile = NULL((void*)0);
241int tcpbuf_dropped = 0; /* count messages dropped from TCP or TLS */
242int file_dropped = 0; /* messages dropped due to file system full */
243int init_dropped = 0; /* messages dropped during initialization */
244
245#define CTL_READING_CMD1 1
246#define CTL_WRITING_REPLY2 2
247#define CTL_WRITING_CONT_REPLY3 3
248int ctl_state = 0; /* What the control socket is up to */
249int membuf_drop = 0; /* logs dropped in continuous membuf read */
250
251/*
252 * Client protocol NB. all numeric fields in network byte order
253 */
254#define CTL_VERSION2 2
255
256/* Request */
257struct {
258 u_int32_t version;
259#define CMD_READ1 1 /* Read out log */
260#define CMD_READ_CLEAR2 2 /* Read and clear log */
261#define CMD_CLEAR3 3 /* Clear log */
262#define CMD_LIST4 4 /* List available logs */
263#define CMD_FLAGS5 5 /* Query flags only */
264#define CMD_READ_CONT6 6 /* Read out log continuously */
265 u_int32_t cmd;
266 u_int32_t lines;
267 char logname[MAX_MEMBUF_NAME64];
268} ctl_cmd;
269
270size_t ctl_cmd_bytes = 0; /* number of bytes of ctl_cmd read */
271
272/* Reply */
273struct ctl_reply_hdr {
274 u_int32_t version;
275#define CTL_HDR_FLAG_OVERFLOW0x01 0x01
276 u_int32_t flags;
277 /* Reply text follows, up to MAX_MEMBUF long */
278};
279
280#define CTL_HDR_LEN(sizeof(struct ctl_reply_hdr)) (sizeof(struct ctl_reply_hdr))
281#define CTL_REPLY_MAXSIZE((sizeof(struct ctl_reply_hdr)) + (256 * 1024)) (CTL_HDR_LEN(sizeof(struct ctl_reply_hdr)) + MAX_MEMBUF(256 * 1024))
282#define CTL_REPLY_SIZE(strlen(reply_text) + (sizeof(struct ctl_reply_hdr))) (strlen(reply_text) + CTL_HDR_LEN(sizeof(struct ctl_reply_hdr)))
283
284char *ctl_reply = NULL((void*)0); /* Buffer for control connection reply */
285char *reply_text; /* Start of reply text in buffer */
286size_t ctl_reply_size = 0; /* Number of bytes used in reply */
287size_t ctl_reply_offset = 0; /* Number of bytes of reply written so far */
288
289char *linebuf;
290int linesize;
291
292int fd_ctlconn, fd_udp, fd_udp6, send_udp, send_udp6;
293struct event *ev_ctlaccept, *ev_ctlread, *ev_ctlwrite;
294
295struct peer {
296 struct buffertls p_buftls;
297 struct bufferevent *p_bufev;
298 struct tls *p_ctx;
299 char *p_peername;
300 char *p_hostname;
301 int p_fd;
302};
303char hostname_unknown[] = "???";
304
305void klog_readcb(int, short, void *);
306void udp_readcb(int, short, void *);
307void unix_readcb(int, short, void *);
308int reserve_accept4(int, int, struct event *,
309 void (*)(int, short, void *), struct sockaddr *, socklen_t *, int);
310void tcp_acceptcb(int, short, void *);
311void tls_acceptcb(int, short, void *);
312void acceptcb(int, short, void *, int);
313int octet_counting(struct evbuffer *, char **, int);
314int non_transparent_framing(struct evbuffer *, char **);
315void tcp_readcb(struct bufferevent *, void *);
316void tcp_closecb(struct bufferevent *, short, void *);
317int tcp_socket(struct filed *);
318void tcp_dropcb(struct bufferevent *, void *);
319void tcp_writecb(struct bufferevent *, void *);
320void tcp_errorcb(struct bufferevent *, short, void *);
321void tcp_connectcb(int, short, void *);
322void tcp_connect_retry(struct bufferevent *, struct filed *);
323int tcpbuf_countmsg(struct bufferevent *bufev);
324void die_signalcb(int, short, void *);
325void mark_timercb(int, short, void *);
326void init_signalcb(int, short, void *);
327void ctlsock_acceptcb(int, short, void *);
328void ctlconn_readcb(int, short, void *);
329void ctlconn_writecb(int, short, void *);
330void ctlconn_logto(char *);
331void ctlconn_cleanup(void);
332
333struct filed *cfline(char *, char *, char *);
334void cvthname(struct sockaddr *, char *, size_t);
335int decode(const char *, const CODE *);
336void markit(void);
337void fprintlog(struct filed *, int, char *);
338void dropped_warn(int *, const char *);
339void init(void);
340void logevent(int, const char *);
341void logline(int, int, char *, char *);
342struct filed *find_dup(struct filed *);
343size_t parsepriority(const char *, int *);
344void printline(char *, char *);
345void printsys(char *);
346void usage(void);
347void wallmsg(struct filed *, struct iovec *);
348int loghost_parse(char *, char **, char **, char **);
349int getmsgbufsize(void);
350void address_alloc(const char *, const char *, char ***, char ***, int *);
351int socket_bind(const char *, const char *, const char *, int,
352 int *, int *);
353int unix_socket(char *, int, mode_t);
354void double_sockbuf(int, int, int);
355void set_sockbuf(int);
356void set_keepalive(int);
357void tailify_replytext(char *, int);
358
359int
360main(int argc, char *argv[])
361{
362 struct timeval to;
363 struct event *ev_klog, *ev_sendsys, *ev_udp, *ev_udp6,
364 *ev_bind, *ev_listen, *ev_tls, *ev_unix,
365 *ev_hup, *ev_int, *ev_quit, *ev_term, *ev_mark;
366 sigset_t sigmask;
367 const char *errstr;
368 char *p;
369 int ch, i;
370 int lockpipe[2] = { -1, -1}, pair[2], nullfd, fd;
371 int fd_ctlsock, fd_klog, fd_sendsys, *fd_bind, *fd_listen;
372 int *fd_tls, *fd_unix, nunix, nbind, nlisten, ntls;
373 char **path_unix, *path_ctlsock;
374 char **bind_host, **bind_port, **listen_host, **listen_port;
375 char *tls_hostport, **tls_host, **tls_port;
376
377 /* block signal until handler is set up */
378 sigemptyset(&sigmask);
379 sigaddset(&sigmask, SIGHUP1);
380 if (sigprocmask(SIG_SETMASK3, &sigmask, NULL((void*)0)) == -1)
1
Assuming the condition is false
2
Taking false branch
381 err(1, "sigprocmask block");
382
383 if ((path_unix = malloc(sizeof(*path_unix))) == NULL((void*)0))
3
Memory is allocated
4
Assuming the condition is false
5
Taking false branch
384 err(1, "malloc %s", _PATH_LOG"/dev/log");
385 path_unix[0] = _PATH_LOG"/dev/log";
386 nunix = 1;
387 path_ctlsock = NULL((void*)0);
388
389 bind_host = listen_host = tls_host = NULL((void*)0);
390 bind_port = listen_port = tls_port = NULL((void*)0);
391 tls_hostport = NULL((void*)0);
392 nbind = nlisten = ntls = 0;
393
394 while ((ch = getopt(argc, argv,
6
Assuming the condition is false
7
Loop condition is false. Execution continues on line 483
395 "46a:C:c:dFf:hK:k:m:nP:p:rS:s:T:U:uVZ")) != -1) {
396 switch (ch) {
397 case '4': /* disable IPv6 */
398 Family = PF_INET2;
399 break;
400 case '6': /* disable IPv4 */
401 Family = PF_INET624;
402 break;
403 case 'a':
404 if ((path_unix = reallocarray(path_unix, nunix + 1,
405 sizeof(*path_unix))) == NULL((void*)0))
406 err(1, "unix path %s", optarg);
407 path_unix[nunix++] = optarg;
408 break;
409 case 'C': /* file containing CA certificates */
410 CAfile = optarg;
411 break;
412 case 'c': /* file containing client certificate */
413 ClientCertfile = optarg;
414 break;
415 case 'd': /* debug */
416 Debug++;
417 break;
418 case 'F': /* foreground */
419 Foreground = 1;
420 break;
421 case 'f': /* configuration file */
422 ConfFile = optarg;
423 break;
424 case 'h': /* RFC 3164 hostnames */
425 IncludeHostname = 1;
426 break;
427 case 'K': /* verify client with CA file */
428 ServerCAfile = optarg;
429 break;
430 case 'k': /* file containing client key */
431 ClientKeyfile = optarg;
432 break;
433 case 'm': /* mark interval */
434 MarkInterval = strtonum(optarg, 0, 365*24*60, &errstr);
435 if (errstr)
436 errx(1, "mark_interval %s: %s", errstr, optarg);
437 MarkInterval *= 60;
438 break;
439 case 'n': /* don't do DNS lookups */
440 NoDNS = 1;
441 break;
442 case 'P': /* used internally, exec the parent */
443 PrivChild = strtonum(optarg, 2, INT_MAX2147483647, &errstr);
444 if (errstr)
445 errx(1, "priv child %s: %s", errstr, optarg);
446 break;
447 case 'p': /* path */
448 path_unix[0] = optarg;
449 break;
450 case 'r':
451 Repeat++;
452 break;
453 case 'S': /* allow tls and listen on address */
454 if (tls_hostport == NULL((void*)0))
455 tls_hostport = optarg;
456 address_alloc("tls", optarg, &tls_host, &tls_port,
457 &ntls);
458 break;
459 case 's':
460 path_ctlsock = optarg;
461 break;
462 case 'T': /* allow tcp and listen on address */
463 address_alloc("listen", optarg, &listen_host,
464 &listen_port, &nlisten);
465 break;
466 case 'U': /* allow udp only from address */
467 address_alloc("bind", optarg, &bind_host, &bind_port,
468 &nbind);
469 break;
470 case 'u': /* allow udp input port */
471 SecureMode = 0;
472 break;
473 case 'V': /* do not verify certificates */
474 NoVerify = 1;
475 break;
476 case 'Z': /* time stamps in UTC ISO format */
477 ZuluTime = 1;
478 break;
479 default:
480 usage();
481 }
482 }
483 if (argc != optind)
8
Assuming 'argc' is equal to 'optind'
9
Taking false branch
484 usage();
485
486 log_init(Debug, LOG_SYSLOG(5<<3));
487 log_procinit("syslogd");
488 if (Debug)
10
Assuming 'Debug' is not equal to 0
11
Taking true branch
489 setvbuf(stdout(&__sF[1]), NULL((void*)0), _IOLBF1, 0);
490
491 if ((nullfd = open(_PATH_DEVNULL"/dev/null", O_RDWR0x0002)) == -1)
12
Assuming the condition is false
13
Taking false branch
492 fatal("open %s", _PATH_DEVNULL"/dev/null");
493 for (fd = nullfd + 1; fd <= STDERR_FILENO2; fd++) {
14
Assuming 'fd' is > STDERR_FILENO
15
Loop condition is false. Execution continues on line 499
494 if (fcntl(fd, F_GETFL3) == -1 && errno(*__errno()) == EBADF9)
495 if (dup2(nullfd, fd) == -1)
496 fatal("dup2 null");
497 }
498
499 if (PrivChild > 1)
16
Assuming 'PrivChild' is <= 1
17
Taking false branch
500 priv_exec(ConfFile, NoDNS, PrivChild, argc, argv);
501
502 consfile.f_type = F_CONSOLE3;
503 (void)strlcpy(consfile.f_un.f_fname, ctty,
504 sizeof(consfile.f_un.f_fname));
505 consfile.f_file = open(consfile.f_un.f_fname, O_WRONLY0x0001|O_NONBLOCK0x0004);
506 if (consfile.f_file == -1)
18
Assuming the condition is false
19
Taking false branch
507 log_warn("open %s", consfile.f_un.f_fname);
508
509 if (gethostname(LocalHostName, sizeof(LocalHostName)) == -1 ||
20
Assuming the condition is true
510 LocalHostName[0] == '\0')
511 strlcpy(LocalHostName, "-", sizeof(LocalHostName));
512 else if ((p = strchr(LocalHostName, '.')) != NULL((void*)0))
513 *p = '\0';
514
515 /* Reserve space for kernel message buffer plus buffer full message. */
516 linesize = getmsgbufsize() + 64;
517 if (linesize < LOG_MAXLINE8192)
21
Assuming 'linesize' is < LOG_MAXLINE
22
Taking true branch
518 linesize = LOG_MAXLINE8192;
519 linesize++;
520 if ((linebuf = malloc(linesize)) == NULL((void*)0))
23
Assuming the condition is false
24
Taking false branch
521 fatal("allocate line buffer");
522
523 if (socket_bind("udp", NULL((void*)0), "syslog", SecureMode,
25
Assuming the condition is false
26
Taking false branch
524 &fd_udp, &fd_udp6) == -1)
525 log_warnx("socket bind * failed");
526 if ((fd_bind = reallocarray(NULL((void*)0), nbind, sizeof(*fd_bind))) == NULL((void*)0))
27
Assuming the condition is false
28
Taking false branch
527 fatal("allocate bind fd");
528 for (i = 0; i < nbind; i++) {
29
Loop condition is false. Execution continues on line 533
529 if (socket_bind("udp", bind_host[i], bind_port[i], 0,
530 &fd_bind[i], &fd_bind[i]) == -1)
531 log_warnx("socket bind udp failed");
532 }
533 if ((fd_listen = reallocarray(NULL((void*)0), nlisten, sizeof(*fd_listen)))
30
Assuming the condition is false
31
Taking false branch
534 == NULL((void*)0))
535 fatal("allocate listen fd");
536 for (i = 0; i < nlisten; i++) {
32
Loop condition is false. Execution continues on line 541
537 if (socket_bind("tcp", listen_host[i], listen_port[i], 0,
538 &fd_listen[i], &fd_listen[i]) == -1)
539 log_warnx("socket listen tcp failed");
540 }
541 if ((fd_tls = reallocarray(NULL((void*)0), ntls, sizeof(*fd_tls))) == NULL((void*)0))
33
Assuming the condition is false
34
Taking false branch
542 fatal("allocate tls fd");
543 for (i = 0; i < ntls; i++) {
35
Loop condition is false. Execution continues on line 549
544 if (socket_bind("tls", tls_host[i], tls_port[i], 0,
545 &fd_tls[i], &fd_tls[i]) == -1)
546 log_warnx("socket listen tls failed");
547 }
548
549 if ((fd_unix = reallocarray(NULL((void*)0), nunix, sizeof(*fd_unix))) == NULL((void*)0))
36
Assuming the condition is false
37
Taking false branch
550 fatal("allocate unix fd");
551 for (i = 0; i < nunix; i++) {
38
Loop condition is true. Entering loop body
41
Loop condition is false. Execution continues on line 561
552 fd_unix[i] = unix_socket(path_unix[i], SOCK_DGRAM2, 0666);
553 if (fd_unix[i] == -1) {
39
Assuming the condition is false
40
Taking false branch
554 if (i == 0)
555 log_warnx("log socket %s failed", path_unix[i]);
556 continue;
557 }
558 double_sockbuf(fd_unix[i], SO_RCVBUF0x1002, 0);
559 }
560
561 if (socketpair(AF_UNIX1, SOCK_DGRAM2, PF_UNSPEC0, pair) == -1) {
42
Potential leak of memory pointed to by 'path_unix'
562 log_warn("socketpair sendsyslog");
563 fd_sendsys = -1;
564 } else {
565 /*
566 * Avoid to lose messages from sendsyslog(2). A larger
567 * 1 MB socket buffer compensates bursts.
568 */
569 double_sockbuf(pair[0], SO_RCVBUF0x1002, 1<<20);
570 double_sockbuf(pair[1], SO_SNDBUF0x1001, 1<<20);
571 fd_sendsys = pair[0];
572 }
573
574 fd_ctlsock = fd_ctlconn = -1;
575 if (path_ctlsock != NULL((void*)0)) {
576 fd_ctlsock = unix_socket(path_ctlsock, SOCK_STREAM1, 0600);
577 if (fd_ctlsock == -1) {
578 log_warnx("control socket %s failed", path_ctlsock);
579 } else {
580 if (listen(fd_ctlsock, 5) == -1) {
581 log_warn("listen control socket");
582 close(fd_ctlsock);
583 fd_ctlsock = -1;
584 }
585 }
586 }
587
588 if ((fd_klog = open(_PATH_KLOG"/dev/klog", O_RDONLY0x0000)) == -1) {
589 log_warn("open %s", _PATH_KLOG"/dev/klog");
590 } else if (fd_sendsys != -1) {
591 /* Use /dev/klog to register sendsyslog(2) receiver. */
592 if (ioctl(fd_klog, LIOCSFD((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('l')) << 8) | ((127)))
, &pair[1]) == -1)
593 log_warn("ioctl klog LIOCSFD sendsyslog");
594 }
595 if (fd_sendsys != -1)
596 close(pair[1]);
597
598 if ((client_config = tls_config_new()) == NULL((void*)0))
599 log_warn("tls_config_new client");
600 if (tls_hostport) {
601 if ((server_config = tls_config_new()) == NULL((void*)0))
602 log_warn("tls_config_new server");
603 if ((server_ctx = tls_server()) == NULL((void*)0)) {
604 log_warn("tls_server");
605 for (i = 0; i < ntls; i++)
606 close(fd_tls[i]);
607 free(fd_tls);
608 fd_tls = NULL((void*)0);
609 free(tls_host);
610 free(tls_port);
611 tls_host = tls_port = NULL((void*)0);
612 ntls = 0;
613 }
614 }
615
616 if (client_config) {
617 if (NoVerify) {
618 tls_config_insecure_noverifycert(client_config);
619 tls_config_insecure_noverifyname(client_config);
620 } else {
621 if (tls_config_set_ca_file(client_config,
622 CAfile) == -1) {
623 log_warnx("load client TLS CA: %s",
624 tls_config_error(client_config));
625 /* avoid reading default certs in chroot */
626 tls_config_set_ca_mem(client_config, "", 0);
627 } else
628 log_debug("CAfile %s", CAfile);
629 }
630 if (ClientCertfile && ClientKeyfile) {
631 if (tls_config_set_cert_file(client_config,
632 ClientCertfile) == -1)
633 log_warnx("load client TLS cert: %s",
634 tls_config_error(client_config));
635 else
636 log_debug("ClientCertfile %s", ClientCertfile);
637
638 if (tls_config_set_key_file(client_config,
639 ClientKeyfile) == -1)
640 log_warnx("load client TLS key: %s",
641 tls_config_error(client_config));
642 else
643 log_debug("ClientKeyfile %s", ClientKeyfile);
644 } else if (ClientCertfile || ClientKeyfile) {
645 log_warnx("options -c and -k must be used together");
646 }
647 if (tls_config_set_protocols(client_config,
648 TLS_PROTOCOLS_ALL((1 << 1)|(1 << 2)| (1 << 3)|(1 << 4)
)
) != 0)
649 log_warnx("set client TLS protocols: %s",
650 tls_config_error(client_config));
651 if (tls_config_set_ciphers(client_config, "all") != 0)
652 log_warnx("set client TLS ciphers: %s",
653 tls_config_error(client_config));
654 }
655 if (server_config && server_ctx) {
656 const char *names[2];
657
658 names[0] = tls_hostport;
659 names[1] = tls_host[0];
660
661 for (i = 0; i < 2; i++) {
662 if (asprintf(&p, "/etc/ssl/private/%s.key", names[i])
663 == -1)
664 continue;
665 if (tls_config_set_key_file(server_config, p) == -1) {
666 log_warnx("load server TLS key: %s",
667 tls_config_error(server_config));
668 free(p);
669 continue;
670 }
671 log_debug("Keyfile %s", p);
672 free(p);
673 if (asprintf(&p, "/etc/ssl/%s.crt", names[i]) == -1)
674 continue;
675 if (tls_config_set_cert_file(server_config, p) == -1) {
676 log_warnx("load server TLS cert: %s",
677 tls_config_error(server_config));
678 free(p);
679 continue;
680 }
681 log_debug("Certfile %s", p);
682 free(p);
683 break;
684 }
685
686 if (ServerCAfile) {
687 if (tls_config_set_ca_file(server_config,
688 ServerCAfile) == -1) {
689 log_warnx("load server TLS CA: %s",
690 tls_config_error(server_config));
691 /* avoid reading default certs in chroot */
692 tls_config_set_ca_mem(server_config, "", 0);
693 } else
694 log_debug("Server CAfile %s", ServerCAfile);
695 tls_config_verify_client(server_config);
696 }
697 if (tls_config_set_protocols(server_config,
698 TLS_PROTOCOLS_ALL((1 << 1)|(1 << 2)| (1 << 3)|(1 << 4)
)
) != 0)
699 log_warnx("set server TLS protocols: %s",
700 tls_config_error(server_config));
701 if (tls_config_set_ciphers(server_config, "compat") != 0)
702 log_warnx("Set server TLS ciphers: %s",
703 tls_config_error(server_config));
704 if (tls_configure(server_ctx, server_config) != 0) {
705 log_warnx("tls_configure server: %s",
706 tls_error(server_ctx));
707 tls_free(server_ctx);
708 server_ctx = NULL((void*)0);
709 for (i = 0; i < ntls; i++)
710 close(fd_tls[i]);
711 free(fd_tls);
712 fd_tls = NULL((void*)0);
713 free(tls_host);
714 free(tls_port);
715 tls_host = tls_port = NULL((void*)0);
716 ntls = 0;
717 }
718 }
719
720 log_debug("off & running....");
721
722 if (!Debug && !Foreground) {
723 char c;
724
725 pipe(lockpipe);
726
727 switch(fork()) {
728 case -1:
729 err(1, "fork");
730 case 0:
731 setsid();
732 close(lockpipe[0]);
733 break;
734 default:
735 close(lockpipe[1]);
736 read(lockpipe[0], &c, 1);
737 _exit(0);
738 }
739 }
740
741 /* tuck my process id away */
742 if (!Debug) {
743 FILE *fp;
744
745 fp = fopen(_PATH_LOGPID"/var/run/syslog.pid", "w");
746 if (fp != NULL((void*)0)) {
747 fprintf(fp, "%ld\n", (long)getpid());
748 (void) fclose(fp);
749 }
750 }
751
752 /* Privilege separation begins here */
753 priv_init(lockpipe[1], nullfd, argc, argv);
754
755 if (pledge("stdio unix inet recvfd", NULL((void*)0)) == -1)
756 err(1, "pledge");
757
758 Started = 1;
759
760 /* Process is now unprivileged and inside a chroot */
761 if (Debug)
762 event_set_log_callback(logevent);
763 event_init();
764
765 if ((ev_ctlaccept = malloc(sizeof(struct event))) == NULL((void*)0) ||
766 (ev_ctlread = malloc(sizeof(struct event))) == NULL((void*)0) ||
767 (ev_ctlwrite = malloc(sizeof(struct event))) == NULL((void*)0) ||
768 (ev_klog = malloc(sizeof(struct event))) == NULL((void*)0) ||
769 (ev_sendsys = malloc(sizeof(struct event))) == NULL((void*)0) ||
770 (ev_udp = malloc(sizeof(struct event))) == NULL((void*)0) ||
771 (ev_udp6 = malloc(sizeof(struct event))) == NULL((void*)0) ||
772 (ev_bind = reallocarray(NULL((void*)0), nbind, sizeof(struct event)))
773 == NULL((void*)0) ||
774 (ev_listen = reallocarray(NULL((void*)0), nlisten, sizeof(struct event)))
775 == NULL((void*)0) ||
776 (ev_tls = reallocarray(NULL((void*)0), ntls, sizeof(struct event)))
777 == NULL((void*)0) ||
778 (ev_unix = reallocarray(NULL((void*)0), nunix, sizeof(struct event)))
779 == NULL((void*)0) ||
780 (ev_hup = malloc(sizeof(struct event))) == NULL((void*)0) ||
781 (ev_int = malloc(sizeof(struct event))) == NULL((void*)0) ||
782 (ev_quit = malloc(sizeof(struct event))) == NULL((void*)0) ||
783 (ev_term = malloc(sizeof(struct event))) == NULL((void*)0) ||
784 (ev_mark = malloc(sizeof(struct event))) == NULL((void*)0))
785 err(1, "malloc");
786
787 event_set(ev_ctlaccept, fd_ctlsock, EV_READ0x02|EV_PERSIST0x10,
788 ctlsock_acceptcb, ev_ctlaccept);
789 event_set(ev_ctlread, fd_ctlconn, EV_READ0x02|EV_PERSIST0x10,
790 ctlconn_readcb, ev_ctlread);
791 event_set(ev_ctlwrite, fd_ctlconn, EV_WRITE0x04|EV_PERSIST0x10,
792 ctlconn_writecb, ev_ctlwrite);
793 event_set(ev_klog, fd_klog, EV_READ0x02|EV_PERSIST0x10, klog_readcb, ev_klog);
794 event_set(ev_sendsys, fd_sendsys, EV_READ0x02|EV_PERSIST0x10, unix_readcb,
795 ev_sendsys);
796 event_set(ev_udp, fd_udp, EV_READ0x02|EV_PERSIST0x10, udp_readcb, ev_udp);
797 event_set(ev_udp6, fd_udp6, EV_READ0x02|EV_PERSIST0x10, udp_readcb, ev_udp6);
798 for (i = 0; i < nbind; i++)
799 event_set(&ev_bind[i], fd_bind[i], EV_READ0x02|EV_PERSIST0x10,
800 udp_readcb, &ev_bind[i]);
801 for (i = 0; i < nlisten; i++)
802 event_set(&ev_listen[i], fd_listen[i], EV_READ0x02|EV_PERSIST0x10,
803 tcp_acceptcb, &ev_listen[i]);
804 for (i = 0; i < ntls; i++)
805 event_set(&ev_tls[i], fd_tls[i], EV_READ0x02|EV_PERSIST0x10,
806 tls_acceptcb, &ev_tls[i]);
807 for (i = 0; i < nunix; i++)
808 event_set(&ev_unix[i], fd_unix[i], EV_READ0x02|EV_PERSIST0x10,
809 unix_readcb, &ev_unix[i]);
810
811 signal_set(ev_hup, SIGHUP, init_signalcb, ev_hup)event_set(ev_hup, 1, 0x08|0x10, init_signalcb, ev_hup);
812 signal_set(ev_int, SIGINT, die_signalcb, ev_int)event_set(ev_int, 2, 0x08|0x10, die_signalcb, ev_int);
813 signal_set(ev_quit, SIGQUIT, die_signalcb, ev_quit)event_set(ev_quit, 3, 0x08|0x10, die_signalcb, ev_quit);
814 signal_set(ev_term, SIGTERM, die_signalcb, ev_term)event_set(ev_term, 15, 0x08|0x10, die_signalcb, ev_term);
815
816 evtimer_set(ev_mark, mark_timercb, ev_mark)event_set(ev_mark, -1, 0, mark_timercb, ev_mark);
817
818 init();
819
820 /* Allocate ctl socket reply buffer if we have a ctl socket */
821 if (fd_ctlsock != -1 &&
822 (ctl_reply = malloc(CTL_REPLY_MAXSIZE((sizeof(struct ctl_reply_hdr)) + (256 * 1024)))) == NULL((void*)0))
823 fatal("allocate control socket reply buffer");
824 reply_text = ctl_reply + CTL_HDR_LEN(sizeof(struct ctl_reply_hdr));
825
826 if (!Debug) {
827 close(lockpipe[1]);
828 dup2(nullfd, STDIN_FILENO0);
829 dup2(nullfd, STDOUT_FILENO1);
830 dup2(nullfd, STDERR_FILENO2);
831 }
832 if (nullfd > 2)
833 close(nullfd);
834
835 /*
836 * Signal to the priv process that the initial config parsing is done
837 * so that it will reject any future attempts to open more files
838 */
839 priv_config_parse_done();
840
841 if (fd_ctlsock != -1)
842 event_add(ev_ctlaccept, NULL((void*)0));
843 if (fd_klog != -1)
844 event_add(ev_klog, NULL((void*)0));
845 if (fd_sendsys != -1)
846 event_add(ev_sendsys, NULL((void*)0));
847 if (!SecureMode) {
848 if (fd_udp != -1)
849 event_add(ev_udp, NULL((void*)0));
850 if (fd_udp6 != -1)
851 event_add(ev_udp6, NULL((void*)0));
852 }
853 for (i = 0; i < nbind; i++)
854 if (fd_bind[i] != -1)
855 event_add(&ev_bind[i], NULL((void*)0));
856 for (i = 0; i < nlisten; i++)
857 if (fd_listen[i] != -1)
858 event_add(&ev_listen[i], NULL((void*)0));
859 for (i = 0; i < ntls; i++)
860 if (fd_tls[i] != -1)
861 event_add(&ev_tls[i], NULL((void*)0));
862 for (i = 0; i < nunix; i++)
863 if (fd_unix[i] != -1)
864 event_add(&ev_unix[i], NULL((void*)0));
865
866 signal_add(ev_hup, NULL)event_add(ev_hup, ((void*)0));
867 signal_add(ev_term, NULL)event_add(ev_term, ((void*)0));
868 if (Debug || Foreground) {
869 signal_add(ev_int, NULL)event_add(ev_int, ((void*)0));
870 signal_add(ev_quit, NULL)event_add(ev_quit, ((void*)0));
871 } else {
872 (void)signal(SIGINT2, SIG_IGN(void (*)(int))1);
873 (void)signal(SIGQUIT3, SIG_IGN(void (*)(int))1);
874 }
875 (void)signal(SIGCHLD20, SIG_IGN(void (*)(int))1);
876 (void)signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
877
878 to.tv_sec = TIMERINTVL30;
879 to.tv_usec = 0;
880 evtimer_add(ev_mark, &to)event_add(ev_mark, &to);
881
882 log_info(LOG_INFO6, "start");
883 log_debug("syslogd: started");
884
885 sigemptyset(&sigmask);
886 if (sigprocmask(SIG_SETMASK3, &sigmask, NULL((void*)0)) == -1)
887 err(1, "sigprocmask unblock");
888
889 /* Send message via libc, flushes log stash in kernel. */
890 openlog("syslogd", LOG_PID0x01, LOG_SYSLOG(5<<3));
891 syslog(LOG_DEBUG7, "running");
892
893 event_dispatch();
894 /* NOTREACHED */
895 return (0);
896}
897
898void
899address_alloc(const char *name, const char *address, char ***host,
900 char ***port, int *num)
901{
902 char *p;
903
904 /* do not care about memory leak, argv has to be preserved */
905 if ((p = strdup(address)) == NULL((void*)0))
906 err(1, "%s address %s", name, address);
907 if ((*host = reallocarray(*host, *num + 1, sizeof(**host))) == NULL((void*)0))
908 err(1, "%s host %s", name, address);
909 if ((*port = reallocarray(*port, *num + 1, sizeof(**port))) == NULL((void*)0))
910 err(1, "%s port %s", name, address);
911 if (loghost_parse(p, NULL((void*)0), *host + *num, *port + *num) == -1)
912 errx(1, "bad %s address: %s", name, address);
913 (*num)++;
914}
915
916int
917socket_bind(const char *proto, const char *host, const char *port,
918 int shutread, int *fd, int *fd6)
919{
920 struct addrinfo hints, *res, *res0;
921 char hostname[NI_MAXHOST256], servname[NI_MAXSERV32];
922 int *fdp, error, reuseaddr;
923
924 *fd = *fd6 = -1;
925 if (proto == NULL((void*)0))
926 proto = "udp";
927 if (port == NULL((void*)0))
928 port = strcmp(proto, "tls") == 0 ? "syslog-tls" : "syslog";
929
930 memset(&hints, 0, sizeof(hints));
931 hints.ai_family = Family;
932 if (strcmp(proto, "udp") == 0) {
933 hints.ai_socktype = SOCK_DGRAM2;
934 hints.ai_protocol = IPPROTO_UDP17;
935 } else {
936 hints.ai_socktype = SOCK_STREAM1;
937 hints.ai_protocol = IPPROTO_TCP6;
938 }
939 hints.ai_flags = AI_PASSIVE1;
940
941 if ((error = getaddrinfo(host, port, &hints, &res0))) {
942 log_warnx("getaddrinfo proto %s, host %s, port %s: %s",
943 proto, host ? host : "*", port, gai_strerror(error));
944 return (-1);
945 }
946
947 for (res = res0; res; res = res->ai_next) {
948 switch (res->ai_family) {
949 case AF_INET2:
950 fdp = fd;
951 break;
952 case AF_INET624:
953 fdp = fd6;
954 break;
955 default:
956 continue;
957 }
958 if (*fdp >= 0)
959 continue;
960
961 if ((*fdp = socket(res->ai_family,
962 res->ai_socktype | SOCK_NONBLOCK0x4000, res->ai_protocol)) == -1)
963 continue;
964
965 if (getnameinfo(res->ai_addr, res->ai_addrlen, hostname,
966 sizeof(hostname), servname, sizeof(servname),
967 NI_NUMERICHOST1 | NI_NUMERICSERV2 |
968 (res->ai_socktype == SOCK_DGRAM2 ? NI_DGRAM16 : 0)) != 0) {
969 log_debug("Malformed bind address");
970 hostname[0] = servname[0] = '\0';
971 }
972 if (shutread && shutdown(*fdp, SHUT_RD0) == -1) {
973 log_warn("shutdown SHUT_RD "
974 "protocol %d, address %s, portnum %s",
975 res->ai_protocol, hostname, servname);
976 close(*fdp);
977 *fdp = -1;
978 continue;
979 }
980 if (!shutread && res->ai_protocol == IPPROTO_UDP17)
981 double_sockbuf(*fdp, SO_RCVBUF0x1002, 0);
982 else if (res->ai_protocol == IPPROTO_TCP6) {
983 set_sockbuf(*fdp);
984 set_keepalive(*fdp);
985 }
986 reuseaddr = 1;
987 if (setsockopt(*fdp, SOL_SOCKET0xffff, SO_REUSEADDR0x0004, &reuseaddr,
988 sizeof(reuseaddr)) == -1) {
989 log_warn("setsockopt SO_REUSEADDR "
990 "protocol %d, address %s, portnum %s",
991 res->ai_protocol, hostname, servname);
992 close(*fdp);
993 *fdp = -1;
994 continue;
995 }
996 if (bind(*fdp, res->ai_addr, res->ai_addrlen) == -1) {
997 log_warn("bind protocol %d, address %s, portnum %s",
998 res->ai_protocol, hostname, servname);
999 close(*fdp);
1000 *fdp = -1;
1001 continue;
1002 }
1003 if (!shutread && res->ai_protocol == IPPROTO_TCP6 &&
1004 listen(*fdp, 10) == -1) {
1005 log_warn("listen protocol %d, address %s, portnum %s",
1006 res->ai_protocol, hostname, servname);
1007 close(*fdp);
1008 *fdp = -1;
1009 continue;
1010 }
1011 }
1012
1013 freeaddrinfo(res0);
1014
1015 if (*fd == -1 && *fd6 == -1)
1016 return (-1);
1017 return (0);
1018}
1019
1020void
1021klog_readcb(int fd, short event, void *arg)
1022{
1023 struct event *ev = arg;
1024 ssize_t n;
1025
1026 n = read(fd, linebuf, linesize - 1);
1027 if (n > 0) {
1028 linebuf[n] = '\0';
1029 printsys(linebuf);
1030 } else if (n == -1 && errno(*__errno()) != EINTR4) {
1031 log_warn("read klog");
1032 event_del(ev);
1033 }
1034}
1035
1036void
1037udp_readcb(int fd, short event, void *arg)
1038{
1039 struct sockaddr_storage sa;
1040 socklen_t salen;
1041 ssize_t n;
1042
1043 salen = sizeof(sa);
1044 n = recvfrom(fd, linebuf, LOG_MAXLINE8192, 0, (struct sockaddr *)&sa,
1045 &salen);
1046 if (n > 0) {
1047 char resolve[NI_MAXHOST256];
1048
1049 linebuf[n] = '\0';
1050 cvthname((struct sockaddr *)&sa, resolve, sizeof(resolve));
1051 log_debug("cvthname res: %s", resolve);
1052 printline(resolve, linebuf);
1053 } else if (n == -1 && errno(*__errno()) != EINTR4 && errno(*__errno()) != EWOULDBLOCK35)
1054 log_warn("recvfrom udp");
1055}
1056
1057void
1058unix_readcb(int fd, short event, void *arg)
1059{
1060 struct sockaddr_un sa;
1061 socklen_t salen;
1062 ssize_t n;
1063
1064 salen = sizeof(sa);
1065 n = recvfrom(fd, linebuf, LOG_MAXLINE8192, 0, (struct sockaddr *)&sa,
1066 &salen);
1067 if (n > 0) {
1068 linebuf[n] = '\0';
1069 printline(LocalHostName, linebuf);
1070 } else if (n == -1 && errno(*__errno()) != EINTR4 && errno(*__errno()) != EWOULDBLOCK35)
1071 log_warn("recvfrom unix");
1072}
1073
1074int
1075reserve_accept4(int lfd, int event, struct event *ev,
1076 void (*cb)(int, short, void *),
1077 struct sockaddr *sa, socklen_t *salen, int flags)
1078{
1079 struct timeval to = { 1, 0 };
1080 int afd;
1081
1082 if (event & EV_TIMEOUT0x01) {
1083 log_debug("Listen again");
1084 /* Enable the listen event, there is no timeout anymore. */
1085 event_set(ev, lfd, EV_READ0x02|EV_PERSIST0x10, cb, ev);
1086 event_add(ev, NULL((void*)0));
1087 errno(*__errno()) = EWOULDBLOCK35;
1088 return (-1);
1089 }
1090
1091 if (getdtablecount() + FD_RESERVE5 >= getdtablesize()) {
1092 afd = -1;
1093 errno(*__errno()) = EMFILE24;
1094 } else
1095 afd = accept4(lfd, sa, salen, flags);
1096
1097 if (afd == -1 && (errno(*__errno()) == ENFILE23 || errno(*__errno()) == EMFILE24)) {
1098 log_info(LOG_WARNING4, "accept deferred: %s", strerror(errno(*__errno())));
1099 /*
1100 * Disable the listen event and convert it to a timeout.
1101 * Pass the listen file descriptor to the callback.
1102 */
1103 event_del(ev);
1104 event_set(ev, lfd, 0, cb, ev);
1105 event_add(ev, &to);
1106 return (-1);
1107 }
1108
1109 return (afd);
1110}
1111
1112void
1113tcp_acceptcb(int lfd, short event, void *arg)
1114{
1115 acceptcb(lfd, event, arg, 0);
1116}
1117
1118void
1119tls_acceptcb(int lfd, short event, void *arg)
1120{
1121 acceptcb(lfd, event, arg, 1);
1122}
1123
1124void
1125acceptcb(int lfd, short event, void *arg, int usetls)
1126{
1127 struct event *ev = arg;
1128 struct peer *p;
1129 struct sockaddr_storage ss;
1130 socklen_t sslen;
1131 char hostname[NI_MAXHOST256], servname[NI_MAXSERV32];
1132 char *peername;
1133 int fd;
1134
1135 sslen = sizeof(ss);
1136 if ((fd = reserve_accept4(lfd, event, ev, tcp_acceptcb,
1137 (struct sockaddr *)&ss, &sslen, SOCK_NONBLOCK0x4000)) == -1) {
1138 if (errno(*__errno()) != ENFILE23 && errno(*__errno()) != EMFILE24 &&
1139 errno(*__errno()) != EINTR4 && errno(*__errno()) != EWOULDBLOCK35 &&
1140 errno(*__errno()) != ECONNABORTED53)
1141 log_warn("accept tcp socket");
1142 return;
1143 }
1144 log_debug("Accepting tcp connection");
1145
1146 if (getnameinfo((struct sockaddr *)&ss, sslen, hostname,
1147 sizeof(hostname), servname, sizeof(servname),
1148 NI_NUMERICHOST1 | NI_NUMERICSERV2) != 0 ||
1149 asprintf(&peername, ss.ss_family == AF_INET624 ?
1150 "[%s]:%s" : "%s:%s", hostname, servname) == -1) {
1151 log_debug("Malformed accept address");
1152 peername = hostname_unknown;
1153 }
1154 log_debug("Peer addresss and port %s", peername);
1155 if ((p = malloc(sizeof(*p))) == NULL((void*)0)) {
1156 log_warn("allocate \"%s\"", peername);
1157 close(fd);
1158 return;
1159 }
1160 p->p_fd = fd;
1161 if ((p->p_bufev = bufferevent_new(fd, tcp_readcb, NULL((void*)0), tcp_closecb,
1162 p)) == NULL((void*)0)) {
1163 log_warn("bufferevent \"%s\"", peername);
1164 free(p);
1165 close(fd);
1166 return;
1167 }
1168 p->p_ctx = NULL((void*)0);
1169 if (usetls) {
1170 if (tls_accept_socket(server_ctx, &p->p_ctx, fd) == -1) {
1171 log_warnx("tls_accept_socket \"%s\": %s",
1172 peername, tls_error(server_ctx));
1173 bufferevent_free(p->p_bufev);
1174 free(p);
1175 close(fd);
1176 return;
1177 }
1178 buffertls_set(&p->p_buftls, p->p_bufev, p->p_ctx, fd);
1179 buffertls_accept(&p->p_buftls, fd);
1180 log_debug("tcp accept callback: tls context success");
1181 }
1182 if (!NoDNS && peername != hostname_unknown &&
1183 priv_getnameinfo((struct sockaddr *)&ss, ss.ss_len, hostname,
1184 sizeof(hostname)) != 0) {
1185 log_debug("Host name for accept address (%s) unknown",
1186 hostname);
1187 }
1188 if (peername == hostname_unknown ||
1189 (p->p_hostname = strdup(hostname)) == NULL((void*)0))
1190 p->p_hostname = hostname_unknown;
1191 log_debug("Peer hostname %s", hostname);
1192 p->p_peername = peername;
1193 bufferevent_enable(p->p_bufev, EV_READ0x02);
1194
1195 log_info(LOG_DEBUG7, "%s logger \"%s\" accepted",
1196 p->p_ctx ? "tls" : "tcp", peername);
1197}
1198
1199/*
1200 * Syslog over TCP RFC 6587 3.4.1. Octet Counting
1201 */
1202int
1203octet_counting(struct evbuffer *evbuf, char **msg, int drain)
1204{
1205 char *p, *buf, *end;
1206 int len;
1207
1208 buf = EVBUFFER_DATA(evbuf)(evbuf)->buffer;
1209 end = buf + EVBUFFER_LENGTH(evbuf)(evbuf)->off;
1210 /*
1211 * It can be assumed that octet-counting framing is used if a syslog
1212 * frame starts with a digit.
1213 */
1214 if (buf >= end || !isdigit((unsigned char)*buf))
1215 return (-1);
1216 /*
1217 * SYSLOG-FRAME = MSG-LEN SP SYSLOG-MSG
1218 * MSG-LEN is the octet count of the SYSLOG-MSG in the SYSLOG-FRAME.
1219 * We support up to 5 digits in MSG-LEN, so the maximum is 99999.
1220 */
1221 for (p = buf; p < end && p < buf + 5; p++) {
1222 if (!isdigit((unsigned char)*p))
1223 break;
1224 }
1225 if (buf >= p || p >= end || *p != ' ')
1226 return (-1);
1227 p++;
1228 /* Using atoi() is safe as buf starts with 1 to 5 digits and a space. */
1229 len = atoi(buf);
1230 if (drain)
1231 log_debugadd(" octet counting %d", len);
1232 if (p + len > end)
1233 return (0);
1234 if (drain)
1235 evbuffer_drain(evbuf, p - buf);
1236 if (msg)
1237 *msg = p;
1238 return (len);
1239}
1240
1241/*
1242 * Syslog over TCP RFC 6587 3.4.2. Non-Transparent-Framing
1243 */
1244int
1245non_transparent_framing(struct evbuffer *evbuf, char **msg)
1246{
1247 char *p, *buf, *end;
1248
1249 buf = EVBUFFER_DATA(evbuf)(evbuf)->buffer;
1250 end = buf + EVBUFFER_LENGTH(evbuf)(evbuf)->off;
1251 /*
1252 * The TRAILER has usually been a single character and most often
1253 * is ASCII LF (%d10). However, other characters have also been
1254 * seen, with ASCII NUL (%d00) being a prominent example.
1255 */
1256 for (p = buf; p < end; p++) {
1257 if (*p == '\0' || *p == '\n')
1258 break;
1259 }
1260 if (p + 1 - buf >= INT_MAX2147483647)
1261 return (-1);
1262 log_debugadd(" non transparent framing");
1263 if (p >= end)
1264 return (0);
1265 /*
1266 * Some devices have also been seen to emit a two-character
1267 * TRAILER, which is usually CR and LF.
1268 */
1269 if (buf < p && p[0] == '\n' && p[-1] == '\r')
1270 p[-1] = '\0';
1271 if (msg)
1272 *msg = buf;
1273 return (p + 1 - buf);
1274}
1275
1276void
1277tcp_readcb(struct bufferevent *bufev, void *arg)
1278{
1279 struct peer *p = arg;
1280 char *msg;
1281 int len;
1282
1283 while (EVBUFFER_LENGTH(bufev->input)(bufev->input)->off > 0) {
1284 log_debugadd("%s logger \"%s\"", p->p_ctx ? "tls" : "tcp",
1285 p->p_peername);
1286 msg = NULL((void*)0);
1287 len = octet_counting(bufev->input, &msg, 1);
1288 if (len < 0)
1289 len = non_transparent_framing(bufev->input, &msg);
1290 if (len < 0)
1291 log_debugadd("unknown method");
1292 if (msg == NULL((void*)0)) {
1293 log_debugadd(", incomplete frame");
1294 break;
1295 }
1296 log_debug(", use %d bytes", len);
1297 if (len > 0 && msg[len-1] == '\n')
1298 msg[len-1] = '\0';
1299 if (len == 0 || msg[len-1] != '\0') {
1300 memcpy(linebuf, msg, MINIMUM(len, LOG_MAXLINE)(((len) < (8192)) ? (len) : (8192)));
1301 linebuf[MINIMUM(len, LOG_MAXLINE)(((len) < (8192)) ? (len) : (8192))] = '\0';
1302 msg = linebuf;
1303 }
1304 printline(p->p_hostname, msg);
1305 evbuffer_drain(bufev->input, len);
1306 }
1307 /* Maximum frame has 5 digits, 1 space, MAXLINE chars, 1 new line. */
1308 if (EVBUFFER_LENGTH(bufev->input)(bufev->input)->off >= 5 + 1 + LOG_MAXLINE8192 + 1) {
1309 log_debug(", use %zu bytes", EVBUFFER_LENGTH(bufev->input)(bufev->input)->off);
1310 EVBUFFER_DATA(bufev->input)(bufev->input)->buffer[5 + 1 + LOG_MAXLINE8192] = '\0';
1311 printline(p->p_hostname, EVBUFFER_DATA(bufev->input)(bufev->input)->buffer);
1312 evbuffer_drain(bufev->input, -1);
1313 } else if (EVBUFFER_LENGTH(bufev->input)(bufev->input)->off > 0)
1314 log_debug(", buffer %zu bytes", EVBUFFER_LENGTH(bufev->input)(bufev->input)->off);
1315}
1316
1317void
1318tcp_closecb(struct bufferevent *bufev, short event, void *arg)
1319{
1320 struct peer *p = arg;
1321
1322 if (event & EVBUFFER_EOF0x10) {
1323 log_info(LOG_DEBUG7, "%s logger \"%s\" connection close",
1324 p->p_ctx ? "tls" : "tcp", p->p_peername);
1325 } else {
1326 log_info(LOG_NOTICE5, "%s logger \"%s\" connection error: %s",
1327 p->p_ctx ? "tls" : "tcp", p->p_peername,
1328 p->p_ctx ? tls_error(p->p_ctx) : strerror(errno(*__errno())));
1329 }
1330
1331 if (p->p_peername != hostname_unknown)
1332 free(p->p_peername);
1333 if (p->p_hostname != hostname_unknown)
1334 free(p->p_hostname);
1335 bufferevent_free(p->p_bufev);
1336 close(p->p_fd);
1337 free(p);
1338}
1339
1340int
1341tcp_socket(struct filed *f)
1342{
1343 int s;
1344
1345 if ((s = socket(f->f_un.f_forw.f_addr.ss_family,
1346 SOCK_STREAM1 | SOCK_NONBLOCK0x4000, IPPROTO_TCP6)) == -1) {
1347 log_warn("socket \"%s\"", f->f_un.f_forw.f_loghost);
1348 return (-1);
1349 }
1350 set_sockbuf(s);
1351 if (connect(s, (struct sockaddr *)&f->f_un.f_forw.f_addr,
1352 f->f_un.f_forw.f_addr.ss_len) == -1 && errno(*__errno()) != EINPROGRESS36) {
1353 log_warn("connect \"%s\"", f->f_un.f_forw.f_loghost);
1354 close(s);
1355 return (-1);
1356 }
1357 return (s);
1358}
1359
1360void
1361tcp_dropcb(struct bufferevent *bufev, void *arg)
1362{
1363 struct filed *f = arg;
1364
1365 /*
1366 * Drop data received from the forward log server.
1367 */
1368 log_debug("loghost \"%s\" did send %zu bytes back",
1369 f->f_un.f_forw.f_loghost, EVBUFFER_LENGTH(bufev->input)(bufev->input)->off);
1370 evbuffer_drain(bufev->input, -1);
1371}
1372
1373void
1374tcp_writecb(struct bufferevent *bufev, void *arg)
1375{
1376 struct filed *f = arg;
1377 char ebuf[ERRBUFSIZE256];
1378
1379 /*
1380 * Successful write, connection to server is good, reset wait time.
1381 */
1382 log_debug("loghost \"%s\" successful write", f->f_un.f_forw.f_loghost);
1383 f->f_un.f_forw.f_reconnectwait = 0;
1384
1385 if (f->f_dropped > 0 &&
1386 EVBUFFER_LENGTH(f->f_un.f_forw.f_bufev->output)(f->f_un.f_forw.f_bufev->output)->off < MAX_TCPBUF(256 * 1024)) {
1387 snprintf(ebuf, sizeof(ebuf), "to loghost \"%s\"",
1388 f->f_un.f_forw.f_loghost);
1389 dropped_warn(&f->f_dropped, ebuf);
1390 }
1391}
1392
1393void
1394tcp_errorcb(struct bufferevent *bufev, short event, void *arg)
1395{
1396 struct filed *f = arg;
1397 char *p, *buf, *end;
1398 int l;
1399 char ebuf[ERRBUFSIZE256];
1400
1401 if (event & EVBUFFER_EOF0x10)
1402 snprintf(ebuf, sizeof(ebuf), "loghost \"%s\" connection close",
1403 f->f_un.f_forw.f_loghost);
1404 else
1405 snprintf(ebuf, sizeof(ebuf),
1406 "loghost \"%s\" connection error: %s",
1407 f->f_un.f_forw.f_loghost, f->f_un.f_forw.f_ctx ?
1408 tls_error(f->f_un.f_forw.f_ctx) : strerror(errno(*__errno())));
1409 log_debug("%s", ebuf);
1410
1411 /* The SIGHUP handler may also close the socket, so invalidate it. */
1412 if (f->f_un.f_forw.f_ctx) {
1413 tls_close(f->f_un.f_forw.f_ctx);
1414 tls_free(f->f_un.f_forw.f_ctx);
1415 f->f_un.f_forw.f_ctx = NULL((void*)0);
1416 }
1417 close(f->f_file);
1418 f->f_file = -1;
1419
1420 /*
1421 * The messages in the output buffer may be out of sync.
1422 * Check that the buffer starts with "1234 <1234 octets>\n".
1423 * Otherwise remove the partial message from the beginning.
1424 */
1425 buf = EVBUFFER_DATA(bufev->output)(bufev->output)->buffer;
1426 end = buf + EVBUFFER_LENGTH(bufev->output)(bufev->output)->off;
1427 if (buf < end && !((l = octet_counting(bufev->output, &p, 0)) > 0 &&
1428 p[l-1] == '\n')) {
1429 for (p = buf; p < end; p++) {
1430 if (*p == '\n') {
1431 evbuffer_drain(bufev->output, p - buf + 1);
1432 break;
1433 }
1434 }
1435 /* Without '\n' discard everything. */
1436 if (p == end)
1437 evbuffer_drain(bufev->output, -1);
1438 log_debug("loghost \"%s\" dropped partial message",
1439 f->f_un.f_forw.f_loghost);
1440 f->f_dropped++;
1441 }
1442
1443 tcp_connect_retry(bufev, f);
1444
1445 /* Log the connection error to the fresh buffer after reconnecting. */
1446 log_info(LOG_WARNING4, "%s", ebuf);
1447}
1448
1449void
1450tcp_connectcb(int fd, short event, void *arg)
1451{
1452 struct filed *f = arg;
1453 struct bufferevent *bufev = f->f_un.f_forw.f_bufev;
1454 int s;
1455
1456 if ((s = tcp_socket(f)) == -1) {
1457 tcp_connect_retry(bufev, f);
1458 return;
1459 }
1460 log_debug("tcp connect callback: socket success, event %#x", event);
1461 f->f_file = s;
1462
1463 bufferevent_setfd(bufev, s);
1464 bufferevent_setcb(bufev, tcp_dropcb, tcp_writecb, tcp_errorcb, f);
1465 /*
1466 * Although syslog is a write only protocol, enable reading from
1467 * the socket to detect connection close and errors.
1468 */
1469 bufferevent_enable(bufev, EV_READ0x02|EV_WRITE0x04);
1470
1471 if (f->f_type == F_FORWTLS10) {
1472 if ((f->f_un.f_forw.f_ctx = tls_client()) == NULL((void*)0)) {
1473 log_warn("tls_client \"%s\"", f->f_un.f_forw.f_loghost);
1474 goto error;
1475 }
1476 if (client_config &&
1477 tls_configure(f->f_un.f_forw.f_ctx, client_config) == -1) {
1478 log_warnx("tls_configure \"%s\": %s",
1479 f->f_un.f_forw.f_loghost,
1480 tls_error(f->f_un.f_forw.f_ctx));
1481 goto error;
1482 }
1483 if (tls_connect_socket(f->f_un.f_forw.f_ctx, s,
1484 f->f_un.f_forw.f_host) == -1) {
1485 log_warnx("tls_connect_socket \"%s\": %s",
1486 f->f_un.f_forw.f_loghost,
1487 tls_error(f->f_un.f_forw.f_ctx));
1488 goto error;
1489 }
1490 log_debug("tcp connect callback: tls context success");
1491
1492 buffertls_set(&f->f_un.f_forw.f_buftls, bufev,
1493 f->f_un.f_forw.f_ctx, s);
1494 buffertls_connect(&f->f_un.f_forw.f_buftls, s);
1495 }
1496
1497 return;
1498
1499 error:
1500 if (f->f_un.f_forw.f_ctx) {
1501 tls_free(f->f_un.f_forw.f_ctx);
1502 f->f_un.f_forw.f_ctx = NULL((void*)0);
1503 }
1504 close(f->f_file);
1505 f->f_file = -1;
1506 tcp_connect_retry(bufev, f);
1507}
1508
1509void
1510tcp_connect_retry(struct bufferevent *bufev, struct filed *f)
1511{
1512 struct timeval to;
1513
1514 if (f->f_un.f_forw.f_reconnectwait == 0)
1515 f->f_un.f_forw.f_reconnectwait = 1;
1516 else
1517 f->f_un.f_forw.f_reconnectwait <<= 1;
1518 if (f->f_un.f_forw.f_reconnectwait > 600)
1519 f->f_un.f_forw.f_reconnectwait = 600;
1520 to.tv_sec = f->f_un.f_forw.f_reconnectwait;
1521 to.tv_usec = 0;
1522
1523 log_debug("tcp connect retry: wait %d",
1524 f->f_un.f_forw.f_reconnectwait);
1525 bufferevent_setfd(bufev, -1);
1526 /* We can reuse the write event as bufferevent is disabled. */
1527 evtimer_set(&bufev->ev_write, tcp_connectcb, f)event_set(&bufev->ev_write, -1, 0, tcp_connectcb, f);
1528 evtimer_add(&bufev->ev_write, &to)event_add(&bufev->ev_write, &to);
1529}
1530
1531int
1532tcpbuf_countmsg(struct bufferevent *bufev)
1533{
1534 char *p, *buf, *end;
1535 int i = 0;
1536
1537 buf = EVBUFFER_DATA(bufev->output)(bufev->output)->buffer;
1538 end = buf + EVBUFFER_LENGTH(bufev->output)(bufev->output)->off;
1539 for (p = buf; p < end; p++) {
1540 if (*p == '\n')
1541 i++;
1542 }
1543 return (i);
1544}
1545
1546void
1547usage(void)
1548{
1549
1550 (void)fprintf(stderr(&__sF[2]),
1551 "usage: syslogd [-46dFhnruVZ] [-a path] [-C CAfile]\n"
1552 "\t[-c cert_file] [-f config_file] [-K CAfile] [-k key_file]\n"
1553 "\t[-m mark_interval] [-p log_socket] [-S listen_address]\n"
1554 "\t[-s reporting_socket] [-T listen_address] [-U bind_address]\n");
1555 exit(1);
1556}
1557
1558/*
1559 * Parse a priority code of the form "<123>" into pri, and return the
1560 * length of the priority code including the surrounding angle brackets.
1561 */
1562size_t
1563parsepriority(const char *msg, int *pri)
1564{
1565 size_t nlen;
1566 char buf[11];
1567 const char *errstr;
1568 int maybepri;
1569
1570 if (*msg++ == '<') {
1571 nlen = strspn(msg, "1234567890");
1572 if (nlen > 0 && nlen < sizeof(buf) && msg[nlen] == '>') {
1573 strlcpy(buf, msg, nlen + 1);
1574 maybepri = strtonum(buf, 0, INT_MAX2147483647, &errstr);
1575 if (errstr == NULL((void*)0)) {
1576 *pri = maybepri;
1577 return nlen + 2;
1578 }
1579 }
1580 }
1581
1582 return 0;
1583}
1584
1585/*
1586 * Take a raw input line, decode the message, and print the message
1587 * on the appropriate log files.
1588 */
1589void
1590printline(char *hname, char *msg)
1591{
1592 int pri;
1593 char *p, *q, line[LOG_MAXLINE8192 + 4 + 1]; /* message, encoding, NUL */
1594
1595 /* test for special codes */
1596 pri = DEFUPRI((1<<3)|5);
1597 p = msg;
1598 p += parsepriority(p, &pri);
1599 if (pri &~ (LOG_FACMASK0x03f8|LOG_PRIMASK0x07))
1600 pri = DEFUPRI((1<<3)|5);
1601
1602 /*
1603 * Don't allow users to log kernel messages.
1604 * NOTE: since LOG_KERN == 0 this will also match
1605 * messages with no facility specified.
1606 */
1607 if (LOG_FAC(pri)(((pri) & 0x03f8) >> 3) == LOG_KERN(0<<3))
1608 pri = LOG_USER(1<<3) | LOG_PRI(pri)((pri) & 0x07);
1609
1610 for (q = line; *p && q < &line[LOG_MAXLINE8192]; p++) {
1611 if (*p == '\n')
1612 *q++ = ' ';
1613 else
1614 q = vis(q, *p, 0, 0);
1615 }
1616 line[LOG_MAXLINE8192] = *q = '\0';
1617
1618 logline(pri, 0, hname, line);
1619}
1620
1621/*
1622 * Take a raw input line from /dev/klog, split and format similar to syslog().
1623 */
1624void
1625printsys(char *msg)
1626{
1627 int c, pri, flags;
1628 char *lp, *p, *q, line[LOG_MAXLINE8192 + 1];
1629 size_t prilen;
1630 int l;
1631
1632 l = snprintf(line, sizeof(line), "%s: ", _PATH_UNIX"/bsd");
1633 if (l < 0 || l >= sizeof(line)) {
1634 line[0] = '\0';
1635 l = 0;
1636 }
1637 lp = line + l;
1638 for (p = msg; *p != '\0'; ) {
1639 flags = SYNC_FILE0x002 | ADDDATE0x004; /* fsync file after write */
1640 pri = DEFSPRI((0<<3)|2);
1641 prilen = parsepriority(p, &pri);
1642 p += prilen;
1643 if (prilen == 0) {
1644 /* kernel printf's come out on console */
1645 flags |= IGN_CONS0x001;
1646 }
1647 if (pri &~ (LOG_FACMASK0x03f8|LOG_PRIMASK0x07))
1648 pri = DEFSPRI((0<<3)|2);
1649
1650 q = lp;
1651 while (*p && (c = *p++) != '\n' && q < &line[sizeof(line) - 4])
1652 q = vis(q, c, 0, 0);
1653
1654 logline(pri, flags, LocalHostName, line);
1655 }
1656}
1657
1658void
1659vlogmsg(int pri, const char *proc, const char *fmt, va_list ap)
1660{
1661 char msg[ERRBUFSIZE256];
1662 int l;
1663
1664 l = snprintf(msg, sizeof(msg), "%s[%d]: ", proc, getpid());
1665 if (l < 0 || l >= sizeof(msg))
1666 l = 0;
1667 l = vsnprintf(msg + l, sizeof(msg) - l, fmt, ap);
1668 if (l < 0)
1669 strlcpy(msg, fmt, sizeof(msg));
1670
1671 if (!Started) {
1672 fprintf(stderr(&__sF[2]), "%s\n", msg);
1673 init_dropped++;
1674 return;
1675 }
1676 logline(pri, ADDDATE0x004, LocalHostName, msg);
1677}
1678
1679struct timeval now;
1680
1681/*
1682 * Log a message to the appropriate log files, users, etc. based on
1683 * the priority.
1684 */
1685void
1686logline(int pri, int flags, char *from, char *msg)
1687{
1688 struct filed *f;
1689 int fac, msglen, prilev, i;
1690 char timestamp[33];
1691 char prog[NAME_MAX255+1];
1692
1693 log_debug("logline: pri 0%o, flags 0x%x, from %s, msg %s",
1694 pri, flags, from, msg);
1695
1696 /*
1697 * Check to see if msg looks non-standard.
1698 */
1699 timestamp[0] = '\0';
1700 msglen = strlen(msg);
1701 if ((flags & ADDDATE0x004) == 0) {
1702 if (msglen >= 16 && msg[3] == ' ' && msg[6] == ' ' &&
1703 msg[9] == ':' && msg[12] == ':' && msg[15] == ' ') {
1704 /* BSD syslog TIMESTAMP, RFC 3164 */
1705 strlcpy(timestamp, msg, 16);
1706 msg += 16;
1707 msglen -= 16;
1708 if (ZuluTime)
1709 flags |= ADDDATE0x004;
1710 } else if (msglen >= 20 &&
1711 isdigit(msg[0]) && isdigit(msg[1]) && isdigit(msg[2]) &&
1712 isdigit(msg[3]) && msg[4] == '-' &&
1713 isdigit(msg[5]) && isdigit(msg[6]) && msg[7] == '-' &&
1714 isdigit(msg[8]) && isdigit(msg[9]) && msg[10] == 'T' &&
1715 isdigit(msg[11]) && isdigit(msg[12]) && msg[13] == ':' &&
1716 isdigit(msg[14]) && isdigit(msg[15]) && msg[16] == ':' &&
1717 isdigit(msg[17]) && isdigit(msg[18]) && (msg[19] == '.' ||
1718 msg[19] == 'Z' || msg[19] == '+' || msg[19] == '-')) {
1719 /* FULL-DATE "T" FULL-TIME, RFC 5424 */
1720 strlcpy(timestamp, msg, sizeof(timestamp));
1721 msg += 19;
1722 msglen -= 19;
1723 i = 0;
1724 if (msglen >= 3 && msg[0] == '.' && isdigit(msg[1])) {
1725 /* TIME-SECFRAC */
1726 msg += 2;
1727 msglen -= 2;
1728 i += 2;
1729 while(i < 7 && msglen >= 1 && isdigit(msg[0])) {
1730 msg++;
1731 msglen--;
1732 i++;
1733 }
1734 }
1735 if (msglen >= 2 && msg[0] == 'Z' && msg[1] == ' ') {
1736 /* "Z" */
1737 timestamp[20+i] = '\0';
1738 msg += 2;
1739 msglen -= 2;
1740 } else if (msglen >= 7 &&
1741 (msg[0] == '+' || msg[0] == '-') &&
1742 isdigit(msg[1]) && isdigit(msg[2]) &&
1743 msg[3] == ':' &&
1744 isdigit(msg[4]) && isdigit(msg[5]) &&
1745 msg[6] == ' ') {
1746 /* TIME-NUMOFFSET */
1747 timestamp[25+i] = '\0';
1748 msg += 7;
1749 msglen -= 7;
1750 } else {
1751 /* invalid time format, roll back */
1752 timestamp[0] = '\0';
1753 msg -= 19 + i;
1754 msglen += 19 + i;
1755 flags |= ADDDATE0x004;
1756 }
1757 } else if (msglen >= 2 && msg[0] == '-' && msg[1] == ' ') {
1758 /* NILVALUE, RFC 5424 */
1759 msg += 2;
1760 msglen -= 2;
1761 flags |= ADDDATE0x004;
1762 } else
1763 flags |= ADDDATE0x004;
1764 }
1765
1766 (void)gettimeofday(&now, NULL((void*)0));
1767 if (flags & ADDDATE0x004) {
1768 if (ZuluTime) {
1769 struct tm *tm;
1770 size_t l;
1771
1772 tm = gmtime(&now.tv_sec);
1773 l = strftime(timestamp, sizeof(timestamp), "%FT%T", tm);
1774 /*
1775 * Use only millisecond precision as some time has
1776 * passed since syslog(3) was called.
1777 */
1778 snprintf(timestamp + l, sizeof(timestamp) - l,
1779 ".%03ldZ", now.tv_usec / 1000);
1780 } else
1781 strlcpy(timestamp, ctime(&now.tv_sec) + 4, 16);
1782 }
1783
1784 /* extract facility and priority level */
1785 if (flags & MARK0x008)
1786 fac = LOG_NFACILITIES24;
1787 else {
1788 fac = LOG_FAC(pri)(((pri) & 0x03f8) >> 3);
1789 if (fac >= LOG_NFACILITIES24 || fac < 0)
1790 fac = LOG_USER(1<<3);
1791 }
1792 prilev = LOG_PRI(pri)((pri) & 0x07);
1793
1794 /* extract program name */
1795 while (isspace((unsigned char)*msg)) {
1796 msg++;
1797 msglen--;
1798 }
1799 for (i = 0; i < NAME_MAX255; i++) {
1800 if (!isalnum((unsigned char)msg[i]) &&
1801 msg[i] != '-' && msg[i] != '.' && msg[i] != '_')
1802 break;
1803 prog[i] = msg[i];
1804 }
1805 prog[i] = 0;
1806
1807 /* log the message to the particular outputs */
1808 if (!Initialized) {
1809 f = &consfile;
1810 if (f->f_type == F_CONSOLE3) {
1811 strlcpy(f->f_lasttime, timestamp,
1812 sizeof(f->f_lasttime));
1813 strlcpy(f->f_prevhost, from,
1814 sizeof(f->f_prevhost));
1815 fprintlog(f, flags, msg);
1816 /* May be set to F_UNUSED, try again next time. */
1817 f->f_type = F_CONSOLE3;
1818 }
1819 init_dropped++;
1820 return;
1821 }
1822 SIMPLEQ_FOREACH(f, &Files, f_next)for((f) = ((&Files)->sqh_first); (f) != ((void*)0); (f
) = ((f)->f_next.sqe_next))
{
1823 /* skip messages that are incorrect priority */
1824 if (f->f_pmask[fac] < prilev ||
1825 f->f_pmask[fac] == INTERNAL_NOPRI0x10)
1826 continue;
1827
1828 /* skip messages with the incorrect program or hostname */
1829 if (f->f_program && fnmatch(f->f_program, prog, 0) != 0)
1830 continue;
1831 if (f->f_hostname && fnmatch(f->f_hostname, from, 0) != 0)
1832 continue;
1833
1834 if (f->f_type == F_CONSOLE3 && (flags & IGN_CONS0x001))
1835 continue;
1836
1837 /* don't output marks to recently written files */
1838 if ((flags & MARK0x008) &&
1839 (now.tv_sec - f->f_time) < MarkInterval / 2)
1840 continue;
1841
1842 /*
1843 * suppress duplicate lines to this file
1844 */
1845 if ((Repeat == 0 || (Repeat == 1 &&
1846 (f->f_type != F_PIPE8 && f->f_type != F_FORWUDP4 &&
1847 f->f_type != F_FORWTCP9 && f->f_type != F_FORWTLS10))) &&
1848 (flags & MARK0x008) == 0 && msglen == f->f_prevlen &&
1849 !strcmp(msg, f->f_prevline) &&
1850 !strcmp(from, f->f_prevhost)) {
1851 strlcpy(f->f_lasttime, timestamp,
1852 sizeof(f->f_lasttime));
1853 f->f_prevcount++;
1854 log_debug("msg repeated %d times, %ld sec of %d",
1855 f->f_prevcount, (long)(now.tv_sec - f->f_time),
1856 repeatinterval[f->f_repeatcount]);
1857 /*
1858 * If domark would have logged this by now,
1859 * flush it now (so we don't hold isolated messages),
1860 * but back off so we'll flush less often
1861 * in the future.
1862 */
1863 if (now.tv_sec > REPEATTIME(f)((f)->f_time + repeatinterval[(f)->f_repeatcount])) {
1864 fprintlog(f, flags, (char *)NULL((void*)0));
1865 BACKOFF(f){ if (++(f)->f_repeatcount > ((sizeof(repeatinterval) /
sizeof(repeatinterval[0])) - 1)) (f)->f_repeatcount = ((sizeof
(repeatinterval) / sizeof(repeatinterval[0])) - 1); }
;
1866 }
1867 } else {
1868 /* new line, save it */
1869 if (f->f_prevcount)
1870 fprintlog(f, 0, (char *)NULL((void*)0));
1871 f->f_repeatcount = 0;
1872 f->f_prevpri = pri;
1873 strlcpy(f->f_lasttime, timestamp,
1874 sizeof(f->f_lasttime));
1875 strlcpy(f->f_prevhost, from,
1876 sizeof(f->f_prevhost));
1877 if (msglen < MAXSVLINE120) {
1878 f->f_prevlen = msglen;
1879 strlcpy(f->f_prevline, msg,
1880 sizeof(f->f_prevline));
1881 fprintlog(f, flags, (char *)NULL((void*)0));
1882 } else {
1883 f->f_prevline[0] = 0;
1884 f->f_prevlen = 0;
1885 fprintlog(f, flags, msg);
1886 }
1887 }
1888
1889 if (f->f_quick)
1890 break;
1891 }
1892}
1893
1894void
1895fprintlog(struct filed *f, int flags, char *msg)
1896{
1897 struct iovec iov[IOVCNT7], *v;
1898 struct msghdr msghdr;
1899 int l, retryonce;
1900 char line[LOG_MAXLINE8192 + 1], pribuf[13], greetings[500], repbuf[80];
1901 char ebuf[ERRBUFSIZE256];
1902
1903 v = iov;
1904 switch (f->f_type) {
1905 case F_FORWUDP4:
1906 case F_FORWTCP9:
1907 case F_FORWTLS10:
1908 l = snprintf(pribuf, sizeof(pribuf), "<%d>", f->f_prevpri);
1909 if (l < 0)
1910 l = strlcpy(pribuf, "<13>", sizeof(pribuf));
1911 if (l >= sizeof(pribuf))
1912 l = sizeof(pribuf) - 1;
1913 v->iov_base = pribuf;
1914 v->iov_len = l;
1915 break;
1916 case F_WALL6:
1917 l = snprintf(greetings, sizeof(greetings),
1918 "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
1919 f->f_prevhost, ctime(&now.tv_sec));
1920 if (l < 0)
1921 l = strlcpy(greetings,
1922 "\r\n\7Message from syslogd ...\r\n",
1923 sizeof(greetings));
1924 if (l >= sizeof(greetings))
1925 l = sizeof(greetings) - 1;
1926 v->iov_base = greetings;
1927 v->iov_len = l;
1928 break;
1929 default:
1930 v->iov_base = "";
1931 v->iov_len = 0;
1932 break;
1933 }
1934 v++;
1935
1936 if (f->f_lasttime[0] != '\0') {
1937 v->iov_base = f->f_lasttime;
1938 v->iov_len = strlen(f->f_lasttime);
1939 v++;
1940 v->iov_base = " ";
1941 v->iov_len = 1;
1942 } else {
1943 v->iov_base = "";
1944 v->iov_len = 0;
1945 v++;
1946 v->iov_base = "";
1947 v->iov_len = 0;
1948 }
1949 v++;
1950
1951 switch (f->f_type) {
1952 case F_FORWUDP4:
1953 case F_FORWTCP9:
1954 case F_FORWTLS10:
1955 if (IncludeHostname) {
1956 v->iov_base = LocalHostName;
1957 v->iov_len = strlen(LocalHostName);
1958 v++;
1959 v->iov_base = " ";
1960 v->iov_len = 1;
1961 } else {
1962 /* XXX RFC requires to include host name */
1963 v->iov_base = "";
1964 v->iov_len = 0;
1965 v++;
1966 v->iov_base = "";
1967 v->iov_len = 0;
1968 }
1969 break;
1970 default:
1971 if (f->f_prevhost[0] != '\0') {
1972 v->iov_base = f->f_prevhost;
1973 v->iov_len = strlen(v->iov_base);
1974 v++;
1975 v->iov_base = " ";
1976 v->iov_len = 1;
1977 } else {
1978 v->iov_base = "";
1979 v->iov_len = 0;
1980 v++;
1981 v->iov_base = "";
1982 v->iov_len = 0;
1983 }
1984 break;
1985 }
1986 v++;
1987
1988 if (msg) {
1989 v->iov_base = msg;
1990 v->iov_len = strlen(msg);
1991 } else if (f->f_prevcount > 1) {
1992 l = snprintf(repbuf, sizeof(repbuf),
1993 "last message repeated %d times", f->f_prevcount);
1994 if (l < 0)
1995 l = strlcpy(repbuf, "last message repeated",
1996 sizeof(repbuf));
1997 if (l >= sizeof(repbuf))
1998 l = sizeof(repbuf) - 1;
1999 v->iov_base = repbuf;
2000 v->iov_len = l;
2001 } else {
2002 v->iov_base = f->f_prevline;
2003 v->iov_len = f->f_prevlen;
2004 }
2005 v++;
2006
2007 switch (f->f_type) {
2008 case F_CONSOLE3:
2009 case F_TTY2:
2010 case F_USERS5:
2011 case F_WALL6:
2012 v->iov_base = "\r\n";
2013 v->iov_len = 2;
2014 break;
2015 case F_FILE1:
2016 case F_PIPE8:
2017 case F_FORWTCP9:
2018 case F_FORWTLS10:
2019 v->iov_base = "\n";
2020 v->iov_len = 1;
2021 break;
2022 default:
2023 v->iov_base = "";
2024 v->iov_len = 0;
2025 break;
2026 }
2027 v = NULL((void*)0);
2028
2029 log_debugadd("Logging to %s", TypeNames[f->f_type]);
2030 f->f_time = now.tv_sec;
2031
2032 switch (f->f_type) {
2033 case F_UNUSED0:
2034 log_debug("%s", "");
2035 break;
2036
2037 case F_FORWUDP4:
2038 log_debug(" %s", f->f_un.f_forw.f_loghost);
2039 l = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len +
2040 iov[3].iov_len + iov[4].iov_len + iov[5].iov_len +
2041 iov[6].iov_len;
2042 if (l > MAX_UDPMSG1180) {
2043 l -= MAX_UDPMSG1180;
2044 if (iov[5].iov_len > l)
2045 iov[5].iov_len -= l;
2046 else
2047 iov[5].iov_len = 0;
2048 }
2049 memset(&msghdr, 0, sizeof(msghdr));
2050 msghdr.msg_name = &f->f_un.f_forw.f_addr;
2051 msghdr.msg_namelen = f->f_un.f_forw.f_addr.ss_len;
2052 msghdr.msg_iov = iov;
2053 msghdr.msg_iovlen = IOVCNT7;
2054 if (sendmsg(f->f_file, &msghdr, 0) == -1) {
2055 switch (errno(*__errno())) {
2056 case EADDRNOTAVAIL49:
2057 case EHOSTDOWN64:
2058 case EHOSTUNREACH65:
2059 case ENETDOWN50:
2060 case ENETUNREACH51:
2061 case ENOBUFS55:
2062 case EWOULDBLOCK35:
2063 /* silently dropped */
2064 break;
2065 default:
2066 f->f_type = F_UNUSED0;
2067 log_warn("sendmsg to \"%s\"",
2068 f->f_un.f_forw.f_loghost);
2069 break;
2070 }
2071 }
2072 break;
2073
2074 case F_FORWTCP9:
2075 case F_FORWTLS10:
2076 log_debugadd(" %s", f->f_un.f_forw.f_loghost);
2077 if (EVBUFFER_LENGTH(f->f_un.f_forw.f_bufev->output)(f->f_un.f_forw.f_bufev->output)->off >=
2078 MAX_TCPBUF(256 * 1024)) {
2079 log_debug(" (dropped)");
2080 f->f_dropped++;
2081 break;
2082 }
2083 /*
2084 * Syslog over TLS RFC 5425 4.3. Sending Data
2085 * Syslog over TCP RFC 6587 3.4.1. Octet Counting
2086 * Use an additional '\n' to split messages. This allows
2087 * buffer synchronisation, helps legacy implementations,
2088 * and makes line based testing easier.
2089 */
2090 l = evbuffer_add_printf(f->f_un.f_forw.f_bufev->output,
2091 "%zu %s%s%s%s%s%s%s", iov[0].iov_len +
2092 iov[1].iov_len + iov[2].iov_len +
2093 iov[3].iov_len + iov[4].iov_len +
2094 iov[5].iov_len + iov[6].iov_len,
2095 (char *)iov[0].iov_base,
2096 (char *)iov[1].iov_base, (char *)iov[2].iov_base,
2097 (char *)iov[3].iov_base, (char *)iov[4].iov_base,
2098 (char *)iov[5].iov_base, (char *)iov[6].iov_base);
2099 if (l < 0) {
2100 log_debug(" (dropped evbuffer_add_printf)");
2101 f->f_dropped++;
2102 break;
2103 }
2104 bufferevent_enable(f->f_un.f_forw.f_bufev, EV_WRITE0x04);
2105 log_debug("%s", "");
2106 break;
2107
2108 case F_CONSOLE3:
2109 if (flags & IGN_CONS0x001) {
2110 log_debug(" (ignored)");
2111 break;
2112 }
2113 /* FALLTHROUGH */
2114 case F_TTY2:
2115 case F_FILE1:
2116 case F_PIPE8:
2117 log_debug(" %s", f->f_un.f_fname);
2118 retryonce = 0;
2119 again:
2120 if (writev(f->f_file, iov, IOVCNT7) == -1) {
2121 int e = errno(*__errno());
2122
2123 /* allow to recover from file system full */
2124 if (e == ENOSPC28 && f->f_type == F_FILE1) {
2125 if (f->f_dropped++ == 0) {
2126 f->f_type = F_UNUSED0;
2127 errno(*__errno()) = e;
2128 log_warn("write to file \"%s\"",
2129 f->f_un.f_fname);
2130 f->f_type = F_FILE1;
2131 }
2132 break;
2133 }
2134
2135 /* pipe is non-blocking. log and drop message if full */
2136 if (e == EAGAIN35 && f->f_type == F_PIPE8) {
2137 if (now.tv_sec - f->f_lasterrtime > 120) {
2138 f->f_lasterrtime = now.tv_sec;
2139 log_warn("write to pipe \"%s\"",
2140 f->f_un.f_fname);
2141 }
2142 break;
2143 }
2144
2145 /*
2146 * Check for errors on TTY's or program pipes.
2147 * Errors happen due to loss of tty or died programs.
2148 */
2149 if (e == EAGAIN35) {
2150 /*
2151 * Silently drop messages on blocked write.
2152 * This can happen when logging to a locked tty.
2153 */
2154 break;
2155 }
2156
2157 (void)close(f->f_file);
2158 if ((e == EIO5 || e == EBADF9) &&
2159 f->f_type != F_FILE1 && f->f_type != F_PIPE8 &&
2160 !retryonce) {
2161 f->f_file = priv_open_tty(f->f_un.f_fname);
2162 retryonce = 1;
2163 if (f->f_file < 0) {
2164 f->f_type = F_UNUSED0;
2165 log_warn("priv_open_tty \"%s\"",
2166 f->f_un.f_fname);
2167 } else
2168 goto again;
2169 } else if ((e == EPIPE32 || e == EBADF9) &&
2170 f->f_type == F_PIPE8 && !retryonce) {
2171 f->f_file = priv_open_log(f->f_un.f_fname);
2172 retryonce = 1;
2173 if (f->f_file < 0) {
2174 f->f_type = F_UNUSED0;
2175 log_warn("priv_open_log \"%s\"",
2176 f->f_un.f_fname);
2177 } else
2178 goto again;
2179 } else {
2180 f->f_type = F_UNUSED0;
2181 f->f_file = -1;
2182 errno(*__errno()) = e;
2183 log_warn("writev \"%s\"", f->f_un.f_fname);
2184 }
2185 } else {
2186 if (flags & SYNC_FILE0x002)
2187 (void)fsync(f->f_file);
2188 if (f->f_dropped && f->f_type == F_FILE1) {
2189 snprintf(ebuf, sizeof(ebuf), "to file \"%s\"",
2190 f->f_un.f_fname);
2191 dropped_warn(&f->f_dropped, ebuf);
2192 }
2193 }
2194 break;
2195
2196 case F_USERS5:
2197 case F_WALL6:
2198 log_debug("%s", "");
2199 wallmsg(f, iov);
2200 break;
2201
2202 case F_MEMBUF7:
2203 log_debug("%s", "");
2204 l = snprintf(line, sizeof(line),
2205 "%s%s%s%s%s%s%s", (char *)iov[0].iov_base,
2206 (char *)iov[1].iov_base, (char *)iov[2].iov_base,
2207 (char *)iov[3].iov_base, (char *)iov[4].iov_base,
2208 (char *)iov[5].iov_base, (char *)iov[6].iov_base);
2209 if (l < 0)
2210 l = strlcpy(line, iov[5].iov_base, sizeof(line));
2211 if (ringbuf_append_line(f->f_un.f_mb.f_rb, line) == 1)
2212 f->f_un.f_mb.f_overflow = 1;
2213 if (f->f_un.f_mb.f_attached)
2214 ctlconn_logto(line);
2215 break;
2216 }
2217 f->f_prevcount = 0;
2218}
2219
2220/*
2221 * WALLMSG -- Write a message to the world at large
2222 *
2223 * Write the specified message to either the entire
2224 * world, or a list of approved users.
2225 */
2226void
2227wallmsg(struct filed *f, struct iovec *iov)
2228{
2229 struct utmp ut;
2230 char utline[sizeof(ut.ut_line) + 1];
2231 static int reenter; /* avoid calling ourselves */
2232 FILE *uf;
2233 int i;
2234
2235 if (reenter++)
2236 return;
2237 if ((uf = priv_open_utmp()) == NULL((void*)0)) {
2238 log_warn("priv_open_utmp");
2239 reenter = 0;
2240 return;
2241 }
2242 while (fread(&ut, sizeof(ut), 1, uf) == 1) {
2243 if (ut.ut_name[0] == '\0')
2244 continue;
2245 /* must use strncpy since ut_* may not be NUL terminated */
2246 strncpy(utline, ut.ut_line, sizeof(utline) - 1);
2247 utline[sizeof(utline) - 1] = '\0';
2248 if (f->f_type == F_WALL6) {
2249 ttymsg(utline, iov);
2250 continue;
2251 }
2252 /* should we send the message to this user? */
2253 for (i = 0; i < MAXUNAMES20; i++) {
2254 if (!f->f_un.f_uname[i][0])
2255 break;
2256 if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
2257 UT_NAMESIZE32)) {
2258 ttymsg(utline, iov);
2259 break;
2260 }
2261 }
2262 }
2263 (void)fclose(uf);
2264 reenter = 0;
2265}
2266
2267/*
2268 * Return a printable representation of a host address.
2269 */
2270void
2271cvthname(struct sockaddr *f, char *result, size_t res_len)
2272{
2273 if (getnameinfo(f, f->sa_len, result, res_len, NULL((void*)0), 0,
2274 NI_NUMERICHOST1|NI_NUMERICSERV2|NI_DGRAM16) != 0) {
2275 log_debug("Malformed from address");
2276 strlcpy(result, hostname_unknown, res_len);
2277 return;
2278 }
2279 log_debug("cvthname(%s)", result);
2280 if (NoDNS)
2281 return;
2282
2283 if (priv_getnameinfo(f, f->sa_len, result, res_len) != 0)
2284 log_debug("Host name for from address (%s) unknown", result);
2285}
2286
2287void
2288die_signalcb(int signum, short event, void *arg)
2289{
2290 die(signum);
2291}
2292
2293void
2294mark_timercb(int unused, short event, void *arg)
2295{
2296 struct event *ev = arg;
2297 struct timeval to;
2298
2299 markit();
2300
2301 to.tv_sec = TIMERINTVL30;
2302 to.tv_usec = 0;
2303 evtimer_add(ev, &to)event_add(ev, &to);
2304}
2305
2306void
2307init_signalcb(int signum, short event, void *arg)
2308{
2309 init();
2310 log_info(LOG_INFO6, "restart");
2311
2312 dropped_warn(&file_dropped, "to file");
2313 dropped_warn(&tcpbuf_dropped, "to remote loghost");
2314 log_debug("syslogd: restarted");
2315}
2316
2317void
2318logevent(int severity, const char *msg)
2319{
2320 log_debug("libevent: [%d] %s", severity, msg);
2321}
2322
2323void
2324dropped_warn(int *count, const char *what)
2325{
2326 int dropped;
2327
2328 if (*count == 0)
2329 return;
2330
2331 dropped = *count;
2332 *count = 0;
2333 log_info(LOG_WARNING4, "dropped %d message%s %s",
2334 dropped, dropped == 1 ? "" : "s", what);
2335}
2336
2337__dead__attribute__((__noreturn__)) void
2338die(int signo)
2339{
2340 struct filed *f;
2341
2342 SIMPLEQ_FOREACH(f, &Files, f_next)for((f) = ((&Files)->sqh_first); (f) != ((void*)0); (f
) = ((f)->f_next.sqe_next))
{
2343 /* flush any pending output */
2344 if (f->f_prevcount)
2345 fprintlog(f, 0, (char *)NULL((void*)0));
2346 if (f->f_type == F_FORWTLS10 || f->f_type == F_FORWTCP9) {
2347 tcpbuf_dropped += f->f_dropped +
2348 tcpbuf_countmsg(f->f_un.f_forw.f_bufev);
2349 f->f_dropped = 0;
2350 }
2351 if (f->f_type == F_FILE1) {
2352 file_dropped += f->f_dropped;
2353 f->f_dropped = 0;
2354 }
2355 }
2356 dropped_warn(&init_dropped, "during initialization");
2357 dropped_warn(&file_dropped, "to file");
2358 dropped_warn(&tcpbuf_dropped, "to remote loghost");
2359
2360 if (signo)
2361 log_info(LOG_ERR3, "exiting on signal %d", signo);
2362 log_debug("syslogd: exited");
2363 exit(0);
2364}
2365
2366/*
2367 * INIT -- Initialize syslogd from configuration table
2368 */
2369void
2370init(void)
2371{
2372 char progblock[NAME_MAX255+1], hostblock[NAME_MAX255+1], *cline, *p, *q;
2373 struct filed_list mb;
2374 struct filed *f, *m;
2375 FILE *cf;
2376 int i;
2377 size_t s;
2378
2379 log_debug("init");
2380
2381 /* If config file has been modified, then just die to restart */
2382 if (priv_config_modified()) {
2383 log_debug("config file changed: dying");
2384 die(0);
2385 }
2386
2387 /*
2388 * Close all open log files.
2389 */
2390 Initialized = 0;
2391 SIMPLEQ_INIT(&mb)do { (&mb)->sqh_first = ((void*)0); (&mb)->sqh_last
= &(&mb)->sqh_first; } while (0)
;
2392 while (!SIMPLEQ_EMPTY(&Files)(((&Files)->sqh_first) == ((void*)0))) {
2393 f = SIMPLEQ_FIRST(&Files)((&Files)->sqh_first);
2394 SIMPLEQ_REMOVE_HEAD(&Files, f_next)do { if (((&Files)->sqh_first = (&Files)->sqh_first
->f_next.sqe_next) == ((void*)0)) (&Files)->sqh_last
= &(&Files)->sqh_first; } while (0)
;
2395 /* flush any pending output */
2396 if (f->f_prevcount)
2397 fprintlog(f, 0, (char *)NULL((void*)0));
2398
2399 switch (f->f_type) {
2400 case F_FORWTLS10:
2401 if (f->f_un.f_forw.f_ctx) {
2402 tls_close(f->f_un.f_forw.f_ctx);
2403 tls_free(f->f_un.f_forw.f_ctx);
2404 }
2405 free(f->f_un.f_forw.f_host);
2406 /* FALLTHROUGH */
2407 case F_FORWTCP9:
2408 tcpbuf_dropped += f->f_dropped +
2409 tcpbuf_countmsg(f->f_un.f_forw.f_bufev);
2410 bufferevent_free(f->f_un.f_forw.f_bufev);
2411 /* FALLTHROUGH */
2412 case F_FILE1:
2413 if (f->f_type == F_FILE1) {
2414 file_dropped += f->f_dropped;
2415 f->f_dropped = 0;
2416 }
2417 case F_TTY2:
2418 case F_CONSOLE3:
2419 case F_PIPE8:
2420 (void)close(f->f_file);
2421 break;
2422 }
2423 free(f->f_program);
2424 free(f->f_hostname);
2425 if (f->f_type == F_MEMBUF7) {
2426 f->f_program = NULL((void*)0);
2427 f->f_hostname = NULL((void*)0);
2428 log_debug("add %p to mb", f);
2429 SIMPLEQ_INSERT_HEAD(&mb, f, f_next)do { if (((f)->f_next.sqe_next = (&mb)->sqh_first) ==
((void*)0)) (&mb)->sqh_last = &(f)->f_next.sqe_next
; (&mb)->sqh_first = (f); } while (0)
;
2430 } else
2431 free(f);
2432 }
2433 SIMPLEQ_INIT(&Files)do { (&Files)->sqh_first = ((void*)0); (&Files)->
sqh_last = &(&Files)->sqh_first; } while (0)
;
2434
2435 /* open the configuration file */
2436 if ((cf = priv_open_config()) == NULL((void*)0)) {
2437 log_debug("cannot open %s", ConfFile);
2438 SIMPLEQ_INSERT_TAIL(&Files,do { (cfline("*.ERR\t/dev/console", "*", "*"))->f_next.sqe_next
= ((void*)0); *(&Files)->sqh_last = (cfline("*.ERR\t/dev/console"
, "*", "*")); (&Files)->sqh_last = &(cfline("*.ERR\t/dev/console"
, "*", "*"))->f_next.sqe_next; } while (0)
2439 cfline("*.ERR\t/dev/console", "*", "*"), f_next)do { (cfline("*.ERR\t/dev/console", "*", "*"))->f_next.sqe_next
= ((void*)0); *(&Files)->sqh_last = (cfline("*.ERR\t/dev/console"
, "*", "*")); (&Files)->sqh_last = &(cfline("*.ERR\t/dev/console"
, "*", "*"))->f_next.sqe_next; } while (0)
;
2440 SIMPLEQ_INSERT_TAIL(&Files,do { (cfline("*.PANIC\t*", "*", "*"))->f_next.sqe_next = (
(void*)0); *(&Files)->sqh_last = (cfline("*.PANIC\t*",
"*", "*")); (&Files)->sqh_last = &(cfline("*.PANIC\t*"
, "*", "*"))->f_next.sqe_next; } while (0)
2441 cfline("*.PANIC\t*", "*", "*"), f_next)do { (cfline("*.PANIC\t*", "*", "*"))->f_next.sqe_next = (
(void*)0); *(&Files)->sqh_last = (cfline("*.PANIC\t*",
"*", "*")); (&Files)->sqh_last = &(cfline("*.PANIC\t*"
, "*", "*"))->f_next.sqe_next; } while (0)
;
2442 Initialized = 1;
2443 dropped_warn(&init_dropped, "during initialization");
2444 return;
2445 }
2446
2447 /*
2448 * Foreach line in the conf table, open that file.
2449 */
2450 cline = NULL((void*)0);
2451 s = 0;
2452 strlcpy(progblock, "*", sizeof(progblock));
2453 strlcpy(hostblock, "*", sizeof(hostblock));
2454 send_udp = send_udp6 = 0;
2455 while (getline(&cline, &s, cf) != -1) {
2456 /*
2457 * check for end-of-section, comments, strip off trailing
2458 * spaces and newline character. !progblock and +hostblock
2459 * are treated specially: the following lines apply only to
2460 * that program.
2461 */
2462 for (p = cline; isspace((unsigned char)*p); ++p)
2463 continue;
2464 if (*p == '\0' || *p == '#')
2465 continue;
2466 if (*p == '!' || *p == '+') {
2467 q = (*p == '!') ? progblock : hostblock;
2468 p++;
2469 while (isspace((unsigned char)*p))
2470 p++;
2471 if (*p == '\0' || (*p == '*' && (p[1] == '\0' ||
2472 isspace((unsigned char)p[1])))) {
2473 strlcpy(q, "*", NAME_MAX255+1);
2474 continue;
2475 }
2476 for (i = 0; i < NAME_MAX255; i++) {
2477 if (*p == '\0' || isspace((unsigned char)*p))
2478 break;
2479 *q++ = *p++;
2480 }
2481 *q = '\0';
2482 continue;
2483 }
2484
2485 p = cline + strlen(cline);
2486 while (p > cline)
2487 if (!isspace((unsigned char)*--p)) {
2488 p++;
2489 break;
2490 }
2491 *p = '\0';
2492 f = cfline(cline, progblock, hostblock);
2493 if (f != NULL((void*)0))
2494 SIMPLEQ_INSERT_TAIL(&Files, f, f_next)do { (f)->f_next.sqe_next = ((void*)0); *(&Files)->
sqh_last = (f); (&Files)->sqh_last = &(f)->f_next
.sqe_next; } while (0)
;
2495 }
2496 free(cline);
2497 if (!feof(cf)(!__isthreaded ? (((cf)->_flags & 0x0020) != 0) : (feof
)(cf))
)
2498 fatal("read config file");
2499
2500 /* Match and initialize the memory buffers */
2501 SIMPLEQ_FOREACH(f, &Files, f_next)for((f) = ((&Files)->sqh_first); (f) != ((void*)0); (f
) = ((f)->f_next.sqe_next))
{
2502 if (f->f_type != F_MEMBUF7)
2503 continue;
2504 log_debug("Initialize membuf %s at %p",
2505 f->f_un.f_mb.f_mname, f);
2506
2507 SIMPLEQ_FOREACH(m, &mb, f_next)for((m) = ((&mb)->sqh_first); (m) != ((void*)0); (m) =
((m)->f_next.sqe_next))
{
2508 if (m->f_un.f_mb.f_rb == NULL((void*)0))
2509 continue;
2510 if (strcmp(m->f_un.f_mb.f_mname,
2511 f->f_un.f_mb.f_mname) == 0)
2512 break;
2513 }
2514 if (m == NULL((void*)0)) {
2515 log_debug("Membuf no match");
2516 f->f_un.f_mb.f_rb = ringbuf_init(f->f_un.f_mb.f_len);
2517 if (f->f_un.f_mb.f_rb == NULL((void*)0)) {
2518 f->f_type = F_UNUSED0;
2519 log_warn("allocate membuf");
2520 }
2521 } else {
2522 log_debug("Membuf match f:%p, m:%p", f, m);
2523 f->f_un = m->f_un;
2524 m->f_un.f_mb.f_rb = NULL((void*)0);
2525 }
2526 }
2527
2528 /* make sure remaining buffers are freed */
2529 while (!SIMPLEQ_EMPTY(&mb)(((&mb)->sqh_first) == ((void*)0))) {
2530 m = SIMPLEQ_FIRST(&mb)((&mb)->sqh_first);
2531 SIMPLEQ_REMOVE_HEAD(&mb, f_next)do { if (((&mb)->sqh_first = (&mb)->sqh_first->
f_next.sqe_next) == ((void*)0)) (&mb)->sqh_last = &
(&mb)->sqh_first; } while (0)
;
2532 if (m->f_un.f_mb.f_rb != NULL((void*)0)) {
2533 log_warnx("mismatched membuf");
2534 ringbuf_free(m->f_un.f_mb.f_rb);
2535 }
2536 log_debug("Freeing membuf %p", m);
2537
2538 free(m);
2539 }
2540
2541 /* close the configuration file */
2542 (void)fclose(cf);
2543
2544 Initialized = 1;
2545 dropped_warn(&init_dropped, "during initialization");
2546
2547 if (SecureMode) {
2548 /*
2549 * If generic UDP file descriptors are used neither
2550 * for receiving nor for sending, close them. Then
2551 * there is no useless *.514 in netstat.
2552 */
2553 if (fd_udp != -1 && !send_udp) {
2554 close(fd_udp);
2555 fd_udp = -1;
2556 }
2557 if (fd_udp6 != -1 && !send_udp6) {
2558 close(fd_udp6);
2559 fd_udp6 = -1;
2560 }
2561 }
2562
2563 if (Debug) {
2564 SIMPLEQ_FOREACH(f, &Files, f_next)for((f) = ((&Files)->sqh_first); (f) != ((void*)0); (f
) = ((f)->f_next.sqe_next))
{
2565 for (i = 0; i <= LOG_NFACILITIES24; i++)
2566 if (f->f_pmask[i] == INTERNAL_NOPRI0x10)
2567 printf("X ");
2568 else
2569 printf("%d ", f->f_pmask[i]);
2570 printf("%s: ", TypeNames[f->f_type]);
2571 switch (f->f_type) {
2572 case F_FILE1:
2573 case F_TTY2:
2574 case F_CONSOLE3:
2575 case F_PIPE8:
2576 printf("%s", f->f_un.f_fname);
2577 break;
2578
2579 case F_FORWUDP4:
2580 case F_FORWTCP9:
2581 case F_FORWTLS10:
2582 printf("%s", f->f_un.f_forw.f_loghost);
2583 break;
2584
2585 case F_USERS5:
2586 for (i = 0; i < MAXUNAMES20 &&
2587 *f->f_un.f_uname[i]; i++)
2588 printf("%s, ", f->f_un.f_uname[i]);
2589 break;
2590
2591 case F_MEMBUF7:
2592 printf("%s", f->f_un.f_mb.f_mname);
2593 break;
2594
2595 }
2596 if (f->f_program || f->f_hostname)
2597 printf(" (%s, %s)",
2598 f->f_program ? f->f_program : "*",
2599 f->f_hostname ? f->f_hostname : "*");
2600 printf("\n");
2601 }
2602 }
2603}
2604
2605#define progmatches(p1, p2)(p1 == p2 || (p1 != ((void*)0) && p2 != ((void*)0) &&
strcmp(p1, p2) == 0))
\
2606 (p1 == p2 || (p1 != NULL((void*)0) && p2 != NULL((void*)0) && strcmp(p1, p2) == 0))
2607
2608/*
2609 * Spot a line with a duplicate file, pipe, console, tty, or membuf target.
2610 */
2611struct filed *
2612find_dup(struct filed *f)
2613{
2614 struct filed *list;
2615
2616 SIMPLEQ_FOREACH(list, &Files, f_next)for((list) = ((&Files)->sqh_first); (list) != ((void*)
0); (list) = ((list)->f_next.sqe_next))
{
2617 if (list->f_quick || f->f_quick)
2618 continue;
2619 switch (list->f_type) {
2620 case F_FILE1:
2621 case F_TTY2:
2622 case F_CONSOLE3:
2623 case F_PIPE8:
2624 if (strcmp(list->f_un.f_fname, f->f_un.f_fname) == 0 &&
2625 progmatches(list->f_program, f->f_program)(list->f_program == f->f_program || (list->f_program
!= ((void*)0) && f->f_program != ((void*)0) &&
strcmp(list->f_program, f->f_program) == 0))
&&
2626 progmatches(list->f_hostname, f->f_hostname)(list->f_hostname == f->f_hostname || (list->f_hostname
!= ((void*)0) && f->f_hostname != ((void*)0) &&
strcmp(list->f_hostname, f->f_hostname) == 0))
) {
2627 log_debug("duplicate %s", f->f_un.f_fname);
2628 return (list);
2629 }
2630 break;
2631 case F_MEMBUF7:
2632 if (strcmp(list->f_un.f_mb.f_mname,
2633 f->f_un.f_mb.f_mname) == 0 &&
2634 progmatches(list->f_program, f->f_program)(list->f_program == f->f_program || (list->f_program
!= ((void*)0) && f->f_program != ((void*)0) &&
strcmp(list->f_program, f->f_program) == 0))
&&
2635 progmatches(list->f_hostname, f->f_hostname)(list->f_hostname == f->f_hostname || (list->f_hostname
!= ((void*)0) && f->f_hostname != ((void*)0) &&
strcmp(list->f_hostname, f->f_hostname) == 0))
) {
2636 log_debug("duplicate membuf %s",
2637 f->f_un.f_mb.f_mname);
2638 return (list);
2639 }
2640 break;
2641 }
2642 }
2643 return (NULL((void*)0));
2644}
2645
2646/*
2647 * Crack a configuration file line
2648 */
2649struct filed *
2650cfline(char *line, char *progblock, char *hostblock)
2651{
2652 int i, pri;
2653 size_t rb_len;
2654 char *bp, *p, *q, *proto, *host, *port, *ipproto;
2655 char buf[LOG_MAXLINE8192];
2656 struct filed *xf, *f, *d;
2657 struct timeval to;
2658
2659 log_debug("cfline(\"%s\", f, \"%s\", \"%s\")",
2660 line, progblock, hostblock);
2661
2662 if ((f = calloc(1, sizeof(*f))) == NULL((void*)0))
2663 fatal("allocate struct filed");
2664 for (i = 0; i <= LOG_NFACILITIES24; i++)
2665 f->f_pmask[i] = INTERNAL_NOPRI0x10;
2666
2667 /* save program name if any */
2668 f->f_quick = 0;
2669 if (*progblock == '!') {
2670 progblock++;
2671 f->f_quick = 1;
2672 }
2673 if (*hostblock == '+') {
2674 hostblock++;
2675 f->f_quick = 1;
2676 }
2677 if (strcmp(progblock, "*") != 0)
2678 f->f_program = strdup(progblock);
2679 if (strcmp(hostblock, "*") != 0)
2680 f->f_hostname = strdup(hostblock);
2681
2682 /* scan through the list of selectors */
2683 for (p = line; *p && *p != '\t' && *p != ' ';) {
2684
2685 /* find the end of this facility name list */
2686 for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.'; )
2687 continue;
2688
2689 /* collect priority name */
2690 for (bp = buf; *q && !strchr("\t,; ", *q); )
2691 *bp++ = *q++;
2692 *bp = '\0';
2693
2694 /* skip cruft */
2695 while (*q && strchr(",;", *q))
2696 q++;
2697
2698 /* decode priority name */
2699 if (*buf == '*')
2700 pri = LOG_PRIMASK0x07 + 1;
2701 else {
2702 /* ignore trailing spaces */
2703 for (i=strlen(buf)-1; i >= 0 && buf[i] == ' '; i--) {
2704 buf[i]='\0';
2705 }
2706
2707 pri = decode(buf, prioritynames);
2708 if (pri < 0) {
2709 log_warnx("unknown priority name \"%s\"", buf);
2710 free(f);
2711 return (NULL((void*)0));
2712 }
2713 }
2714
2715 /* scan facilities */
2716 while (*p && !strchr("\t.; ", *p)) {
2717 for (bp = buf; *p && !strchr("\t,;. ", *p); )
2718 *bp++ = *p++;
2719 *bp = '\0';
2720 if (*buf == '*')
2721 for (i = 0; i < LOG_NFACILITIES24; i++)
2722 f->f_pmask[i] = pri;
2723 else {
2724 i = decode(buf, facilitynames);
2725 if (i < 0) {
2726 log_warnx("unknown facility name "
2727 "\"%s\"", buf);
2728 free(f);
2729 return (NULL((void*)0));
2730 }
2731 f->f_pmask[i >> 3] = pri;
2732 }
2733 while (*p == ',' || *p == ' ')
2734 p++;
2735 }
2736
2737 p = q;
2738 }
2739
2740 /* skip to action part */
2741 while (*p == '\t' || *p == ' ')
2742 p++;
2743
2744 switch (*p) {
2745 case '@':
2746 if ((strlcpy(f->f_un.f_forw.f_loghost, p,
2747 sizeof(f->f_un.f_forw.f_loghost)) >=
2748 sizeof(f->f_un.f_forw.f_loghost))) {
2749 log_warnx("loghost too long \"%s\"", p);
2750 break;
2751 }
2752 if (loghost_parse(++p, &proto, &host, &port) == -1) {
2753 log_warnx("bad loghost \"%s\"",
2754 f->f_un.f_forw.f_loghost);
2755 break;
2756 }
2757 if (proto == NULL((void*)0))
2758 proto = "udp";
2759 if (strcmp(proto, "udp") == 0) {
2760 if (fd_udp == -1)
2761 proto = "udp6";
2762 if (fd_udp6 == -1)
2763 proto = "udp4";
2764 }
2765 ipproto = proto;
2766 if (strcmp(proto, "udp") == 0) {
2767 send_udp = send_udp6 = 1;
2768 } else if (strcmp(proto, "udp4") == 0) {
2769 send_udp = 1;
2770 if (fd_udp == -1) {
2771 log_warnx("no udp4 \"%s\"",
2772 f->f_un.f_forw.f_loghost);
2773 break;
2774 }
2775 } else if (strcmp(proto, "udp6") == 0) {
2776 send_udp6 = 1;
2777 if (fd_udp6 == -1) {
2778 log_warnx("no udp6 \"%s\"",
2779 f->f_un.f_forw.f_loghost);
2780 break;
2781 }
2782 } else if (strcmp(proto, "tcp") == 0 ||
2783 strcmp(proto, "tcp4") == 0 || strcmp(proto, "tcp6") == 0) {
2784 ;
2785 } else if (strcmp(proto, "tls") == 0) {
2786 ipproto = "tcp";
2787 } else if (strcmp(proto, "tls4") == 0) {
2788 ipproto = "tcp4";
2789 } else if (strcmp(proto, "tls6") == 0) {
2790 ipproto = "tcp6";
2791 } else {
2792 log_warnx("bad protocol \"%s\"",
2793 f->f_un.f_forw.f_loghost);
2794 break;
2795 }
2796 if (strlen(host) >= NI_MAXHOST256) {
2797 log_warnx("host too long \"%s\"",
2798 f->f_un.f_forw.f_loghost);
2799 break;
2800 }
2801 if (port == NULL((void*)0))
2802 port = strncmp(proto, "tls", 3) == 0 ?
2803 "syslog-tls" : "syslog";
2804 if (strlen(port) >= NI_MAXSERV32) {
2805 log_warnx("port too long \"%s\"",
2806 f->f_un.f_forw.f_loghost);
2807 break;
2808 }
2809 if (priv_getaddrinfo(ipproto, host, port,
2810 (struct sockaddr*)&f->f_un.f_forw.f_addr,
2811 sizeof(f->f_un.f_forw.f_addr)) != 0) {
2812 log_warnx("bad hostname \"%s\"",
2813 f->f_un.f_forw.f_loghost);
2814 break;
2815 }
2816 f->f_file = -1;
2817 if (strncmp(proto, "udp", 3) == 0) {
2818 switch (f->f_un.f_forw.f_addr.ss_family) {
2819 case AF_INET2:
2820 f->f_file = fd_udp;
2821 break;
2822 case AF_INET624:
2823 f->f_file = fd_udp6;
2824 break;
2825 }
2826 f->f_type = F_FORWUDP4;
2827 } else if (strncmp(ipproto, "tcp", 3) == 0) {
2828 if ((f->f_un.f_forw.f_bufev = bufferevent_new(-1,
2829 tcp_dropcb, tcp_writecb, tcp_errorcb, f)) == NULL((void*)0)) {
2830 log_warn("bufferevent \"%s\"",
2831 f->f_un.f_forw.f_loghost);
2832 break;
2833 }
2834 if (strncmp(proto, "tls", 3) == 0) {
2835 f->f_un.f_forw.f_host = strdup(host);
2836 f->f_type = F_FORWTLS10;
2837 } else {
2838 f->f_type = F_FORWTCP9;
2839 }
2840 /*
2841 * If we try to connect to a TLS server immediately
2842 * syslogd gets an SIGPIPE as the signal handlers have
2843 * not been set up. Delay the connection until the
2844 * event loop is started. We can reuse the write event
2845 * for that as bufferevent is still disabled.
2846 */
2847 to.tv_sec = 0;
2848 to.tv_usec = 1;
2849 evtimer_set(&f->f_un.f_forw.f_bufev->ev_write,event_set(&f->f_un.f_forw.f_bufev->ev_write, -1, 0,
tcp_connectcb, f)
2850 tcp_connectcb, f)event_set(&f->f_un.f_forw.f_bufev->ev_write, -1, 0,
tcp_connectcb, f)
;
2851 evtimer_add(&f->f_un.f_forw.f_bufev->ev_write, &to)event_add(&f->f_un.f_forw.f_bufev->ev_write, &to
)
;
2852 }
2853 break;
2854
2855 case '/':
2856 case '|':
2857 (void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname));
2858 d = find_dup(f);
2859 if (d != NULL((void*)0)) {
2860 for (i = 0; i <= LOG_NFACILITIES24; i++)
2861 if (f->f_pmask[i] != INTERNAL_NOPRI0x10)
2862 d->f_pmask[i] = f->f_pmask[i];
2863 free(f);
2864 return (NULL((void*)0));
2865 }
2866 if (strcmp(p, ctty) == 0) {
2867 f->f_file = priv_open_tty(p);
2868 if (f->f_file < 0)
2869 log_warn("priv_open_tty \"%s\"", p);
2870 } else {
2871 f->f_file = priv_open_log(p);
2872 if (f->f_file < 0)
2873 log_warn("priv_open_log \"%s\"", p);
2874 }
2875 if (f->f_file < 0) {
2876 f->f_type = F_UNUSED0;
2877 break;
2878 }
2879 if (isatty(f->f_file)) {
2880 if (strcmp(p, ctty) == 0)
2881 f->f_type = F_CONSOLE3;
2882 else
2883 f->f_type = F_TTY2;
2884 } else {
2885 if (*p == '|')
2886 f->f_type = F_PIPE8;
2887 else {
2888 f->f_type = F_FILE1;
2889
2890 /* Clear O_NONBLOCK flag on f->f_file */
2891 if ((i = fcntl(f->f_file, F_GETFL3)) != -1) {
2892 i &= ~O_NONBLOCK0x0004;
2893 fcntl(f->f_file, F_SETFL4, i);
2894 }
2895 }
2896 }
2897 break;
2898
2899 case '*':
2900 f->f_type = F_WALL6;
2901 break;
2902
2903 case ':':
2904 f->f_type = F_MEMBUF7;
2905
2906 /* Parse buffer size (in kb) */
2907 errno(*__errno()) = 0;
2908 rb_len = strtoul(++p, &q, 0);
2909 if (*p == '\0' || (errno(*__errno()) == ERANGE34 && rb_len == ULONG_MAX(9223372036854775807L *2UL+1UL)) ||
2910 *q != ':' || rb_len == 0) {
2911 f->f_type = F_UNUSED0;
2912 log_warnx("strtoul \"%s\"", p);
2913 break;
2914 }
2915 q++;
2916 rb_len *= 1024;
2917
2918 /* Copy buffer name */
2919 for(i = 0; (size_t)i < sizeof(f->f_un.f_mb.f_mname) - 1; i++) {
2920 if (!isalnum((unsigned char)q[i]))
2921 break;
2922 f->f_un.f_mb.f_mname[i] = q[i];
2923 }
2924
2925 /* Make sure buffer name is unique */
2926 xf = find_dup(f);
2927
2928 /* Error on missing or non-unique name, or bad buffer length */
2929 if (i == 0 || rb_len > MAX_MEMBUF(256 * 1024) || xf != NULL((void*)0)) {
2930 f->f_type = F_UNUSED0;
2931 log_warnx("find_dup \"%s\"", p);
2932 break;
2933 }
2934
2935 /* Set buffer length */
2936 rb_len = MAXIMUM(rb_len, MIN_MEMBUF)(((rb_len) > ((8192 * 4))) ? (rb_len) : ((8192 * 4)));
2937 f->f_un.f_mb.f_len = rb_len;
2938 f->f_un.f_mb.f_overflow = 0;
2939 f->f_un.f_mb.f_attached = 0;
2940 break;
2941
2942 default:
2943 for (i = 0; i < MAXUNAMES20 && *p; i++) {
2944 for (q = p; *q && *q != ','; )
2945 q++;
2946 (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE32);
2947 if ((q - p) > UT_NAMESIZE32)
2948 f->f_un.f_uname[i][UT_NAMESIZE32] = '\0';
2949 else
2950 f->f_un.f_uname[i][q - p] = '\0';
2951 while (*q == ',' || *q == ' ')
2952 q++;
2953 p = q;
2954 }
2955 f->f_type = F_USERS5;
2956 break;
2957 }
2958 return (f);
2959}
2960
2961/*
2962 * Parse the host and port parts from a loghost string.
2963 */
2964int
2965loghost_parse(char *str, char **proto, char **host, char **port)
2966{
2967 char *prefix = NULL((void*)0);
2968
2969 if ((*host = strchr(str, ':')) &&
2970 (*host)[1] == '/' && (*host)[2] == '/') {
2971 prefix = str;
2972 **host = '\0';
2973 str = *host + 3;
2974 }
2975 if (proto)
2976 *proto = prefix;
2977 else if (prefix)
2978 return (-1);
2979
2980 *host = str;
2981 if (**host == '[') {
2982 (*host)++;
2983 str = strchr(*host, ']');
2984 if (str == NULL((void*)0))
2985 return (-1);
2986 *str++ = '\0';
2987 }
2988 *port = strrchr(str, ':');
2989 if (*port != NULL((void*)0))
2990 *(*port)++ = '\0';
2991
2992 return (0);
2993}
2994
2995/*
2996 * Retrieve the size of the kernel message buffer, via sysctl.
2997 */
2998int
2999getmsgbufsize(void)
3000{
3001 int msgbufsize, mib[2];
3002 size_t size;
3003
3004 mib[0] = CTL_KERN1;
3005 mib[1] = KERN_MSGBUFSIZE38;
3006 size = sizeof msgbufsize;
3007 if (sysctl(mib, 2, &msgbufsize, &size, NULL((void*)0), 0) == -1) {
3008 log_debug("couldn't get kern.msgbufsize");
3009 return (0);
3010 }
3011 return (msgbufsize);
3012}
3013
3014/*
3015 * Decode a symbolic name to a numeric value
3016 */
3017int
3018decode(const char *name, const CODE *codetab)
3019{
3020 const CODE *c;
3021 char *p, buf[40];
3022
3023 for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
3024 if (isupper((unsigned char)*name))
3025 *p = tolower((unsigned char)*name);
3026 else
3027 *p = *name;
3028 }
3029 *p = '\0';
3030 for (c = codetab; c->c_name; c++)
3031 if (!strcmp(buf, c->c_name))
3032 return (c->c_val);
3033
3034 return (-1);
3035}
3036
3037void
3038markit(void)
3039{
3040 struct filed *f;
3041
3042 (void)gettimeofday(&now, NULL((void*)0));
3043 MarkSeq += TIMERINTVL30;
3044 if (MarkSeq >= MarkInterval) {
3045 logline(LOG_INFO6, ADDDATE0x004|MARK0x008, LocalHostName, "-- MARK --");
3046 MarkSeq = 0;
3047 }
3048
3049 SIMPLEQ_FOREACH(f, &Files, f_next)for((f) = ((&Files)->sqh_first); (f) != ((void*)0); (f
) = ((f)->f_next.sqe_next))
{
3050 if (f->f_prevcount && now.tv_sec >= REPEATTIME(f)((f)->f_time + repeatinterval[(f)->f_repeatcount])) {
3051 log_debug("flush %s: repeated %d times, %d sec",
3052 TypeNames[f->f_type], f->f_prevcount,
3053 repeatinterval[f->f_repeatcount]);
3054 fprintlog(f, 0, (char *)NULL((void*)0));
3055 BACKOFF(f){ if (++(f)->f_repeatcount > ((sizeof(repeatinterval) /
sizeof(repeatinterval[0])) - 1)) (f)->f_repeatcount = ((sizeof
(repeatinterval) / sizeof(repeatinterval[0])) - 1); }
;
3056 }
3057 }
3058}
3059
3060int
3061unix_socket(char *path, int type, mode_t mode)
3062{
3063 struct sockaddr_un s_un;
3064 int fd, optval;
3065 mode_t old_umask;
3066
3067 memset(&s_un, 0, sizeof(s_un));
3068 s_un.sun_family = AF_UNIX1;
3069 if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) >=
3070 sizeof(s_un.sun_path)) {
3071 log_warnx("socket path too long \"%s\"", path);
3072 return (-1);
3073 }
3074
3075 if ((fd = socket(AF_UNIX1, type, 0)) == -1) {
3076 log_warn("socket unix \"%s\"", path);
3077 return (-1);
3078 }
3079
3080 if (Debug) {
3081 if (connect(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == 0 ||
3082 errno(*__errno()) == EPROTOTYPE41) {
3083 close(fd);
3084 errno(*__errno()) = EISCONN56;
3085 log_warn("connect unix \"%s\"", path);
3086 return (-1);
3087 }
3088 }
3089
3090 old_umask = umask(0177);
3091
3092 unlink(path);
3093 if (bind(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
3094 log_warn("bind unix \"%s\"", path);
3095 umask(old_umask);
3096 close(fd);
3097 return (-1);
3098 }
3099
3100 umask(old_umask);
3101
3102 if (chmod(path, mode) == -1) {
3103 log_warn("chmod unix \"%s\"", path);
3104 close(fd);
3105 unlink(path);
3106 return (-1);
3107 }
3108
3109 optval = LOG_MAXLINE8192 + PATH_MAX1024;
3110 if (setsockopt(fd, SOL_SOCKET0xffff, SO_RCVBUF0x1002, &optval, sizeof(optval))
3111 == -1)
3112 log_warn("setsockopt unix \"%s\"", path);
3113
3114 return (fd);
3115}
3116
3117/*
3118 * Increase socket buffer size in small steps to get partial success
3119 * if we hit a kernel limit. Allow an optional final step.
3120 */
3121void
3122double_sockbuf(int fd, int optname, int bigsize)
3123{
3124 socklen_t len;
3125 int i, newsize, oldsize = 0;
3126
3127 len = sizeof(oldsize);
3128 if (getsockopt(fd, SOL_SOCKET0xffff, optname, &oldsize, &len) == -1)
3129 log_warn("getsockopt bufsize");
3130 len = sizeof(newsize);
3131 newsize = LOG_MAXLINE8192 + 128; /* data + control */
3132 /* allow 8 full length messages, that is 66560 bytes */
3133 for (i = 0; i < 4; i++, newsize *= 2) {
3134 if (newsize <= oldsize)
3135 continue;
3136 if (setsockopt(fd, SOL_SOCKET0xffff, optname, &newsize, len) == -1)
3137 log_warn("setsockopt bufsize %d", newsize);
3138 else
3139 oldsize = newsize;
3140 }
3141 if (bigsize && bigsize > oldsize) {
3142 if (setsockopt(fd, SOL_SOCKET0xffff, optname, &bigsize, len) == -1)
3143 log_warn("setsockopt bufsize %d", bigsize);
3144 }
3145}
3146
3147void
3148set_sockbuf(int fd)
3149{
3150 int size = 65536;
3151
3152 if (setsockopt(fd, SOL_SOCKET0xffff, SO_SNDBUF0x1001, &size, sizeof(size)) == -1)
3153 log_warn("setsockopt sndbufsize %d", size);
3154 if (setsockopt(fd, SOL_SOCKET0xffff, SO_RCVBUF0x1002, &size, sizeof(size)) == -1)
3155 log_warn("setsockopt rcvbufsize %d", size);
3156}
3157
3158void
3159set_keepalive(int fd)
3160{
3161 int val = 1;
3162
3163 if (setsockopt(fd, SOL_SOCKET0xffff, SO_KEEPALIVE0x0008, &val, sizeof(val)) == -1)
3164 log_warn("setsockopt keepalive %d", val);
3165}
3166
3167void
3168ctlconn_cleanup(void)
3169{
3170 struct filed *f;
3171
3172 close(fd_ctlconn);
3173 fd_ctlconn = -1;
3174 event_del(ev_ctlread);
3175 event_del(ev_ctlwrite);
3176 event_add(ev_ctlaccept, NULL((void*)0));
3177
3178 if (ctl_state == CTL_WRITING_CONT_REPLY3)
3179 SIMPLEQ_FOREACH(f, &Files, f_next)for((f) = ((&Files)->sqh_first); (f) != ((void*)0); (f
) = ((f)->f_next.sqe_next))
3180 if (f->f_type == F_MEMBUF7)
3181 f->f_un.f_mb.f_attached = 0;
3182
3183 ctl_state = ctl_cmd_bytes = ctl_reply_offset = ctl_reply_size = 0;
3184}
3185
3186void
3187ctlsock_acceptcb(int fd, short event, void *arg)
3188{
3189 struct event *ev = arg;
3190
3191 if ((fd = reserve_accept4(fd, event, ev, ctlsock_acceptcb,
3192 NULL((void*)0), NULL((void*)0), SOCK_NONBLOCK0x4000)) == -1) {
3193 if (errno(*__errno()) != ENFILE23 && errno(*__errno()) != EMFILE24 &&
3194 errno(*__errno()) != EINTR4 && errno(*__errno()) != EWOULDBLOCK35 &&
3195 errno(*__errno()) != ECONNABORTED53)
3196 log_warn("accept control socket");
3197 return;
3198 }
3199 log_debug("Accepting control connection");
3200
3201 if (fd_ctlconn != -1)
3202 ctlconn_cleanup();
3203
3204 /* Only one connection at a time */
3205 event_del(ev);
3206
3207 fd_ctlconn = fd;
3208 /* file descriptor has changed, reset event */
3209 event_set(ev_ctlread, fd_ctlconn, EV_READ0x02|EV_PERSIST0x10,
3210 ctlconn_readcb, ev_ctlread);
3211 event_set(ev_ctlwrite, fd_ctlconn, EV_WRITE0x04|EV_PERSIST0x10,
3212 ctlconn_writecb, ev_ctlwrite);
3213 event_add(ev_ctlread, NULL((void*)0));
3214 ctl_state = CTL_READING_CMD1;
3215 ctl_cmd_bytes = 0;
3216}
3217
3218static struct filed
3219*find_membuf_log(const char *name)
3220{
3221 struct filed *f;
3222
3223 SIMPLEQ_FOREACH(f, &Files, f_next)for((f) = ((&Files)->sqh_first); (f) != ((void*)0); (f
) = ((f)->f_next.sqe_next))
{
3224 if (f->f_type == F_MEMBUF7 &&
3225 strcmp(f->f_un.f_mb.f_mname, name) == 0)
3226 break;
3227 }
3228 return (f);
3229}
3230
3231void
3232ctlconn_readcb(int fd, short event, void *arg)
3233{
3234 struct filed *f;
3235 struct ctl_reply_hdr *reply_hdr = (struct ctl_reply_hdr *)ctl_reply;
3236 ssize_t n;
3237 u_int32_t flags = 0;
3238
3239 if (ctl_state == CTL_WRITING_REPLY2 ||
3240 ctl_state == CTL_WRITING_CONT_REPLY3) {
3241 /* client has closed the connection */
3242 ctlconn_cleanup();
3243 return;
3244 }
3245
3246 retry:
3247 n = read(fd, (char*)&ctl_cmd + ctl_cmd_bytes,
3248 sizeof(ctl_cmd) - ctl_cmd_bytes);
3249 switch (n) {
3250 case -1:
3251 if (errno(*__errno()) == EINTR4)
3252 goto retry;
3253 if (errno(*__errno()) == EWOULDBLOCK35)
3254 return;
3255 log_warn("read control socket");
3256 /* FALLTHROUGH */
3257 case 0:
3258 ctlconn_cleanup();
3259 return;
3260 default:
3261 ctl_cmd_bytes += n;
3262 }
3263 if (ctl_cmd_bytes < sizeof(ctl_cmd))
3264 return;
3265
3266 if (ntohl(ctl_cmd.version)(__uint32_t)(__builtin_constant_p(ctl_cmd.version) ? (__uint32_t
)(((__uint32_t)(ctl_cmd.version) & 0xff) << 24 | ((
__uint32_t)(ctl_cmd.version) & 0xff00) << 8 | ((__uint32_t
)(ctl_cmd.version) & 0xff0000) >> 8 | ((__uint32_t)
(ctl_cmd.version) & 0xff000000) >> 24) : __swap32md
(ctl_cmd.version))
!= CTL_VERSION2) {
3267 log_warnx("unknown client protocol version");
3268 ctlconn_cleanup();
3269 return;
3270 }
3271
3272 /* Ensure that logname is \0 terminated */
3273 if (memchr(ctl_cmd.logname, '\0', sizeof(ctl_cmd.logname)) == NULL((void*)0)) {
3274 log_warnx("corrupt control socket command");
3275 ctlconn_cleanup();
3276 return;
3277 }
3278
3279 *reply_text = '\0';
3280
3281 ctl_reply_size = ctl_reply_offset = 0;
3282 memset(reply_hdr, '\0', sizeof(*reply_hdr));
3283
3284 ctl_cmd.cmd = ntohl(ctl_cmd.cmd)(__uint32_t)(__builtin_constant_p(ctl_cmd.cmd) ? (__uint32_t)
(((__uint32_t)(ctl_cmd.cmd) & 0xff) << 24 | ((__uint32_t
)(ctl_cmd.cmd) & 0xff00) << 8 | ((__uint32_t)(ctl_cmd
.cmd) & 0xff0000) >> 8 | ((__uint32_t)(ctl_cmd.cmd)
& 0xff000000) >> 24) : __swap32md(ctl_cmd.cmd))
;
3285 log_debug("ctlcmd %x logname \"%s\"", ctl_cmd.cmd, ctl_cmd.logname);
3286
3287 switch (ctl_cmd.cmd) {
3288 case CMD_READ1:
3289 case CMD_READ_CLEAR2:
3290 case CMD_READ_CONT6:
3291 case CMD_FLAGS5:
3292 f = find_membuf_log(ctl_cmd.logname);
3293 if (f == NULL((void*)0)) {
3294 strlcpy(reply_text, "No such log\n", MAX_MEMBUF(256 * 1024));
3295 } else {
3296 if (ctl_cmd.cmd != CMD_FLAGS5) {
3297 ringbuf_to_string(reply_text, MAX_MEMBUF(256 * 1024),
3298 f->f_un.f_mb.f_rb);
3299 }
3300 if (f->f_un.f_mb.f_overflow)
3301 flags |= CTL_HDR_FLAG_OVERFLOW0x01;
3302 if (ctl_cmd.cmd == CMD_READ_CLEAR2) {
3303 ringbuf_clear(f->f_un.f_mb.f_rb);
3304 f->f_un.f_mb.f_overflow = 0;
3305 }
3306 if (ctl_cmd.cmd == CMD_READ_CONT6) {
3307 f->f_un.f_mb.f_attached = 1;
3308 tailify_replytext(reply_text,
3309 ctl_cmd.lines > 0 ? ctl_cmd.lines : 10);
3310 } else if (ctl_cmd.lines > 0) {
3311 tailify_replytext(reply_text, ctl_cmd.lines);
3312 }
3313 }
3314 break;
3315 case CMD_CLEAR3:
3316 f = find_membuf_log(ctl_cmd.logname);
3317 if (f == NULL((void*)0)) {
3318 strlcpy(reply_text, "No such log\n", MAX_MEMBUF(256 * 1024));
3319 } else {
3320 ringbuf_clear(f->f_un.f_mb.f_rb);
3321 if (f->f_un.f_mb.f_overflow)
3322 flags |= CTL_HDR_FLAG_OVERFLOW0x01;
3323 f->f_un.f_mb.f_overflow = 0;
3324 strlcpy(reply_text, "Log cleared\n", MAX_MEMBUF(256 * 1024));
3325 }
3326 break;
3327 case CMD_LIST4:
3328 SIMPLEQ_FOREACH(f, &Files, f_next)for((f) = ((&Files)->sqh_first); (f) != ((void*)0); (f
) = ((f)->f_next.sqe_next))
{
3329 if (f->f_type == F_MEMBUF7) {
3330 strlcat(reply_text, f->f_un.f_mb.f_mname,
3331 MAX_MEMBUF(256 * 1024));
3332 if (f->f_un.f_mb.f_overflow) {
3333 strlcat(reply_text, "*", MAX_MEMBUF(256 * 1024));
3334 flags |= CTL_HDR_FLAG_OVERFLOW0x01;
3335 }
3336 strlcat(reply_text, " ", MAX_MEMBUF(256 * 1024));
3337 }
3338 }
3339 strlcat(reply_text, "\n", MAX_MEMBUF(256 * 1024));
3340 break;
3341 default:
3342 log_warnx("unsupported control socket command");
3343 ctlconn_cleanup();
3344 return;
3345 }
3346 reply_hdr->version = htonl(CTL_VERSION)(__uint32_t)(__builtin_constant_p(2) ? (__uint32_t)(((__uint32_t
)(2) & 0xff) << 24 | ((__uint32_t)(2) & 0xff00)
<< 8 | ((__uint32_t)(2) & 0xff0000) >> 8 | (
(__uint32_t)(2) & 0xff000000) >> 24) : __swap32md(2
))
;
3347 reply_hdr->flags = htonl(flags)(__uint32_t)(__builtin_constant_p(flags) ? (__uint32_t)(((__uint32_t
)(flags) & 0xff) << 24 | ((__uint32_t)(flags) &
0xff00) << 8 | ((__uint32_t)(flags) & 0xff0000) >>
8 | ((__uint32_t)(flags) & 0xff000000) >> 24) : __swap32md
(flags))
;
3348
3349 ctl_reply_size = CTL_REPLY_SIZE(strlen(reply_text) + (sizeof(struct ctl_reply_hdr)));
3350 log_debug("ctlcmd reply length %lu", (u_long)ctl_reply_size);
3351
3352 /* Otherwise, set up to write out reply */
3353 ctl_state = (ctl_cmd.cmd == CMD_READ_CONT6) ?
3354 CTL_WRITING_CONT_REPLY3 : CTL_WRITING_REPLY2;
3355
3356 event_add(ev_ctlwrite, NULL((void*)0));
3357
3358 /* another syslogc can kick us out */
3359 if (ctl_state == CTL_WRITING_CONT_REPLY3)
3360 event_add(ev_ctlaccept, NULL((void*)0));
3361}
3362
3363void
3364ctlconn_writecb(int fd, short event, void *arg)
3365{
3366 struct event *ev = arg;
3367 ssize_t n;
3368
3369 if (!(ctl_state == CTL_WRITING_REPLY2 ||
3370 ctl_state == CTL_WRITING_CONT_REPLY3)) {
3371 /* Shouldn't be here! */
3372 log_warnx("control socket write with bad state");
3373 ctlconn_cleanup();
3374 return;
3375 }
3376
3377 retry:
3378 n = write(fd, ctl_reply + ctl_reply_offset,
3379 ctl_reply_size - ctl_reply_offset);
3380 switch (n) {
3381 case -1:
3382 if (errno(*__errno()) == EINTR4)
3383 goto retry;
3384 if (errno(*__errno()) == EWOULDBLOCK35)
3385 return;
3386 if (errno(*__errno()) != EPIPE32)
3387 log_warn("write control socket");
3388 /* FALLTHROUGH */
3389 case 0:
3390 ctlconn_cleanup();
3391 return;
3392 default:
3393 ctl_reply_offset += n;
3394 }
3395 if (ctl_reply_offset < ctl_reply_size)
3396 return;
3397
3398 if (ctl_state != CTL_WRITING_CONT_REPLY3) {
3399 ctlconn_cleanup();
3400 return;
3401 }
3402
3403 /*
3404 * Make space in the buffer for continous writes.
3405 * Set offset behind reply header to skip it
3406 */
3407 *reply_text = '\0';
3408 ctl_reply_offset = ctl_reply_size = CTL_REPLY_SIZE(strlen(reply_text) + (sizeof(struct ctl_reply_hdr)));
3409
3410 /* Now is a good time to report dropped lines */
3411 if (membuf_drop) {
3412 strlcat(reply_text, "<ENOBUFS>\n", MAX_MEMBUF(256 * 1024));
3413 ctl_reply_size = CTL_REPLY_SIZE(strlen(reply_text) + (sizeof(struct ctl_reply_hdr)));
3414 membuf_drop = 0;
3415 } else {
3416 /* Nothing left to write */
3417 event_del(ev);
3418 }
3419}
3420
3421/* Shorten replytext to number of lines */
3422void
3423tailify_replytext(char *replytext, int lines)
3424{
3425 char *start, *nl;
3426 int count = 0;
3427 start = nl = replytext;
3428
3429 while ((nl = strchr(nl, '\n')) != NULL((void*)0)) {
3430 nl++;
3431 if (++count > lines) {
3432 start = strchr(start, '\n');
3433 start++;
3434 }
3435 }
3436 if (start != replytext) {
3437 int len = strlen(start);
3438 memmove(replytext, start, len);
3439 *(replytext + len) = '\0';
3440 }
3441}
3442
3443void
3444ctlconn_logto(char *line)
3445{
3446 size_t l;
3447
3448 if (membuf_drop)
3449 return;
3450
3451 l = strlen(line);
3452 if (l + 2 > (CTL_REPLY_MAXSIZE((sizeof(struct ctl_reply_hdr)) + (256 * 1024)) - ctl_reply_size)) {
3453 /* remember line drops for later report */
3454 membuf_drop = 1;
3455 return;
3456 }
3457 memcpy(ctl_reply + ctl_reply_size, line, l);
3458 memcpy(ctl_reply + ctl_reply_size + l, "\n", 2);
3459 ctl_reply_size += l + 1;
3460 event_add(ev_ctlwrite, NULL((void*)0));
3461}