]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/logger.c
logger: handle failures of gettimeofday()
[thirdparty/util-linux.git] / misc-utils / logger.c
1 /*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
34 * - added Native Language Support
35 * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
36 * - fixed strerr(errno) in gettext calls
37 */
38
39 #include <errno.h>
40 #include <limits.h>
41 #include <unistd.h>
42 #include <stdlib.h>
43 #include <sys/time.h>
44 #include <stdio.h>
45 #include <ctype.h>
46 #include <string.h>
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <sys/un.h>
50 #include <arpa/inet.h>
51 #include <netdb.h>
52 #include <getopt.h>
53 #include <pwd.h>
54 #include <signal.h>
55 #include <sys/uio.h>
56
57 #include "all-io.h"
58 #include "c.h"
59 #include "closestream.h"
60 #include "nls.h"
61 #include "pathnames.h"
62 #include "strutils.h"
63 #include "xalloc.h"
64 #include "strv.h"
65 #include "list.h"
66 #include "pwdutils.h"
67
68 #define SYSLOG_NAMES
69 #include <syslog.h>
70
71 #ifdef HAVE_LIBSYSTEMD
72 # define SD_JOURNAL_SUPPRESS_LOCATION
73 # include <systemd/sd-daemon.h>
74 # include <systemd/sd-journal.h>
75 #endif
76
77 #ifdef HAVE_SYS_TIMEX_H
78 # include <sys/timex.h>
79 #endif
80
81 enum {
82 TYPE_UDP = (1 << 1),
83 TYPE_TCP = (1 << 2),
84 ALL_TYPES = TYPE_UDP | TYPE_TCP
85 };
86
87 enum {
88 AF_UNIX_ERRORS_OFF = 0,
89 AF_UNIX_ERRORS_ON,
90 AF_UNIX_ERRORS_AUTO
91 };
92
93 enum {
94 OPT_PRIO_PREFIX = CHAR_MAX + 1,
95 OPT_JOURNALD,
96 OPT_RFC3164,
97 OPT_RFC5424,
98 OPT_SOCKET_ERRORS,
99 OPT_MSGID,
100 OPT_NOACT,
101 OPT_ID,
102 OPT_STRUCTURED_DATA_ID,
103 OPT_STRUCTURED_DATA_PARAM,
104 OPT_OCTET_COUNT
105 };
106
107 /* rfc5424 structured data */
108 struct structured_data {
109 char *id; /* SD-ID */
110 char **params; /* array with SD-PARAMs */
111
112 struct list_head sds;
113 };
114
115 struct logger_ctl {
116 int fd;
117 int pri;
118 pid_t pid; /* zero when unwanted */
119 char *hdr; /* the syslog header (based on protocol) */
120 char const *tag;
121 char *login;
122 char *msgid;
123 char *unix_socket; /* -u <path> or default to _PATH_DEVLOG */
124 char *server;
125 char *port;
126 int socket_type;
127 size_t max_message_size;
128 struct list_head user_sds; /* user defined rfc5424 structured data */
129 struct list_head reserved_sds; /* standard rfc5424 structured data */
130
131 void (*syslogfp)(struct logger_ctl *ctl);
132
133 unsigned int
134 unix_socket_errors:1, /* whether to report or not errors */
135 noact:1, /* do not write to sockets */
136 prio_prefix:1, /* read priority from input */
137 stderr_printout:1, /* output message to stderr */
138 rfc5424_time:1, /* include time stamp */
139 rfc5424_tq:1, /* include time quality markup */
140 rfc5424_host:1, /* include hostname */
141 skip_empty_lines:1, /* do not send empty lines when processing files */
142 octet_count:1; /* use RFC6587 octet counting */
143 };
144
145 #define is_connected(_ctl) ((_ctl)->fd >= 0)
146 static void logger_reopen(struct logger_ctl *ctl);
147
148 /*
149 * For tests we want to be able to control datetime outputs
150 */
151 #ifdef TEST_LOGGER
152 static inline int logger_gettimeofday(struct timeval *tv, struct timezone *tz)
153 {
154 char *str = getenv("LOGGER_TEST_TIMEOFDAY");
155 uintmax_t sec, usec;
156
157 if (str && sscanf(str, "%ju.%ju", &sec, &usec) == 2) {
158 tv->tv_sec = sec;
159 tv->tv_usec = usec;
160 return tv->tv_sec >= 0 && tv->tv_usec >= 0 ? 0 : -EINVAL;
161 }
162
163 return gettimeofday(tv, tz);
164 }
165
166 static inline char *logger_xgethostname(void)
167 {
168 char *str = getenv("LOGGER_TEST_HOSTNAME");
169 return str ? xstrdup(str) : xgethostname();
170 }
171
172 static inline pid_t logger_getpid(void)
173 {
174 char *str = getenv("LOGGER_TEST_GETPID");
175 unsigned int pid;
176
177 if (str && sscanf(str, "%u", &pid) == 1)
178 return pid;
179 return getpid();
180 }
181
182
183 #undef HAVE_NTP_GETTIME /* force to default non-NTP */
184
185 #else /* !TEST_LOGGER */
186 # define logger_gettimeofday(x, y) gettimeofday(x, y)
187 # define logger_xgethostname xgethostname
188 # define logger_getpid getpid
189 #endif
190
191
192 static int decode(const char *name, const CODE *codetab)
193 {
194 register const CODE *c;
195
196 if (name == NULL || *name == '\0')
197 return -1;
198 if (isdigit(*name)) {
199 int num;
200 char *end = NULL;
201
202 errno = 0;
203 num = strtol(name, &end, 10);
204 if (errno || name == end || (end && *end))
205 return -1;
206 for (c = codetab; c->c_name; c++)
207 if (num == c->c_val)
208 return num;
209 return -1;
210 }
211 for (c = codetab; c->c_name; c++)
212 if (!strcasecmp(name, c->c_name))
213 return (c->c_val);
214
215 return -1;
216 }
217
218 static int pencode(char *s)
219 {
220 int facility, level;
221 char *separator;
222
223 assert(s);
224
225 separator = strchr(s, '.');
226 if (separator) {
227 *separator = '\0';
228 facility = decode(s, facilitynames);
229 if (facility < 0)
230 errx(EXIT_FAILURE, _("unknown facility name: %s"), s);
231 s = ++separator;
232 } else
233 facility = LOG_USER;
234 level = decode(s, prioritynames);
235 if (level < 0)
236 errx(EXIT_FAILURE, _("unknown priority name: %s"), s);
237 if (facility == LOG_KERN)
238 facility = LOG_USER; /* kern is forbidden */
239 return ((level & LOG_PRIMASK) | (facility & LOG_FACMASK));
240 }
241
242 static int unix_socket(struct logger_ctl *ctl, const char *path, int *socket_type)
243 {
244 int fd = -1, i, type = -1;
245 static struct sockaddr_un s_addr; /* AF_UNIX address of local logger */
246
247 if (strlen(path) >= sizeof(s_addr.sun_path))
248 errx(EXIT_FAILURE, _("openlog %s: pathname too long"), path);
249
250 s_addr.sun_family = AF_UNIX;
251 xstrncpy(s_addr.sun_path, path, sizeof(s_addr.sun_path));
252
253 for (i = 2; i; i--) {
254 int st = -1;
255
256 if (i == 2 && *socket_type & TYPE_UDP) {
257 st = SOCK_DGRAM;
258 type = TYPE_UDP;
259 }
260 if (i == 1 && *socket_type & TYPE_TCP) {
261 st = SOCK_STREAM;
262 type = TYPE_TCP;
263 }
264 if (st == -1 || (fd = socket(AF_UNIX, st, 0)) == -1)
265 continue;
266 if (connect(fd, (struct sockaddr *)&s_addr, sizeof(s_addr)) == -1) {
267 close(fd);
268 continue;
269 }
270 break;
271 }
272
273 if (i == 0) {
274 if (ctl->unix_socket_errors)
275 err(EXIT_FAILURE, _("socket %s"), path);
276
277 /* write_output() will try to reconnect */
278 return -1;
279 }
280
281 /* replace ALL_TYPES with the real TYPE_* */
282 if (type > 0 && type != *socket_type)
283 *socket_type = type;
284 return fd;
285 }
286
287 static int inet_socket(const char *servername, const char *port, int *socket_type)
288 {
289 int fd, errcode, i, type = -1;
290 struct addrinfo hints, *res;
291 const char *p = port;
292
293 for (i = 2; i; i--) {
294 memset(&hints, 0, sizeof(hints));
295 if (i == 2 && *socket_type & TYPE_UDP) {
296 hints.ai_socktype = SOCK_DGRAM;
297 type = TYPE_UDP;
298 if (port == NULL)
299 p = "syslog";
300 }
301 if (i == 1 && *socket_type & TYPE_TCP) {
302 hints.ai_socktype = SOCK_STREAM;
303 type = TYPE_TCP;
304 if (port == NULL)
305 p = "syslog-conn";
306 }
307 if (hints.ai_socktype == 0)
308 continue;
309 hints.ai_family = AF_UNSPEC;
310 errcode = getaddrinfo(servername, p, &hints, &res);
311 if (errcode != 0)
312 errx(EXIT_FAILURE, _("failed to resolve name %s port %s: %s"),
313 servername, p, gai_strerror(errcode));
314 if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
315 freeaddrinfo(res);
316 continue;
317 }
318 if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) {
319 freeaddrinfo(res);
320 close(fd);
321 continue;
322 }
323
324 freeaddrinfo(res);
325 break;
326 }
327
328 if (i == 0)
329 errx(EXIT_FAILURE, _("failed to connect to %s port %s"), servername, p);
330
331 /* replace ALL_TYPES with the real TYPE_* */
332 if (type > 0 && type != *socket_type)
333 *socket_type = type;
334 return fd;
335 }
336
337 #ifdef HAVE_LIBSYSTEMD
338 static int journald_entry(struct logger_ctl *ctl, FILE *fp)
339 {
340 struct iovec *iovec;
341 char *buf = NULL;
342 ssize_t sz;
343 int n, lines = 0, vectors = 8, ret = 0, msgline = -1;
344 size_t dummy = 0;
345
346 iovec = xreallocarray(NULL, vectors, sizeof(struct iovec));
347 while (1) {
348 buf = NULL;
349 sz = getline(&buf, &dummy, fp);
350 if (sz == -1 ||
351 (sz = rtrim_whitespace((unsigned char *) buf)) == 0) {
352 free(buf);
353 break;
354 }
355
356 if (strncmp(buf, "MESSAGE=", 8) == 0) {
357 if (msgline == -1)
358 msgline = lines; /* remember the first message */
359 else {
360 char *p = xrealloc(iovec[msgline].iov_base,
361 iovec[msgline].iov_len + sz - 8 + 2);
362
363 iovec[msgline].iov_base = p;
364 p += iovec[msgline].iov_len;
365 *p++ = '\n';
366 memcpy(p, buf + 8, sz - 8);
367 free(buf);
368
369 iovec[msgline].iov_len += sz - 8 + 1;
370 continue;
371 }
372 }
373
374 if (lines == vectors) {
375 vectors *= 2;
376 if (IOV_MAX < vectors)
377 errx(EXIT_FAILURE, _("maximum input lines (%d) exceeded"), IOV_MAX);
378 iovec = xreallocarray(iovec, vectors, sizeof(struct iovec));
379 }
380 iovec[lines].iov_base = buf;
381 iovec[lines].iov_len = sz;
382 ++lines;
383 }
384
385 if (!ctl->noact)
386 ret = sd_journal_sendv(iovec, lines);
387 if (ctl->stderr_printout) {
388 for (n = 0; n < lines; n++)
389 fprintf(stderr, "%s\n", (char *) iovec[n].iov_base);
390 }
391 for (n = 0; n < lines; n++)
392 free(iovec[n].iov_base);
393 free(iovec);
394 return ret;
395 }
396 #endif
397
398 /* this creates a timestamp based on current time according to the
399 * fine rules of RFC3164, most importantly it ensures in a portable
400 * way that the month day is correctly written (with a SP instead
401 * of a leading 0). The function uses a static buffer which is
402 * overwritten on the next call (just like ctime() does).
403 */
404 static char const *rfc3164_current_time(void)
405 {
406 static char time[32];
407 struct timeval tv;
408 struct tm tm;
409 int ret;
410 static char const * const monthnames[] = {
411 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
412 "Sep", "Oct", "Nov", "Dec"
413 };
414
415 ret = logger_gettimeofday(&tv, NULL);
416 if (ret == -1)
417 err(EXIT_FAILURE, _("gettimeofday() failed"));
418 localtime_r(&tv.tv_sec, &tm);
419 snprintf(time, sizeof(time),"%s %2d %2.2d:%2.2d:%2.2d",
420 monthnames[tm.tm_mon], tm.tm_mday,
421 tm.tm_hour, tm.tm_min, tm.tm_sec);
422 return time;
423 }
424
425 #define next_iovec(ary, idx) __extension__ ({ \
426 assert(ARRAY_SIZE(ary) > (size_t)idx); \
427 assert(idx >= 0); \
428 &ary[idx++]; \
429 })
430
431 #define iovec_add_string(ary, idx, str, len) \
432 do { \
433 struct iovec *v = next_iovec(ary, idx); \
434 v->iov_base = (void *) str; \
435 v->iov_len = len ? len : strlen(str); \
436 } while (0)
437
438 #define iovec_memcmp(ary, idx, str, len) \
439 memcmp((ary)[(idx) - 1].iov_base, str, len)
440
441 /* writes generated buffer to desired destination. For TCP syslog,
442 * we use RFC6587 octet-stuffing (unless octet-counting is selected).
443 * This is not great, but doing full blown RFC5425 (TLS) looks like
444 * it is too much for the logger utility. If octet-counting is
445 * selected, we use that.
446 */
447 static void write_output(struct logger_ctl *ctl, const char *const msg)
448 {
449 struct iovec iov[4];
450 int iovlen = 0;
451 char *octet = NULL;
452
453 /* initial connect failed? */
454 if (!ctl->noact && !is_connected(ctl))
455 logger_reopen(ctl);
456
457 /* 1) octet count */
458 if (ctl->octet_count) {
459 size_t len = xasprintf(&octet, "%zu ", strlen(ctl->hdr) + strlen(msg));
460 iovec_add_string(iov, iovlen, octet, len);
461 }
462
463 /* 2) header */
464 iovec_add_string(iov, iovlen, ctl->hdr, 0);
465
466 /* 3) message */
467 iovec_add_string(iov, iovlen, msg, 0);
468
469 if (!ctl->noact && is_connected(ctl)) {
470 struct msghdr message = { 0 };
471 #ifdef SCM_CREDENTIALS
472 struct cmsghdr *cmhp;
473 struct ucred *cred;
474 union {
475 struct cmsghdr cmh;
476 char control[CMSG_SPACE(sizeof(struct ucred))];
477 } cbuf = { .control = { 0 } };
478 #endif
479
480 /* 4) add extra \n to make sure message is terminated */
481 if ((ctl->socket_type == TYPE_TCP) && !ctl->octet_count)
482 iovec_add_string(iov, iovlen, "\n", 1);
483
484 message.msg_iov = iov;
485 message.msg_iovlen = iovlen;
486
487 #ifdef SCM_CREDENTIALS
488 /* syslog/journald may follow local socket credentials rather
489 * than in the message PID. If we use --id as root than we can
490 * force kernel to accept another valid PID than the real logger(1)
491 * PID.
492 */
493 if (ctl->pid && !ctl->server && ctl->pid != getpid()
494 && geteuid() == 0 && kill(ctl->pid, 0) == 0) {
495
496 message.msg_control = cbuf.control;
497 message.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
498
499 cmhp = CMSG_FIRSTHDR(&message);
500 cmhp->cmsg_len = CMSG_LEN(sizeof(struct ucred));
501 cmhp->cmsg_level = SOL_SOCKET;
502 cmhp->cmsg_type = SCM_CREDENTIALS;
503 cred = (struct ucred *) CMSG_DATA(cmhp);
504
505 cred->pid = ctl->pid;
506 }
507 #endif
508 /* Note that logger(1) maybe executed for long time (as pipe
509 * reader) and connection endpoint (syslogd) may be restarted.
510 *
511 * The libc syslog() function reconnects on failed send().
512 * Let's do the same to be robust. [kzak -- Oct 2017]
513 *
514 * MSG_NOSIGNAL is POSIX.1-2008 compatible, but it for example
515 * not supported by apple-darwin15.6.0.
516 */
517 #ifndef MSG_NOSIGNAL
518 # define MSG_NOSIGNAL 0
519 #endif
520 if (sendmsg(ctl->fd, &message, MSG_NOSIGNAL) < 0) {
521 logger_reopen(ctl);
522 if (sendmsg(ctl->fd, &message, MSG_NOSIGNAL) < 0)
523 warn(_("send message failed"));
524 }
525 }
526
527 if (ctl->stderr_printout) {
528 /* make sure it's terminated for stderr */
529 if (iovec_memcmp(iov, iovlen, "\n", 1) != 0)
530 iovec_add_string(iov, iovlen, "\n", 1);
531
532 ignore_result( writev(STDERR_FILENO, iov, iovlen) );
533 }
534
535 free(octet);
536 }
537
538 #define NILVALUE "-"
539 static void syslog_rfc3164_header(struct logger_ctl *const ctl)
540 {
541 char pid[30], *hostname;
542
543 *pid = '\0';
544 if (ctl->pid)
545 snprintf(pid, sizeof(pid), "[%d]", ctl->pid);
546
547 if ((hostname = logger_xgethostname())) {
548 char *dot = strchr(hostname, '.');
549 if (dot)
550 *dot = '\0';
551 } else
552 hostname = xstrdup(NILVALUE);
553
554 xasprintf(&ctl->hdr, "<%d>%.15s %s %.200s%s: ",
555 ctl->pri, rfc3164_current_time(), hostname, ctl->tag, pid);
556
557 free(hostname);
558 }
559
560 static inline struct list_head *get_user_structured_data(struct logger_ctl *ctl)
561 {
562 return &ctl->user_sds;
563 }
564
565 static inline struct list_head *get_reserved_structured_data(struct logger_ctl *ctl)
566 {
567 return &ctl->reserved_sds;
568 }
569
570 static int has_structured_data_id(struct list_head *ls, const char *id)
571 {
572 struct list_head *p;
573
574 if (!ls || list_empty(ls))
575 return 0;
576
577 list_for_each(p, ls) {
578 struct structured_data *sd = list_entry(p, struct structured_data, sds);
579 if (sd->id && strcmp(sd->id, id) == 0)
580 return 1;
581 }
582
583 return 0;
584 }
585
586 static void add_structured_data_id(struct list_head *ls, const char *id)
587 {
588 struct structured_data *sd;
589
590 assert(id);
591
592 if (has_structured_data_id(ls, id))
593 errx(EXIT_FAILURE, _("structured data ID '%s' is not unique"), id);
594
595 sd = xcalloc(1, sizeof(*sd));
596 INIT_LIST_HEAD(&sd->sds);
597 sd->id = xstrdup(id);
598
599 list_add_tail(&sd->sds, ls);
600 }
601
602 static void add_structured_data_param(struct list_head *ls, const char *param)
603 {
604 struct structured_data *sd;
605
606 if (list_empty(ls))
607 errx(EXIT_FAILURE, _("--sd-id was not specified for --sd-param %s"), param);
608
609 assert(param);
610
611 sd = list_last_entry(ls, struct structured_data, sds);
612
613 if (strv_extend(&sd->params, param))
614 err_oom();
615 }
616
617 static void __attribute__ ((__format__ (__printf__, 2, 3)))
618 add_structured_data_paramf(struct list_head *ls, const char *fmt, ...)
619 {
620 struct structured_data *sd;
621 va_list ap;
622 int x;
623
624 assert(!list_empty(ls));
625 assert(fmt);
626
627 sd = list_last_entry(ls, struct structured_data, sds);
628 va_start(ap, fmt);
629 x = strv_extendv(&sd->params, fmt, ap);
630 va_end(ap);
631
632 if (x)
633 err_oom();
634 }
635
636 static char *strdup_structured_data(struct structured_data *sd)
637 {
638 char *res, *tmp;
639
640 if (strv_isempty(sd->params))
641 return NULL;
642
643 xasprintf(&res, "[%s %s]", sd->id,
644 (tmp = strv_join(sd->params, " ")));
645 free(tmp);
646 return res;
647 }
648
649 static char *strdup_structured_data_list(struct list_head *ls)
650 {
651 struct list_head *p;
652 char *res = NULL;
653
654 list_for_each(p, ls) {
655 struct structured_data *sd = list_entry(p, struct structured_data, sds);
656 char *one = strdup_structured_data(sd);
657 char *tmp = res;
658
659 if (!one)
660 continue;
661 res = strconcat(tmp, one);
662 free(tmp);
663 free(one);
664 }
665
666 return res;
667 }
668
669 static char *get_structured_data_string(struct logger_ctl *ctl)
670 {
671 char *sys = NULL, *usr = NULL, *res;
672
673 if (!list_empty(&ctl->reserved_sds))
674 sys = strdup_structured_data_list(&ctl->reserved_sds);
675 if (!list_empty(&ctl->user_sds))
676 usr = strdup_structured_data_list(&ctl->user_sds);
677
678 if (sys && usr) {
679 res = strconcat(sys, usr);
680 free(sys);
681 free(usr);
682 } else
683 res = sys ? sys : usr;
684
685 return res;
686 }
687
688 static int valid_structured_data_param(const char *str)
689 {
690 char *s;
691 char *eq = strchr(str, '='),
692 *qm1 = strchr(str, '"'),
693 *qm2 = qm1 ? ul_strchr_escaped(qm1 + 1, '"') : NULL;
694
695 /* something is missing */
696 if (!eq || !qm1 || !qm2)
697 return 0;
698
699 /* ']' need to be escaped */
700 for (s = qm1 + 1; s && *s; ) {
701 char *p = strchr(s, ']');
702 if (!p)
703 break;
704 if (p > qm2 || p == ul_strchr_escaped(s, ']'))
705 return 0;
706 s = p + 1;
707 }
708
709 /* '\' is allowed only before '[]"\' chars */
710 for (s = qm1 + 1; s && *s; ) {
711 char *p = strchr(s, '\\');
712 if (!p)
713 break;
714 if (!strchr("[]\"\\", *(p + 1)))
715 return 0;
716 s = p + 1;
717 if (*s == '\\')
718 s++;
719 }
720
721 /* foo="bar" */
722 return eq > str && eq < qm1 && eq + 1 == qm1 && qm1 < qm2 && *(qm2 + 1) == '\0';
723 }
724
725 /* SD-ID format:
726 * name@<private enterprise number>, e.g., "ourSDID@32473"
727 */
728 static int valid_structured_data_id(const char *str)
729 {
730 char *at = strchr(str, '@');
731 const char *p;
732
733 /* standardized IDs without @<digits> */
734 if (!at && (strcmp(str, "timeQuality") == 0 ||
735 strcmp(str, "origin") == 0 ||
736 strcmp(str, "meta") == 0))
737 return 1;
738
739 if (!at || at == str || !*(at + 1))
740 return 0;
741
742 /* <digits> or <digits>.<digits>[...] */
743 for (p = at + 1; p && *p; p++) {
744 const char *end;
745
746 if (isdigit_strend(p, &end))
747 break; /* only digits in the string */
748
749 if (end == NULL || end == p ||
750 *end != '.' || *(end + 1) == '\0')
751 return 0;
752 p = end;
753 }
754
755 /* check for forbidden chars in the <name> */
756 for (p = str; p < at; p++) {
757 if (*p == '[' || *p == '=' || *p == '"' || *p == '@')
758 return 0;
759 if (isblank((unsigned char) *p) || iscntrl((unsigned char) *p))
760 return 0;
761 }
762 return 1;
763 }
764
765
766 /* Some field mappings may be controversial, thus I give the reason
767 * why this specific mapping was used:
768 * APP-NAME <-- tag
769 * Some may argue that "logger" is a better fit, but we think
770 * this is better inline of what other implementations do. In
771 * rsyslog, for example, the TAG value is populated from APP-NAME.
772 * PROCID <-- pid
773 * This is a relatively straightforward interpretation from
774 * RFC5424, sect. 6.2.6.
775 * MSGID <-- msgid (from --msgid)
776 * One may argue that the string "logger" would be better suited
777 * here so that a receiver can identify the sender process.
778 * However, this does not sound like a good match to RFC5424,
779 * sect. 6.2.7.
780 * Note that appendix A.1 of RFC5424 does not provide clear guidance
781 * of how these fields should be used. This is the case because the
782 * IETF working group couldn't arrive at a clear agreement when we
783 * specified RFC5424. The rest of the field mappings should be
784 * pretty clear from RFC5424. -- Rainer Gerhards, 2015-03-10
785 */
786 static void syslog_rfc5424_header(struct logger_ctl *const ctl)
787 {
788 int ret;
789 char *time;
790 char *hostname;
791 char const *app_name = ctl->tag;
792 char *procid;
793 char *const msgid = xstrdup(ctl->msgid ? ctl->msgid : NILVALUE);
794 char *structured = NULL;
795 struct list_head *sd;
796
797 if (ctl->rfc5424_time) {
798 struct timeval tv;
799 struct tm tm;
800
801 ret = logger_gettimeofday(&tv, NULL);
802 if (ret == -1)
803 err(EXIT_FAILURE, _("gettimeofday() failed"));
804 if (localtime_r(&tv.tv_sec, &tm) != NULL) {
805 char fmt[64];
806 const size_t i = strftime(fmt, sizeof(fmt),
807 "%Y-%m-%dT%H:%M:%S.%%06u%z ", &tm);
808 /* patch TZ info to comply with RFC3339 (we left SP at end) */
809 fmt[i - 1] = fmt[i - 2];
810 fmt[i - 2] = fmt[i - 3];
811 fmt[i - 3] = ':';
812 xasprintf(&time, fmt, tv.tv_usec);
813 } else
814 err(EXIT_FAILURE, _("localtime() failed"));
815 } else
816 time = xstrdup(NILVALUE);
817
818 if (ctl->rfc5424_host) {
819 if (!(hostname = logger_xgethostname()))
820 hostname = xstrdup(NILVALUE);
821 /* Arbitrary looking 'if (var < strlen()) checks originate from
822 * RFC 5424 - 6 Syslog Message Format definition. */
823 if (255 < strlen(hostname))
824 errx(EXIT_FAILURE, _("hostname '%s' is too long"),
825 hostname);
826 } else
827 hostname = xstrdup(NILVALUE);
828
829 if (48 < strlen(ctl->tag))
830 errx(EXIT_FAILURE, _("tag '%s' is too long"), ctl->tag);
831
832 if (ctl->pid)
833 xasprintf(&procid, "%d", ctl->pid);
834 else
835 procid = xstrdup(NILVALUE);
836
837 sd = get_reserved_structured_data(ctl);
838
839 /* time quality structured data (maybe overwritten by --sd-id timeQuality) */
840 if (ctl->rfc5424_tq && !has_structured_data_id(sd, "timeQuality")) {
841
842 add_structured_data_id(sd, "timeQuality");
843 add_structured_data_param(sd, "tzKnown=\"1\"");
844
845 #ifdef HAVE_NTP_GETTIME
846 struct ntptimeval ntptv;
847
848 if (ntp_gettime(&ntptv) == TIME_OK) {
849 add_structured_data_param(sd, "isSynced=\"1\"");
850 add_structured_data_paramf(sd, "syncAccuracy=\"%ld\"", ntptv.maxerror);
851 } else
852 #endif
853 add_structured_data_paramf(sd, "isSynced=\"0\"");
854 }
855
856 /* convert all structured data to string */
857 structured = get_structured_data_string(ctl);
858 if (!structured)
859 structured = xstrdup(NILVALUE);
860
861 xasprintf(&ctl->hdr, "<%d>1 %s %s %s %s %s %s ",
862 ctl->pri,
863 time,
864 hostname,
865 app_name,
866 procid,
867 msgid,
868 structured);
869
870 free(time);
871 free(hostname);
872 /* app_name points to ctl->tag, do NOT free! */
873 free(procid);
874 free(msgid);
875 free(structured);
876 }
877
878 static void parse_rfc5424_flags(struct logger_ctl *ctl, char *s)
879 {
880 char *in, *tok;
881
882 in = s;
883 while ((tok = strtok(in, ","))) {
884 in = NULL;
885 if (!strcmp(tok, "notime")) {
886 ctl->rfc5424_time = 0;
887 ctl->rfc5424_tq = 0;
888 } else if (!strcmp(tok, "notq"))
889 ctl->rfc5424_tq = 0;
890 else if (!strcmp(tok, "nohost"))
891 ctl->rfc5424_host = 0;
892 else
893 warnx(_("ignoring unknown option argument: %s"), tok);
894 }
895 }
896
897 static int parse_unix_socket_errors_flags(char *s)
898 {
899 if (!strcmp(s, "off"))
900 return AF_UNIX_ERRORS_OFF;
901 if (!strcmp(s, "on"))
902 return AF_UNIX_ERRORS_ON;
903 if (!strcmp(s, "auto"))
904 return AF_UNIX_ERRORS_AUTO;
905 warnx(_("invalid argument: %s: using automatic errors"), s);
906 return AF_UNIX_ERRORS_AUTO;
907 }
908
909 static void syslog_local_header(struct logger_ctl *const ctl)
910 {
911 char pid[32];
912
913 if (ctl->pid)
914 snprintf(pid, sizeof(pid), "[%d]", ctl->pid);
915 else
916 pid[0] = '\0';
917
918 xasprintf(&ctl->hdr, "<%d>%s %s%s: ", ctl->pri, rfc3164_current_time(),
919 ctl->tag, pid);
920 }
921
922 static void generate_syslog_header(struct logger_ctl *const ctl)
923 {
924 free(ctl->hdr);
925 ctl->hdr = NULL;
926 ctl->syslogfp(ctl);
927 }
928
929 /* just open, nothing else */
930 static void __logger_open(struct logger_ctl *ctl)
931 {
932 if (ctl->server) {
933 ctl->fd = inet_socket(ctl->server, ctl->port, &ctl->socket_type);
934 } else {
935 if (!ctl->unix_socket)
936 ctl->unix_socket = _PATH_DEVLOG;
937
938 ctl->fd = unix_socket(ctl, ctl->unix_socket, &ctl->socket_type);
939 }
940 }
941
942 /* open and initialize relevant @ctl tuff */
943 static void logger_open(struct logger_ctl *ctl)
944 {
945 __logger_open(ctl);
946
947 if (!ctl->syslogfp)
948 ctl->syslogfp = ctl->server ? syslog_rfc5424_header :
949 syslog_local_header;
950 if (!ctl->tag)
951 ctl->tag = ctl->login = xgetlogin();
952 if (!ctl->tag)
953 ctl->tag = "<someone>";
954 }
955
956 /* re-open; usually after failed connection */
957 static void logger_reopen(struct logger_ctl *ctl)
958 {
959 if (ctl->fd != -1)
960 close(ctl->fd);
961 ctl->fd = -1;
962
963 __logger_open(ctl);
964 }
965
966 static void logger_command_line(struct logger_ctl *ctl, char **argv)
967 {
968 /* note: we never re-generate the syslog header here, even if we
969 * generate multiple messages. If so, we think it is the right thing
970 * to do to report them with the same timestamp, as the user actually
971 * intended to send a single message.
972 */
973 char *const buf = xmalloc(ctl->max_message_size + 1);
974 char *p = buf;
975 const char *endp = buf + ctl->max_message_size - 1;
976 size_t len;
977
978 while (*argv) {
979 len = strlen(*argv);
980 if (endp < p + len && p != buf) {
981 write_output(ctl, buf);
982 p = buf;
983 }
984 if (ctl->max_message_size < len) {
985 (*argv)[ctl->max_message_size] = '\0'; /* truncate */
986 write_output(ctl, *argv++);
987 continue;
988 }
989 if (p != buf)
990 *p++ = ' ';
991 memmove(p, *argv++, len);
992 *(p += len) = '\0';
993 }
994 if (p != buf)
995 write_output(ctl, buf);
996 free(buf);
997 }
998
999 static void logger_stdin(struct logger_ctl *ctl)
1000 {
1001 /* note: we re-generate the syslog header for each log message to
1002 * update header timestamps and to reflect possible priority changes.
1003 */
1004 int default_priority = ctl->pri;
1005 char *buf = xmalloc(ctl->max_message_size + 2 + 2);
1006 int pri;
1007 int c;
1008 size_t i;
1009
1010 c = getchar();
1011 while (c != EOF) {
1012 i = 0;
1013 if (ctl->prio_prefix && c == '<') {
1014 pri = 0;
1015 buf[i++] = c;
1016 while (isdigit(c = getchar()) && pri <= 191) {
1017 buf[i++] = c;
1018 pri = pri * 10 + c - '0';
1019 }
1020 if (c != EOF && c != '\n')
1021 buf[i++] = c;
1022 if (c == '>' && 0 <= pri && pri <= 191) {
1023 /* valid RFC PRI values */
1024 i = 0;
1025 if ((pri & LOG_FACMASK) == 0)
1026 pri |= (default_priority & LOG_FACMASK);
1027 ctl->pri = pri;
1028 } else
1029 ctl->pri = default_priority;
1030
1031 if (c != EOF && c != '\n')
1032 c = getchar();
1033 }
1034
1035 while (c != EOF && c != '\n' && i < ctl->max_message_size) {
1036 buf[i++] = c;
1037 c = getchar();
1038 }
1039 buf[i] = '\0';
1040
1041 if (i > 0 || !ctl->skip_empty_lines) {
1042 generate_syslog_header(ctl);
1043 write_output(ctl, buf);
1044 }
1045
1046 if (c == '\n') /* discard line terminator */
1047 c = getchar();
1048 }
1049
1050 free(buf);
1051 }
1052
1053 static void logger_close(const struct logger_ctl *ctl)
1054 {
1055 if (ctl->fd != -1 && close(ctl->fd) != 0)
1056 err(EXIT_FAILURE, _("close failed"));
1057 free(ctl->hdr);
1058 free(ctl->login);
1059 }
1060
1061 static void __attribute__((__noreturn__)) usage(void)
1062 {
1063 FILE *out = stdout;
1064 fputs(USAGE_HEADER, out);
1065 fprintf(out, _(" %s [options] [<message>]\n"), program_invocation_short_name);
1066
1067 fputs(USAGE_SEPARATOR, out);
1068 fputs(_("Enter messages into the system log.\n"), out);
1069
1070 fputs(USAGE_OPTIONS, out);
1071 fputs(_(" -i log the logger command's PID\n"), out);
1072 fputs(_(" --id[=<id>] log the given <id>, or otherwise the PID\n"), out);
1073 fputs(_(" -f, --file <file> log the contents of this file\n"), out);
1074 fputs(_(" -e, --skip-empty do not log empty lines when processing files\n"), out);
1075 fputs(_(" --no-act do everything except the write the log\n"), out);
1076 fputs(_(" -p, --priority <prio> mark given message with this priority\n"), out);
1077 fputs(_(" --octet-count use rfc6587 octet counting\n"), out);
1078 fputs(_(" --prio-prefix look for a prefix on every line read from stdin\n"), out);
1079 fputs(_(" -s, --stderr output message to standard error as well\n"), out);
1080 fputs(_(" -S, --size <size> maximum size for a single message\n"), out);
1081 fputs(_(" -t, --tag <tag> mark every line with this tag\n"), out);
1082 fputs(_(" -n, --server <name> write to this remote syslog server\n"), out);
1083 fputs(_(" -P, --port <port> use this port for UDP or TCP connection\n"), out);
1084 fputs(_(" -T, --tcp use TCP only\n"), out);
1085 fputs(_(" -d, --udp use UDP only\n"), out);
1086 fputs(_(" --rfc3164 use the obsolete BSD syslog protocol\n"), out);
1087 fputs(_(" --rfc5424[=<snip>] use the syslog protocol (the default for remote);\n"
1088 " <snip> can be notime, or notq, and/or nohost\n"), out);
1089 fputs(_(" --sd-id <id> rfc5424 structured data ID\n"), out);
1090 fputs(_(" --sd-param <data> rfc5424 structured data name=value\n"), out);
1091 fputs(_(" --msgid <msgid> set rfc5424 message id field\n"), out);
1092 fputs(_(" -u, --socket <socket> write to this Unix socket\n"), out);
1093 fputs(_(" --socket-errors[=<on|off|auto>]\n"
1094 " print connection errors when using Unix sockets\n"), out);
1095 #ifdef HAVE_LIBSYSTEMD
1096 fputs(_(" --journald[=<file>] write journald entry\n"), out);
1097 #endif
1098
1099 fputs(USAGE_SEPARATOR, out);
1100 fprintf(out, USAGE_HELP_OPTIONS(26));
1101 fprintf(out, USAGE_MAN_TAIL("logger(1)"));
1102
1103 exit(EXIT_SUCCESS);
1104 }
1105
1106 /*
1107 * logger -- read and log utility
1108 *
1109 * Reads from an input and arranges to write the result on the system
1110 * log.
1111 */
1112 int main(int argc, char **argv)
1113 {
1114 struct logger_ctl ctl = {
1115 .fd = -1,
1116 .pid = 0,
1117 .pri = LOG_USER | LOG_NOTICE,
1118 .prio_prefix = 0,
1119 .tag = NULL,
1120 .unix_socket = NULL,
1121 .unix_socket_errors = 0,
1122 .server = NULL,
1123 .port = NULL,
1124 .hdr = NULL,
1125 .msgid = NULL,
1126 .socket_type = ALL_TYPES,
1127 .max_message_size = 1024,
1128 .rfc5424_time = 1,
1129 .rfc5424_tq = 1,
1130 .rfc5424_host = 1,
1131 .skip_empty_lines = 0
1132 };
1133 int ch;
1134 int stdout_reopened = 0;
1135 int unix_socket_errors_mode = AF_UNIX_ERRORS_AUTO;
1136 #ifdef HAVE_LIBSYSTEMD
1137 FILE *jfd = NULL;
1138 #endif
1139 static const struct option longopts[] = {
1140 { "id", optional_argument, 0, OPT_ID },
1141 { "stderr", no_argument, 0, 's' },
1142 { "file", required_argument, 0, 'f' },
1143 { "no-act", no_argument, 0, OPT_NOACT, },
1144 { "priority", required_argument, 0, 'p' },
1145 { "tag", required_argument, 0, 't' },
1146 { "socket", required_argument, 0, 'u' },
1147 { "socket-errors", required_argument, 0, OPT_SOCKET_ERRORS },
1148 { "udp", no_argument, 0, 'd' },
1149 { "tcp", no_argument, 0, 'T' },
1150 { "server", required_argument, 0, 'n' },
1151 { "port", required_argument, 0, 'P' },
1152 { "version", no_argument, 0, 'V' },
1153 { "help", no_argument, 0, 'h' },
1154 { "octet-count", no_argument, 0, OPT_OCTET_COUNT },
1155 { "prio-prefix", no_argument, 0, OPT_PRIO_PREFIX },
1156 { "rfc3164", no_argument, 0, OPT_RFC3164 },
1157 { "rfc5424", optional_argument, 0, OPT_RFC5424 },
1158 { "size", required_argument, 0, 'S' },
1159 { "msgid", required_argument, 0, OPT_MSGID },
1160 { "skip-empty", no_argument, 0, 'e' },
1161 { "sd-id", required_argument, 0, OPT_STRUCTURED_DATA_ID },
1162 { "sd-param", required_argument, 0, OPT_STRUCTURED_DATA_PARAM },
1163 #ifdef HAVE_LIBSYSTEMD
1164 { "journald", optional_argument, 0, OPT_JOURNALD },
1165 #endif
1166 { NULL, 0, 0, 0 }
1167 };
1168
1169 setlocale(LC_ALL, "");
1170 bindtextdomain(PACKAGE, LOCALEDIR);
1171 textdomain(PACKAGE);
1172 close_stdout_atexit();
1173
1174 INIT_LIST_HEAD(&ctl.user_sds);
1175 INIT_LIST_HEAD(&ctl.reserved_sds);
1176
1177 while ((ch = getopt_long(argc, argv, "ef:ip:S:st:u:dTn:P:Vh",
1178 longopts, NULL)) != -1) {
1179 switch (ch) {
1180 case 'f': /* file to log */
1181 if (freopen(optarg, "r", stdin) == NULL)
1182 err(EXIT_FAILURE, _("file %s"), optarg);
1183 stdout_reopened = 1;
1184 break;
1185 case 'e':
1186 ctl.skip_empty_lines = 1;
1187 break;
1188 case 'i': /* log process id also */
1189 ctl.pid = logger_getpid();
1190 break;
1191 case OPT_ID:
1192 if (optarg) {
1193 const char *p = optarg;
1194
1195 if (*p == '=')
1196 p++;
1197 ctl.pid = strtoul_or_err(optarg, _("failed to parse id"));
1198 } else
1199 ctl.pid = logger_getpid();
1200 break;
1201 case 'p': /* priority */
1202 ctl.pri = pencode(optarg);
1203 break;
1204 case 's': /* log to standard error */
1205 ctl.stderr_printout = 1;
1206 break;
1207 case 't': /* tag */
1208 ctl.tag = optarg;
1209 break;
1210 case 'u': /* unix socket */
1211 ctl.unix_socket = optarg;
1212 break;
1213 case 'S': /* max message size */
1214 ctl.max_message_size = strtosize_or_err(optarg,
1215 _("failed to parse message size"));
1216 break;
1217 case 'd':
1218 ctl.socket_type = TYPE_UDP;
1219 break;
1220 case 'T':
1221 ctl.socket_type = TYPE_TCP;
1222 break;
1223 case 'n':
1224 ctl.server = optarg;
1225 break;
1226 case 'P':
1227 ctl.port = optarg;
1228 break;
1229 case OPT_OCTET_COUNT:
1230 ctl.octet_count = 1;
1231 break;
1232 case OPT_PRIO_PREFIX:
1233 ctl.prio_prefix = 1;
1234 break;
1235 case OPT_RFC3164:
1236 ctl.syslogfp = syslog_rfc3164_header;
1237 break;
1238 case OPT_RFC5424:
1239 ctl.syslogfp = syslog_rfc5424_header;
1240 if (optarg)
1241 parse_rfc5424_flags(&ctl, optarg);
1242 break;
1243 case OPT_MSGID:
1244 if (strchr(optarg, ' '))
1245 errx(EXIT_FAILURE, _("--msgid cannot contain space"));
1246 ctl.msgid = optarg;
1247 break;
1248 #ifdef HAVE_LIBSYSTEMD
1249 case OPT_JOURNALD:
1250 if (optarg) {
1251 jfd = fopen(optarg, "r");
1252 if (!jfd)
1253 err(EXIT_FAILURE, _("cannot open %s"),
1254 optarg);
1255 } else
1256 jfd = stdin;
1257 break;
1258 #endif
1259 case OPT_SOCKET_ERRORS:
1260 unix_socket_errors_mode = parse_unix_socket_errors_flags(optarg);
1261 break;
1262 case OPT_NOACT:
1263 ctl.noact = 1;
1264 break;
1265 case OPT_STRUCTURED_DATA_ID:
1266 if (!valid_structured_data_id(optarg))
1267 errx(EXIT_FAILURE, _("invalid structured data ID: '%s'"), optarg);
1268 add_structured_data_id(get_user_structured_data(&ctl), optarg);
1269 break;
1270 case OPT_STRUCTURED_DATA_PARAM:
1271 if (!valid_structured_data_param(optarg))
1272 errx(EXIT_FAILURE, _("invalid structured data parameter: '%s'"), optarg);
1273 add_structured_data_param(get_user_structured_data(&ctl), optarg);
1274 break;
1275
1276 case 'V':
1277 print_version(EXIT_SUCCESS);
1278 case 'h':
1279 usage();
1280 default:
1281 errtryhelp(EXIT_FAILURE);
1282 }
1283 }
1284 argc -= optind;
1285 argv += optind;
1286 if (stdout_reopened && argc)
1287 warnx(_("--file <file> and <message> are mutually exclusive, message is ignored"));
1288 #ifdef HAVE_LIBSYSTEMD
1289 if (jfd) {
1290 int ret = journald_entry(&ctl, jfd);
1291 if (stdin != jfd)
1292 fclose(jfd);
1293 if (ret)
1294 errx(EXIT_FAILURE, _("journald entry could not be written"));
1295 return EXIT_SUCCESS;
1296 }
1297 #endif
1298
1299 /* user overwrites built-in SD-ELEMENT */
1300 if (has_structured_data_id(get_user_structured_data(&ctl), "timeQuality"))
1301 ctl.rfc5424_tq = 0;
1302
1303 switch (unix_socket_errors_mode) {
1304 case AF_UNIX_ERRORS_OFF:
1305 ctl.unix_socket_errors = 0;
1306 break;
1307 case AF_UNIX_ERRORS_ON:
1308 ctl.unix_socket_errors = 1;
1309 break;
1310 case AF_UNIX_ERRORS_AUTO:
1311 ctl.unix_socket_errors = ctl.noact || ctl.stderr_printout;
1312 #ifdef HAVE_LIBSYSTEMD
1313 ctl.unix_socket_errors |= !!sd_booted();
1314 #endif
1315 break;
1316 default:
1317 abort();
1318 }
1319 logger_open(&ctl);
1320 if (0 < argc) {
1321 generate_syslog_header(&ctl);
1322 logger_command_line(&ctl, argv);
1323 } else
1324 /* Note. --file <arg> reopens stdin making the below
1325 * function to be used for file inputs. */
1326 logger_stdin(&ctl);
1327
1328 logger_close(&ctl);
1329 return EXIT_SUCCESS;
1330 }