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