1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #ifndef lint 33 static const char copyright[] = 34 "@(#) Copyright (c) 1983, 1993\n\ 35 The Regents of the University of California. All rights reserved.\n"; 36 #endif /* not lint */ 37 38 #if 0 39 #ifndef lint 40 static char sccsid[] = "@(#)logger.c 8.1 (Berkeley) 6/6/93"; 41 #endif /* not lint */ 42 #endif 43 44 #include <sys/cdefs.h> 45 __FBSDID("$FreeBSD$"); 46 47 #include <sys/capsicum.h> 48 #include <sys/param.h> 49 #include <sys/socket.h> 50 #include <netinet/in.h> 51 52 #include <capsicum_helpers.h> 53 #include <ctype.h> 54 #include <err.h> 55 #include <netdb.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <time.h> 60 #include <unistd.h> 61 62 #include <libcasper.h> 63 #include <casper/cap_syslog.h> 64 65 #define SYSLOG_NAMES 66 #include <syslog.h> 67 68 #define sstosa(ss) ((struct sockaddr *)(void *)ss) 69 70 struct socks { 71 int sk_sock; 72 int sk_addrlen; 73 struct sockaddr_storage sk_addr; 74 }; 75 76 static int decode(char *, const CODE *); 77 static int pencode(char *); 78 static ssize_t socksetup(const char *, const char *, const char *, 79 struct socks **); 80 static void logmessage(int, const char *, const char *, const char *, 81 struct socks *, ssize_t, const char *); 82 static void usage(void); 83 84 static cap_channel_t *capsyslog; 85 #ifdef INET6 86 static int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */ 87 #else 88 static int family = PF_INET; /* protocol family (IPv4 only) */ 89 #endif 90 static int send_to_all = 0; /* send message to all IPv4/IPv6 addresses */ 91 92 /* 93 * logger -- read and log utility 94 * 95 * Reads from an input and arranges to write the result on the system 96 * log. 97 */ 98 int 99 main(int argc, char *argv[]) 100 { 101 cap_channel_t *capcas; 102 struct socks *socks; 103 ssize_t nsock; 104 time_t now; 105 int ch, logflags, pri; 106 char *tag, *host, buf[1024], *timestamp, tbuf[26], 107 *hostname, hbuf[MAXHOSTNAMELEN], *pristr; 108 const char *svcname, *src; 109 110 tag = NULL; 111 host = NULL; 112 hostname = NULL; 113 svcname = "syslog"; 114 src = NULL; 115 socks = NULL; 116 pri = LOG_USER | LOG_NOTICE; 117 pristr = NULL; 118 logflags = 0; 119 unsetenv("TZ"); 120 while ((ch = getopt(argc, argv, "46Af:H:h:iP:p:S:st:")) != -1) 121 switch((char)ch) { 122 case '4': 123 family = PF_INET; 124 break; 125 #ifdef INET6 126 case '6': 127 family = PF_INET6; 128 break; 129 #endif 130 case 'A': 131 send_to_all++; 132 break; 133 case 'f': /* file to log */ 134 if (freopen(optarg, "r", stdin) == NULL) 135 err(1, "%s", optarg); 136 setvbuf(stdin, 0, _IONBF, 0); 137 break; 138 case 'H': /* hostname to set in message header */ 139 hostname = optarg; 140 break; 141 case 'h': /* hostname to deliver to */ 142 host = optarg; 143 break; 144 case 'i': /* log process id also */ 145 logflags |= LOG_PID; 146 break; 147 case 'P': /* service name or port number */ 148 svcname = optarg; 149 break; 150 case 'p': /* priority */ 151 pristr = optarg; 152 break; 153 case 's': /* log to standard error */ 154 logflags |= LOG_PERROR; 155 break; 156 case 'S': /* source address */ 157 src = optarg; 158 break; 159 case 't': /* tag */ 160 tag = optarg; 161 break; 162 case '?': 163 default: 164 usage(); 165 } 166 argc -= optind; 167 argv += optind; 168 169 if (host) { 170 nsock = socksetup(src, host, svcname, &socks); 171 if (nsock <= 0) 172 errx(1, "socket"); 173 } else { 174 if (src) 175 errx(1, "-h option is missing."); 176 nsock = 0; 177 } 178 179 capcas = cap_init(); 180 if (capcas == NULL) 181 err(1, "Unable to contact Casper"); 182 caph_cache_catpages(); 183 caph_cache_tzdata(); 184 if (nsock == 0) { 185 if (caph_enter_casper() < 0) 186 err(1, "Unable to enter capability mode"); 187 } 188 capsyslog = cap_service_open(capcas, "system.syslog"); 189 if (capsyslog == NULL) 190 err(1, "Unable to open system.syslog service"); 191 cap_close(capcas); 192 193 if (pristr != NULL) 194 pri = pencode(pristr); 195 if (tag == NULL) 196 tag = getlogin(); 197 /* setup for logging */ 198 if (host == NULL) 199 cap_openlog(capsyslog, tag, logflags, 0); 200 201 if (hostname == NULL) { 202 hostname = hbuf; 203 (void )gethostname(hbuf, MAXHOSTNAMELEN); 204 *strchrnul(hostname, '.') = '\0'; 205 } 206 207 timestamp = tbuf + 4; 208 209 /* log input line if appropriate */ 210 if (argc > 0) { 211 char *p, *endp; 212 size_t len; 213 214 (void )time(&now); 215 (void )ctime_r(&now, tbuf); 216 tbuf[19] = '\0'; 217 218 for (p = buf, endp = buf + sizeof(buf) - 2; *argv;) { 219 len = strlen(*argv); 220 if (p + len > endp && p > buf) { 221 logmessage(pri, timestamp, hostname, tag, 222 socks, nsock, buf); 223 p = buf; 224 } 225 if (len > sizeof(buf) - 1) 226 logmessage(pri, timestamp, hostname, tag, 227 socks, nsock, *argv++); 228 else { 229 if (p != buf) 230 *p++ = ' '; 231 bcopy(*argv++, p, len); 232 *(p += len) = '\0'; 233 } 234 } 235 if (p != buf) 236 logmessage(pri, timestamp, hostname, tag, socks, nsock, 237 buf); 238 } else 239 while (fgets(buf, sizeof(buf), stdin) != NULL) { 240 (void )time(&now); 241 (void )ctime_r(&now, tbuf); 242 tbuf[19] = '\0'; 243 244 logmessage(pri, timestamp, hostname, tag, socks, nsock, 245 buf); 246 } 247 exit(0); 248 } 249 250 static ssize_t 251 socksetup(const char *src, const char *dst, const char *svcname, 252 struct socks **socks) 253 { 254 struct addrinfo hints, *res, *res0; 255 struct sockaddr_storage *ss_src[AF_MAX]; 256 struct socks *sk; 257 ssize_t nsock = 0; 258 int error, maxs; 259 260 memset(&ss_src[0], 0, sizeof(ss_src)); 261 if (src) { 262 char *p, *p0, *hs, *hbuf, *sbuf; 263 264 hbuf = sbuf = NULL; 265 p0 = p = strdup(src); 266 if (p0 == NULL) 267 err(1, "strdup failed"); 268 hs = p0; /* point to search ":" */ 269 #ifdef INET6 270 /* -S option supports IPv6 addr in "[2001:db8::1]:service". */ 271 if (*p0 == '[') { 272 p = strchr(p0, ']'); 273 if (p == NULL) 274 errx(1, "\"]\" not found in src addr"); 275 *p = '\0'; 276 /* hs points just after ']' (':' or '\0'). */ 277 hs = p + 1; 278 /* 279 * p points just after '[' while it points hs 280 * in the case of []. 281 */ 282 p = ((p0 + 1) == (hs - 1)) ? hs : p0 + 1; 283 } 284 #endif 285 if (*p != '\0') { 286 /* (p == hs) means ":514" or "[]:514". */ 287 hbuf = (p == hs && *p == ':') ? NULL : p; 288 p = strchr(hs, ':'); 289 if (p != NULL) { 290 *p = '\0'; 291 sbuf = (*(p + 1) != '\0') ? p + 1 : NULL; 292 } 293 } 294 hints = (struct addrinfo){ 295 .ai_family = family, 296 .ai_socktype = SOCK_DGRAM, 297 .ai_flags = AI_PASSIVE 298 }; 299 error = getaddrinfo(hbuf, sbuf, &hints, &res0); 300 if (error) 301 errx(1, "%s: %s", gai_strerror(error), src); 302 for (res = res0; res; res = res->ai_next) { 303 switch (res->ai_family) { 304 case AF_INET: 305 #ifdef INET6 306 case AF_INET6: 307 #endif 308 if (ss_src[res->ai_family] != NULL) 309 continue; 310 ss_src[res->ai_family] = 311 malloc(sizeof(struct sockaddr_storage)); 312 if (ss_src[res->ai_family] == NULL) 313 err(1, "malloc failed"); 314 memcpy(ss_src[res->ai_family], res->ai_addr, 315 res->ai_addrlen); 316 } 317 } 318 freeaddrinfo(res0); 319 free(p0); 320 } 321 322 /* resolve hostname */ 323 hints = (struct addrinfo){ 324 .ai_family = family, 325 .ai_socktype = SOCK_DGRAM 326 }; 327 error = getaddrinfo(dst, svcname, &hints, &res0); 328 if (error == EAI_SERVICE) { 329 warnx("%s/udp: unknown service", svcname); 330 error = getaddrinfo(dst, "514", &hints, &res0); 331 } 332 if (error) 333 errx(1, "%s: %s", gai_strerror(error), dst); 334 /* count max number of sockets we may open */ 335 maxs = 0; 336 for (res = res0; res; res = res->ai_next) 337 maxs++; 338 sk = calloc(maxs, sizeof(*sk)); 339 if (sk == NULL) 340 errx(1, "couldn't allocate memory for sockets"); 341 for (res = res0; res; res = res->ai_next) { 342 int s; 343 344 s = socket(res->ai_family, res->ai_socktype, 345 res->ai_protocol); 346 if (s < 0) 347 continue; 348 if (src && ss_src[res->ai_family] == NULL) 349 errx(1, "address family mismatch"); 350 351 if (ss_src[res->ai_family]) { 352 error = bind(s, sstosa(ss_src[res->ai_family]), 353 ss_src[res->ai_family]->ss_len); 354 if (error < 0) 355 err(1, "bind"); 356 } 357 sk[nsock] = (struct socks){ 358 .sk_addrlen = res->ai_addrlen, 359 .sk_sock = s 360 }; 361 memcpy(&sk[nsock].sk_addr, res->ai_addr, res->ai_addrlen); 362 nsock++; 363 } 364 freeaddrinfo(res0); 365 366 *socks = sk; 367 return (nsock); 368 } 369 370 /* 371 * Send the message to syslog, either on the local host, or on a remote host 372 */ 373 static void 374 logmessage(int pri, const char *timestamp, const char *hostname, 375 const char *tag, struct socks *sk, ssize_t nsock, const char *buf) 376 { 377 char *line; 378 int len, i, lsent; 379 380 if (nsock == 0) { 381 cap_syslog(capsyslog, pri, "%s", buf); 382 return; 383 } 384 if ((len = asprintf(&line, "<%d>%s %s %s: %s", pri, timestamp, 385 hostname, tag, buf)) == -1) 386 errx(1, "asprintf"); 387 388 lsent = -1; 389 for (i = 0; i < nsock; i++) { 390 lsent = sendto(sk[i].sk_sock, line, len, 0, 391 sstosa(&sk[i].sk_addr), sk[i].sk_addrlen); 392 if (lsent == len && !send_to_all) 393 break; 394 } 395 if (lsent != len) { 396 if (lsent == -1) 397 warn("sendto"); 398 else 399 warnx("sendto: short send - %d bytes", lsent); 400 } 401 402 free(line); 403 } 404 405 /* 406 * Decode a symbolic name to a numeric value 407 */ 408 static int 409 pencode(char *s) 410 { 411 char *save; 412 int fac, lev; 413 414 for (save = s; *s && *s != '.'; ++s); 415 if (*s) { 416 *s = '\0'; 417 fac = decode(save, facilitynames); 418 if (fac < 0) 419 errx(1, "unknown facility name: %s", save); 420 *s++ = '.'; 421 } 422 else { 423 fac = 0; 424 s = save; 425 } 426 lev = decode(s, prioritynames); 427 if (lev < 0) 428 errx(1, "unknown priority name: %s", save); 429 return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); 430 } 431 432 static int 433 decode(char *name, const CODE *codetab) 434 { 435 const CODE *c; 436 437 if (isdigit(*name)) 438 return (atoi(name)); 439 440 for (c = codetab; c->c_name; c++) 441 if (!strcasecmp(name, c->c_name)) 442 return (c->c_val); 443 444 return (-1); 445 } 446 447 static void 448 usage(void) 449 { 450 (void)fprintf(stderr, "usage: %s\n", 451 "logger [-46Ais] [-f file] [-h host] [-P port] [-p pri] [-t tag]\n" 452 " [-S addr:port] [message ...]" 453 ); 454 exit(1); 455 } 456