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 #include <sys/capsicum.h> 46 #include <sys/param.h> 47 #include <sys/socket.h> 48 #include <netinet/in.h> 49 50 #include <capsicum_helpers.h> 51 #include <ctype.h> 52 #include <err.h> 53 #include <netdb.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include <time.h> 58 #include <unistd.h> 59 60 #include <libcasper.h> 61 #include <casper/cap_syslog.h> 62 63 #define SYSLOG_NAMES 64 #include <syslog.h> 65 66 #define sstosa(ss) ((struct sockaddr *)(void *)ss) 67 68 struct socks { 69 int sk_sock; 70 int sk_addrlen; 71 struct sockaddr_storage sk_addr; 72 }; 73 74 static int decode(char *, const CODE *); 75 static int pencode(char *); 76 static ssize_t socksetup(const char *, const char *, const char *, 77 struct socks **); 78 static void logmessage(int, const char *, const char *, const char *, 79 struct socks *, ssize_t, const char *); 80 static void usage(void); 81 82 static cap_channel_t *capsyslog; 83 #ifdef INET6 84 static int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */ 85 #else 86 static int family = PF_INET; /* protocol family (IPv4 only) */ 87 #endif 88 static int send_to_all = 0; /* send message to all IPv4/IPv6 addresses */ 89 90 /* 91 * logger -- read and log utility 92 * 93 * Reads from an input and arranges to write the result on the system 94 * log. 95 */ 96 int 97 main(int argc, char *argv[]) 98 { 99 cap_channel_t *capcas; 100 struct socks *socks; 101 ssize_t nsock; 102 time_t now; 103 int ch, logflags, pri; 104 char *tag, *host, buf[1024], *timestamp, tbuf[26], 105 *hostname, hbuf[MAXHOSTNAMELEN], *pristr; 106 const char *svcname, *src; 107 108 tag = NULL; 109 host = NULL; 110 hostname = NULL; 111 svcname = "syslog"; 112 src = NULL; 113 socks = NULL; 114 pri = LOG_USER | LOG_NOTICE; 115 pristr = NULL; 116 logflags = 0; 117 unsetenv("TZ"); 118 while ((ch = getopt(argc, argv, "46Af:H:h:iP:p:S:st:")) != -1) 119 switch((char)ch) { 120 case '4': 121 family = PF_INET; 122 break; 123 #ifdef INET6 124 case '6': 125 family = PF_INET6; 126 break; 127 #endif 128 case 'A': 129 send_to_all++; 130 break; 131 case 'f': /* file to log */ 132 if (freopen(optarg, "r", stdin) == NULL) 133 err(1, "%s", optarg); 134 setvbuf(stdin, 0, _IONBF, 0); 135 break; 136 case 'H': /* hostname to set in message header */ 137 hostname = optarg; 138 break; 139 case 'h': /* hostname to deliver to */ 140 host = optarg; 141 break; 142 case 'i': /* log process id also */ 143 logflags |= LOG_PID; 144 break; 145 case 'P': /* service name or port number */ 146 svcname = optarg; 147 break; 148 case 'p': /* priority */ 149 pristr = optarg; 150 break; 151 case 's': /* log to standard error */ 152 logflags |= LOG_PERROR; 153 break; 154 case 'S': /* source address */ 155 src = optarg; 156 break; 157 case 't': /* tag */ 158 tag = optarg; 159 break; 160 case '?': 161 default: 162 usage(); 163 } 164 argc -= optind; 165 argv += optind; 166 167 if (host) { 168 nsock = socksetup(src, host, svcname, &socks); 169 if (nsock <= 0) 170 errx(1, "socket"); 171 } else { 172 if (src) 173 errx(1, "-h option is missing."); 174 nsock = 0; 175 } 176 177 capcas = cap_init(); 178 if (capcas == NULL) 179 err(1, "Unable to contact Casper"); 180 caph_cache_catpages(); 181 caph_cache_tzdata(); 182 if (nsock == 0) { 183 if (caph_enter_casper() < 0) 184 err(1, "Unable to enter capability mode"); 185 } 186 capsyslog = cap_service_open(capcas, "system.syslog"); 187 if (capsyslog == NULL) 188 err(1, "Unable to open system.syslog service"); 189 cap_close(capcas); 190 191 if (pristr != NULL) 192 pri = pencode(pristr); 193 if (tag == NULL) 194 tag = getlogin(); 195 /* setup for logging */ 196 if (host == NULL) 197 cap_openlog(capsyslog, tag, logflags, 0); 198 199 if (hostname == NULL) { 200 hostname = hbuf; 201 (void )gethostname(hbuf, MAXHOSTNAMELEN); 202 *strchrnul(hostname, '.') = '\0'; 203 } 204 205 timestamp = tbuf + 4; 206 207 /* log input line if appropriate */ 208 if (argc > 0) { 209 char *p, *endp; 210 size_t len; 211 212 (void )time(&now); 213 (void )ctime_r(&now, tbuf); 214 tbuf[19] = '\0'; 215 216 for (p = buf, endp = buf + sizeof(buf) - 2; *argv;) { 217 len = strlen(*argv); 218 if (p + len > endp && p > buf) { 219 logmessage(pri, timestamp, hostname, tag, 220 socks, nsock, buf); 221 p = buf; 222 } 223 if (len > sizeof(buf) - 1) 224 logmessage(pri, timestamp, hostname, tag, 225 socks, nsock, *argv++); 226 else { 227 if (p != buf) 228 *p++ = ' '; 229 bcopy(*argv++, p, len); 230 *(p += len) = '\0'; 231 } 232 } 233 if (p != buf) 234 logmessage(pri, timestamp, hostname, tag, socks, nsock, 235 buf); 236 } else 237 while (fgets(buf, sizeof(buf), stdin) != NULL) { 238 (void )time(&now); 239 (void )ctime_r(&now, tbuf); 240 tbuf[19] = '\0'; 241 242 logmessage(pri, timestamp, hostname, tag, socks, nsock, 243 buf); 244 } 245 exit(0); 246 } 247 248 static ssize_t 249 socksetup(const char *src, const char *dst, const char *svcname, 250 struct socks **socks) 251 { 252 struct addrinfo hints, *res, *res0; 253 struct sockaddr_storage *ss_src[AF_MAX]; 254 struct socks *sk; 255 ssize_t nsock = 0; 256 int error, maxs; 257 258 memset(&ss_src[0], 0, sizeof(ss_src)); 259 if (src) { 260 char *p, *p0, *hs, *hbuf, *sbuf; 261 262 hbuf = sbuf = NULL; 263 p0 = p = strdup(src); 264 if (p0 == NULL) 265 err(1, "strdup failed"); 266 hs = p0; /* point to search ":" */ 267 #ifdef INET6 268 /* -S option supports IPv6 addr in "[2001:db8::1]:service". */ 269 if (*p0 == '[') { 270 p = strchr(p0, ']'); 271 if (p == NULL) 272 errx(1, "\"]\" not found in src addr"); 273 *p = '\0'; 274 /* hs points just after ']' (':' or '\0'). */ 275 hs = p + 1; 276 /* 277 * p points just after '[' while it points hs 278 * in the case of []. 279 */ 280 p = ((p0 + 1) == (hs - 1)) ? hs : p0 + 1; 281 } 282 #endif 283 if (*p != '\0') { 284 /* (p == hs) means ":514" or "[]:514". */ 285 hbuf = (p == hs && *p == ':') ? NULL : p; 286 p = strchr(hs, ':'); 287 if (p != NULL) { 288 *p = '\0'; 289 sbuf = (*(p + 1) != '\0') ? p + 1 : NULL; 290 } 291 } 292 hints = (struct addrinfo){ 293 .ai_family = family, 294 .ai_socktype = SOCK_DGRAM, 295 .ai_flags = AI_PASSIVE 296 }; 297 error = getaddrinfo(hbuf, sbuf, &hints, &res0); 298 if (error) 299 errx(1, "%s: %s", gai_strerror(error), src); 300 for (res = res0; res; res = res->ai_next) { 301 switch (res->ai_family) { 302 case AF_INET: 303 #ifdef INET6 304 case AF_INET6: 305 #endif 306 if (ss_src[res->ai_family] != NULL) 307 continue; 308 ss_src[res->ai_family] = 309 malloc(sizeof(struct sockaddr_storage)); 310 if (ss_src[res->ai_family] == NULL) 311 err(1, "malloc failed"); 312 memcpy(ss_src[res->ai_family], res->ai_addr, 313 res->ai_addrlen); 314 } 315 } 316 freeaddrinfo(res0); 317 free(p0); 318 } 319 320 /* resolve hostname */ 321 hints = (struct addrinfo){ 322 .ai_family = family, 323 .ai_socktype = SOCK_DGRAM 324 }; 325 error = getaddrinfo(dst, svcname, &hints, &res0); 326 if (error == EAI_SERVICE) { 327 warnx("%s/udp: unknown service", svcname); 328 error = getaddrinfo(dst, "514", &hints, &res0); 329 } 330 if (error) 331 errx(1, "%s: %s", gai_strerror(error), dst); 332 /* count max number of sockets we may open */ 333 maxs = 0; 334 for (res = res0; res; res = res->ai_next) 335 maxs++; 336 sk = calloc(maxs, sizeof(*sk)); 337 if (sk == NULL) 338 errx(1, "couldn't allocate memory for sockets"); 339 for (res = res0; res; res = res->ai_next) { 340 int s; 341 342 s = socket(res->ai_family, res->ai_socktype, 343 res->ai_protocol); 344 if (s < 0) 345 continue; 346 if (src && ss_src[res->ai_family] == NULL) 347 errx(1, "address family mismatch"); 348 349 if (ss_src[res->ai_family]) { 350 error = bind(s, sstosa(ss_src[res->ai_family]), 351 ss_src[res->ai_family]->ss_len); 352 if (error < 0) 353 err(1, "bind"); 354 } 355 sk[nsock] = (struct socks){ 356 .sk_addrlen = res->ai_addrlen, 357 .sk_sock = s 358 }; 359 memcpy(&sk[nsock].sk_addr, res->ai_addr, res->ai_addrlen); 360 nsock++; 361 } 362 freeaddrinfo(res0); 363 364 *socks = sk; 365 return (nsock); 366 } 367 368 /* 369 * Send the message to syslog, either on the local host, or on a remote host 370 */ 371 static void 372 logmessage(int pri, const char *timestamp, const char *hostname, 373 const char *tag, struct socks *sk, ssize_t nsock, const char *buf) 374 { 375 char *line; 376 int len, i, lsent; 377 378 if (nsock == 0) { 379 cap_syslog(capsyslog, pri, "%s", buf); 380 return; 381 } 382 if ((len = asprintf(&line, "<%d>%s %s %s: %s", pri, timestamp, 383 hostname, tag, buf)) == -1) 384 errx(1, "asprintf"); 385 386 lsent = -1; 387 for (i = 0; i < nsock; i++) { 388 lsent = sendto(sk[i].sk_sock, line, len, 0, 389 sstosa(&sk[i].sk_addr), sk[i].sk_addrlen); 390 if (lsent == len && !send_to_all) 391 break; 392 } 393 if (lsent != len) { 394 if (lsent == -1) 395 warn("sendto"); 396 else 397 warnx("sendto: short send - %d bytes", lsent); 398 } 399 400 free(line); 401 } 402 403 /* 404 * Decode a symbolic name to a numeric value 405 */ 406 static int 407 pencode(char *s) 408 { 409 char *save; 410 int fac, lev; 411 412 for (save = s; *s && *s != '.'; ++s); 413 if (*s) { 414 *s = '\0'; 415 fac = decode(save, facilitynames); 416 if (fac < 0) 417 errx(1, "unknown facility name: %s", save); 418 *s++ = '.'; 419 } 420 else { 421 fac = 0; 422 s = save; 423 } 424 lev = decode(s, prioritynames); 425 if (lev < 0) 426 errx(1, "unknown priority name: %s", save); 427 return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); 428 } 429 430 static int 431 decode(char *name, const CODE *codetab) 432 { 433 const CODE *c; 434 435 if (isdigit(*name)) 436 return (atoi(name)); 437 438 for (c = codetab; c->c_name; c++) 439 if (!strcasecmp(name, c->c_name)) 440 return (c->c_val); 441 442 return (-1); 443 } 444 445 static void 446 usage(void) 447 { 448 (void)fprintf(stderr, "usage: %s\n", 449 "logger [-46Ais] [-f file] [-h host] [-P port] [-p pri] [-t tag]\n" 450 " [-S addr:port] [message ...]" 451 ); 452 exit(1); 453 } 454