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