tftpd.c revision 1.43
1/* $OpenBSD: tftpd.c,v 1.43 2019/07/03 03:24:03 deraadt Exp $ */ 2 3/* 4 * Copyright (c) 2012 David Gwynne <dlg@uq.edu.au> 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 Regents of the University of California. 21 * 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 * Trivial file transfer protocol server. 50 * 51 * This version is based on src/libexec/tftpd which includes many 52 * modifications by Jim Guyton <guyton@rand-unix>. 53 * 54 * It was restructured to be a persistent event driven daemon 55 * supporting concurrent connections by dlg for use at the University 56 * of Queensland in the Faculty of Engineering Architecture and 57 * Information Technology. 58 */ 59 60#include <sys/types.h> 61#include <sys/queue.h> 62#include <sys/socket.h> 63#include <sys/stat.h> 64#include <sys/uio.h> 65#include <sys/un.h> 66 67#include <netinet/in.h> 68#include <arpa/inet.h> 69#include <arpa/tftp.h> 70#include <netdb.h> 71 72#include <err.h> 73#include <ctype.h> 74#include <errno.h> 75#include <event.h> 76#include <fcntl.h> 77#include <paths.h> 78#include <poll.h> 79#include <pwd.h> 80#include <stdio.h> 81#include <stdlib.h> 82#include <string.h> 83#include <stdarg.h> 84#include <syslog.h> 85#include <unistd.h> 86#include <limits.h> 87#include <vis.h> 88 89#define TIMEOUT 5 /* packet rexmt timeout */ 90#define TIMEOUT_MIN 1 /* minimal packet rexmt timeout */ 91#define TIMEOUT_MAX 255 /* maximal packet rexmt timeout */ 92 93#define RETRIES 5 94 95#define SEEDPATH "/etc/random.seed" 96 97struct formats; 98 99enum opt_enum { 100 OPT_TSIZE = 0, 101 OPT_TIMEOUT, 102 OPT_BLKSIZE, 103 NOPT 104}; 105 106static char *opt_names[] = { 107 "tsize", 108 "timeout", 109 "blksize" 110}; 111 112struct opt_client { 113 char *o_request; 114 long long o_reply; 115}; 116 117 118struct tftp_server { 119 struct event ev; 120 TAILQ_ENTRY(tftp_server) entry; 121 int s; 122}; 123 124TAILQ_HEAD(, tftp_server) tftp_servers; 125 126struct tftp_client { 127 char buf[SEGSIZE_MAX + 4]; 128 struct event sev; 129 struct sockaddr_storage ss; 130 131 struct timeval tv; 132 133 TAILQ_ENTRY(tftp_client) entry; 134 135 struct opt_client *options; 136 137 size_t segment_size; 138 size_t packet_size; 139 size_t buflen; 140 141 FILE *file; 142 int (*fgetc)(struct tftp_client *); 143 int (*fputc)(struct tftp_client *, int); 144 145 u_int retries; 146 u_int16_t block; 147 148 int opcode; 149 int newline; 150 151 int sock; 152}; 153 154__dead void usage(void); 155const char *getip(void *); 156int rdaemon(int); 157 158void rewrite_connect(const char *); 159void rewrite_events(void); 160void rewrite_map(struct tftp_client *, const char *); 161void rewrite_req(int, short, void *); 162void rewrite_res(int, short, void *); 163 164int tftpd_listen(const char *, const char *, int); 165void tftpd_events(void); 166void tftpd_recv(int, short, void *); 167int retry(struct tftp_client *); 168int tftp_flush(struct tftp_client *); 169void tftp_end(struct tftp_client *); 170 171void tftp(struct tftp_client *, struct tftphdr *, size_t); 172void tftp_open(struct tftp_client *, const char *); 173void nak(struct tftp_client *, int); 174int oack(struct tftp_client *); 175void oack_done(int, short, void *); 176 177void sendfile(struct tftp_client *); 178void recvfile(struct tftp_client *); 179int fget_octet(struct tftp_client *); 180int fput_octet(struct tftp_client *, int); 181int fget_netascii(struct tftp_client *); 182int fput_netascii(struct tftp_client *, int); 183void file_read(struct tftp_client *); 184int tftp_wrq_ack_packet(struct tftp_client *); 185void tftp_rrq_ack(int, short, void *); 186void tftp_wrq_ack(struct tftp_client *client); 187void tftp_wrq(int, short, void *); 188void tftp_wrq_end(int, short, void *); 189 190int parse_options(struct tftp_client *, char *, size_t, 191 struct opt_client *); 192int validate_access(struct tftp_client *, const char *); 193 194struct tftp_client * 195 client_alloc(void); 196void client_free(struct tftp_client *client); 197 198struct formats { 199 const char *f_mode; 200 int (*f_getc)(struct tftp_client *); 201 int (*f_putc)(struct tftp_client *, int); 202} formats[] = { 203 { "octet", fget_octet, fput_octet }, 204 { "netascii", fget_netascii, fput_netascii }, 205 { NULL, NULL } 206}; 207 208struct errmsg { 209 int e_code; 210 const char *e_msg; 211} errmsgs[] = { 212 { EUNDEF, "Undefined error code" }, 213 { ENOTFOUND, "File not found" }, 214 { EACCESS, "Access violation" }, 215 { ENOSPACE, "Disk full or allocation exceeded" }, 216 { EBADOP, "Illegal TFTP operation" }, 217 { EBADID, "Unknown transfer ID" }, 218 { EEXISTS, "File already exists" }, 219 { ENOUSER, "No such user" }, 220 { EOPTNEG, "Option negotiation failed" }, 221 { -1, NULL } 222}; 223 224struct loggers { 225 __dead void (*err)(int, const char *, ...) 226 __attribute__((__format__ (printf, 2, 3))); 227 __dead void (*errx)(int, const char *, ...) 228 __attribute__((__format__ (printf, 2, 3))); 229 void (*warn)(const char *, ...) 230 __attribute__((__format__ (printf, 1, 2))); 231 void (*warnx)(const char *, ...) 232 __attribute__((__format__ (printf, 1, 2))); 233 void (*info)(const char *, ...) 234 __attribute__((__format__ (printf, 1, 2))); 235 void (*debug)(const char *, ...) 236 __attribute__((__format__ (printf, 1, 2))); 237}; 238 239const struct loggers conslogger = { 240 err, 241 errx, 242 warn, 243 warnx, 244 warnx, /* info */ 245 warnx /* debug */ 246}; 247 248__dead void syslog_err(int, const char *, ...) 249 __attribute__((__format__ (printf, 2, 3))); 250__dead void syslog_errx(int, const char *, ...) 251 __attribute__((__format__ (printf, 2, 3))); 252void syslog_warn(const char *, ...) 253 __attribute__((__format__ (printf, 1, 2))); 254void syslog_warnx(const char *, ...) 255 __attribute__((__format__ (printf, 1, 2))); 256void syslog_info(const char *, ...) 257 __attribute__((__format__ (printf, 1, 2))); 258void syslog_debug(const char *, ...) 259 __attribute__((__format__ (printf, 1, 2))); 260void syslog_vstrerror(int, int, const char *, va_list) 261 __attribute__((__format__ (printf, 3, 0))); 262 263const struct loggers syslogger = { 264 syslog_err, 265 syslog_errx, 266 syslog_warn, 267 syslog_warnx, 268 syslog_info, 269 syslog_debug 270}; 271 272const struct loggers *logger = &conslogger; 273 274#define lerr(_e, _f...) logger->err((_e), _f) 275#define lerrx(_e, _f...) logger->errx((_e), _f) 276#define lwarn(_f...) logger->warn(_f) 277#define lwarnx(_f...) logger->warnx(_f) 278#define linfo(_f...) logger->info(_f) 279#define ldebug(_f...) logger->debug(_f) 280 281__dead void 282usage(void) 283{ 284 extern char *__progname; 285 fprintf(stderr, "usage: %s [-46cdiv] [-l address] [-p port] [-r socket]" 286 " directory\n", __progname); 287 exit(1); 288} 289 290int cancreate = 0; 291int verbose = 0; 292int debug = 0; 293int iflag = 0; 294 295int 296main(int argc, char *argv[]) 297{ 298 extern char *__progname; 299 300 int c; 301 struct passwd *pw; 302 303 char *dir = NULL; 304 char *rewrite = NULL; 305 306 char *addr = NULL; 307 char *port = "tftp"; 308 int family = AF_UNSPEC; 309 int devnull = -1; 310 311 while ((c = getopt(argc, argv, "46cdil:p:r:v")) != -1) { 312 switch (c) { 313 case '4': 314 family = AF_INET; 315 break; 316 case '6': 317 family = AF_INET6; 318 break; 319 case 'c': 320 cancreate = 1; 321 break; 322 case 'd': 323 verbose = debug = 1; 324 break; 325 case 'i': 326 if (rewrite != NULL) 327 errx(1, "options -i and -r are incompatible"); 328 iflag = 1; 329 break; 330 case 'l': 331 addr = optarg; 332 break; 333 case 'p': 334 port = optarg; 335 break; 336 case 'r': 337 if (iflag == 1) 338 errx(1, "options -i and -r are incompatible"); 339 rewrite = optarg; 340 break; 341 case 'v': 342 verbose = 1; 343 break; 344 default: 345 usage(); 346 /* NOTREACHED */ 347 } 348 } 349 350 argc -= optind; 351 argv += optind; 352 353 if (argc != 1) 354 usage(); 355 356 dir = argv[0]; 357 358 if (geteuid() != 0) 359 errx(1, "need root privileges"); 360 361 pw = getpwnam("_tftpd"); 362 if (pw == NULL) 363 errx(1, "no _tftpd user"); 364 365 if (!debug) { 366 openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON); 367 tzset(); 368 logger = &syslogger; 369 devnull = open(_PATH_DEVNULL, O_RDWR, 0); 370 if (devnull == -1) 371 err(1, "open %s", _PATH_DEVNULL); 372 } 373 374 if (rewrite != NULL) 375 rewrite_connect(rewrite); 376 377 tftpd_listen(addr, port, family); 378 379 if (chroot(dir)) 380 err(1, "chroot %s", dir); 381 if (chdir("/")) 382 err(1, "chdir %s", dir); 383 384 /* drop privs */ 385 if (setgroups(1, &pw->pw_gid) || 386 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 387 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 388 errx(1, "can't drop privileges"); 389 390 if (!debug && rdaemon(devnull) == -1) 391 err(1, "unable to daemonize"); 392 393 if (pledge("stdio rpath wpath cpath fattr dns inet", NULL) == -1) 394 lerr(1, "pledge"); 395 396 event_init(); 397 398 if (rewrite != NULL) 399 rewrite_events(); 400 401 tftpd_events(); 402 403 event_dispatch(); 404 405 exit(0); 406} 407 408struct rewritemap { 409 struct event wrev; 410 struct event rdev; 411 struct evbuffer *wrbuf; 412 struct evbuffer *rdbuf; 413 414 TAILQ_HEAD(, tftp_client) clients; 415 416 int s; 417}; 418 419struct rewritemap *rwmap = NULL; 420 421void 422rewrite_connect(const char *path) 423{ 424 int s; 425 struct sockaddr_un remote; 426 size_t len; 427 428 rwmap = malloc(sizeof(*rwmap)); 429 if (rwmap == NULL) 430 err(1, "rewrite event malloc"); 431 432 rwmap->wrbuf = evbuffer_new(); 433 if (rwmap->wrbuf == NULL) 434 err(1, "rewrite wrbuf"); 435 436 rwmap->rdbuf = evbuffer_new(); 437 if (rwmap->rdbuf == NULL) 438 err(1, "rewrite rdbuf"); 439 440 TAILQ_INIT(&rwmap->clients); 441 442 s = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); 443 if (s == -1) 444 err(1, "rewrite socket"); 445 446 remote.sun_family = AF_UNIX; 447 len = strlcpy(remote.sun_path, path, sizeof(remote.sun_path)); 448 if (len >= sizeof(remote.sun_path)) 449 errx(1, "rewrite socket path is too long"); 450 451 len += sizeof(remote.sun_family) + 1; 452 if (connect(s, (struct sockaddr *)&remote, len) == -1) 453 err(1, "%s", path); 454 455 rwmap->s = s; 456} 457 458void 459rewrite_events(void) 460{ 461 event_set(&rwmap->wrev, rwmap->s, EV_WRITE, rewrite_req, NULL); 462 event_set(&rwmap->rdev, rwmap->s, EV_READ | EV_PERSIST, rewrite_res, NULL); 463 event_add(&rwmap->rdev, NULL); 464} 465 466void 467rewrite_map(struct tftp_client *client, const char *filename) 468{ 469 char *nicebuf; 470 471 if (stravis(&nicebuf, filename, VIS_SAFE|VIS_OCTAL) == -1) 472 lerr(1, "rwmap stravis"); 473 474 if (evbuffer_add_printf(rwmap->wrbuf, "%s %s %s\n", getip(&client->ss), 475 client->opcode == WRQ ? "write" : "read", nicebuf) == -1) 476 lerr(1, "rwmap printf"); 477 478 free(nicebuf); 479 480 TAILQ_INSERT_TAIL(&rwmap->clients, client, entry); 481 482 event_add(&rwmap->wrev, NULL); 483} 484 485void 486rewrite_req(int fd, short events, void *arg) 487{ 488 if (evbuffer_write(rwmap->wrbuf, fd) == -1) { 489 switch (errno) { 490 case EINTR: 491 case EAGAIN: 492 event_add(&rwmap->wrev, NULL); 493 return; 494 } 495 496 lerr(1, "rewrite socket write"); 497 } 498 499 if (EVBUFFER_LENGTH(rwmap->wrbuf)) 500 event_add(&rwmap->wrev, NULL); 501} 502 503void 504rewrite_res(int fd, short events, void *arg) 505{ 506 struct tftp_client *client; 507 char *filename; 508 size_t len; 509 510 switch (evbuffer_read(rwmap->rdbuf, fd, PATH_MAX)) { 511 case -1: 512 switch (errno) { 513 case EINTR: 514 case EAGAIN: 515 return; 516 } 517 lerr(1, "rewrite socket read"); 518 case 0: 519 lerrx(1, "rewrite socket closed"); 520 default: 521 break; 522 } 523 524 while ((filename = evbuffer_readln(rwmap->rdbuf, &len, 525 EVBUFFER_EOL_LF)) != NULL) { 526 client = TAILQ_FIRST(&rwmap->clients); 527 if (client == NULL) 528 lerrx(1, "unexpected rwmap reply"); 529 530 TAILQ_REMOVE(&rwmap->clients, client, entry); 531 532 tftp_open(client, filename); 533 534 free(filename); 535 }; 536} 537 538int 539tftpd_listen(const char *addr, const char *port, int family) 540{ 541 struct tftp_server *server; 542 543 struct addrinfo hints, *res, *res0; 544 int error; 545 int s; 546 547 int cerrno = EADDRNOTAVAIL; 548 const char *cause = "getaddrinfo"; 549 550 int on = 1; 551 552 memset(&hints, 0, sizeof(hints)); 553 hints.ai_family = family; 554 hints.ai_socktype = SOCK_DGRAM; 555 hints.ai_flags = AI_PASSIVE; 556 557 TAILQ_INIT(&tftp_servers); 558 559 error = getaddrinfo(addr, port, &hints, &res0); 560 if (error) { 561 errx(1, "%s:%s: %s", addr ? addr : "*", port, 562 gai_strerror(error)); 563 } 564 565 for (res = res0; res != NULL; res = res->ai_next) { 566 s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK, 567 res->ai_protocol); 568 if (s == -1) { 569 cause = "socket"; 570 cerrno = errno; 571 continue; 572 } 573 574 if (bind(s, res->ai_addr, res->ai_addrlen) == -1) { 575 cause = "bind"; 576 cerrno = errno; 577 close(s); 578 continue; 579 } 580 581 switch (res->ai_family) { 582 case AF_INET: 583 if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, 584 &on, sizeof(on)) == -1) 585 err(1, "setsockopt(IP_RECVDSTADDR)"); 586 break; 587 case AF_INET6: 588 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, 589 &on, sizeof(on)) == -1) 590 err(1, "setsockopt(IPV6_RECVPKTINFO)"); 591 break; 592 } 593 594 server = malloc(sizeof(*server)); 595 if (server == NULL) 596 err(1, "malloc"); 597 598 server->s = s; 599 TAILQ_INSERT_TAIL(&tftp_servers, server, entry); 600 } 601 602 if (TAILQ_EMPTY(&tftp_servers)) 603 errc(1, cerrno, "%s", cause); 604 605 freeaddrinfo(res0); 606 return (0); 607} 608 609void 610tftpd_events(void) 611{ 612 struct tftp_server *server; 613 TAILQ_FOREACH(server, &tftp_servers, entry) { 614 event_set(&server->ev, server->s, EV_READ | EV_PERSIST, 615 tftpd_recv, server); 616 event_add(&server->ev, NULL); 617 } 618} 619 620struct tftp_client * 621client_alloc(void) 622{ 623 struct tftp_client *client; 624 625 client = calloc(1, sizeof(*client)); 626 if (client == NULL) 627 return (NULL); 628 629 client->segment_size = SEGSIZE; 630 client->packet_size = SEGSIZE + 4; 631 632 client->tv.tv_sec = TIMEOUT; 633 client->tv.tv_usec = 0; 634 635 client->sock = -1; 636 client->file = NULL; 637 client->newline = 0; 638 639 return (client); 640} 641 642void 643client_free(struct tftp_client *client) 644{ 645 free(client->options); 646 647 if (client->file != NULL) 648 fclose(client->file); 649 650 close(client->sock); 651 652 free(client); 653} 654 655void 656tftpd_recv(int fd, short events, void *arg) 657{ 658 union { 659 struct cmsghdr hdr; 660 char buf[CMSG_SPACE(sizeof(struct sockaddr_storage))]; 661 } cmsgbuf; 662 struct cmsghdr *cmsg; 663 struct msghdr msg; 664 struct iovec iov; 665 666 ssize_t n; 667 struct sockaddr_storage s_in; 668 int dobind = 1; 669 int on = 1; 670 671 struct tftphdr *tp; 672 673 struct tftp_client *client; 674 675 client = client_alloc(); 676 if (client == NULL) { 677 char buf[SEGSIZE_MAX + 4]; 678 /* no memory! flush this request... */ 679 recv(fd, buf, SEGSIZE_MAX + 4, 0); 680 /* dont care if it fails */ 681 return; 682 } 683 684 bzero(&msg, sizeof(msg)); 685 iov.iov_base = client->buf; 686 iov.iov_len = client->packet_size; 687 msg.msg_name = &client->ss; 688 msg.msg_namelen = sizeof(client->ss); 689 msg.msg_iov = &iov; 690 msg.msg_iovlen = 1; 691 msg.msg_control = &cmsgbuf.buf; 692 msg.msg_controllen = sizeof(cmsgbuf.buf); 693 694 n = recvmsg(fd, &msg, 0); 695 if (n == -1) { 696 lwarn("recvmsg"); 697 goto err; 698 } 699 if (n < 4) 700 goto err; 701 702 client->sock = socket(client->ss.ss_family, 703 SOCK_DGRAM | SOCK_NONBLOCK, 0); 704 if (client->sock == -1) { 705 lwarn("socket"); 706 goto err; 707 } 708 memset(&s_in, 0, sizeof(s_in)); 709 s_in.ss_family = client->ss.ss_family; 710 s_in.ss_len = client->ss.ss_len; 711 712 /* get local address if possible */ 713 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 714 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 715 if (cmsg->cmsg_level == IPPROTO_IP && 716 cmsg->cmsg_type == IP_RECVDSTADDR) { 717 memcpy(&((struct sockaddr_in *)&s_in)->sin_addr, 718 CMSG_DATA(cmsg), sizeof(struct in_addr)); 719 if (((struct sockaddr_in *)&s_in)->sin_addr.s_addr == 720 INADDR_BROADCAST) 721 dobind = 0; 722 break; 723 } 724 if (cmsg->cmsg_level == IPPROTO_IPV6 && 725 cmsg->cmsg_type == IPV6_PKTINFO) { 726 struct in6_pktinfo *ipi; 727 728 ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg); 729 memcpy(&((struct sockaddr_in6 *)&s_in)->sin6_addr, 730 &ipi->ipi6_addr, sizeof(struct in6_addr)); 731#ifdef __KAME__ 732 if (IN6_IS_ADDR_LINKLOCAL(&ipi->ipi6_addr)) 733 ((struct sockaddr_in6 *)&s_in)->sin6_scope_id = 734 ipi->ipi6_ifindex; 735#endif 736 break; 737 } 738 } 739 740 if (dobind) { 741 setsockopt(client->sock, SOL_SOCKET, SO_REUSEADDR, 742 &on, sizeof(on)); 743 setsockopt(client->sock, SOL_SOCKET, SO_REUSEPORT, 744 &on, sizeof(on)); 745 746 if (bind(client->sock, (struct sockaddr *)&s_in, 747 s_in.ss_len) == -1) { 748 lwarn("bind to %s", getip(&s_in)); 749 goto err; 750 } 751 } 752 if (connect(client->sock, (struct sockaddr *)&client->ss, 753 client->ss.ss_len) == -1) { 754 lwarn("connect to %s", getip(&client->ss)); 755 goto err; 756 } 757 758 tp = (struct tftphdr *)client->buf; 759 client->opcode = ntohs(tp->th_opcode); 760 if (client->opcode != RRQ && client->opcode != WRQ) { 761 /* bad request */ 762 goto err; 763 } 764 765 tftp(client, tp, n); 766 767 return; 768 769err: 770 client_free(client); 771} 772 773int 774parse_options(struct tftp_client *client, char *cp, size_t size, 775 struct opt_client *options) 776{ 777 char *option; 778 char *ccp; 779 int has_options = 0; 780 int i; 781 782 while (++cp < client->buf + size) { 783 for (i = 2, ccp = cp; i > 0; ccp++) { 784 if (ccp >= client->buf + size) { 785 /* 786 * Don't reject the request, just stop trying 787 * to parse the option and get on with it. 788 * Some Apple OpenFirmware versions have 789 * trailing garbage on the end of otherwise 790 * valid requests. 791 */ 792 return (has_options); 793 } else if (*ccp == '\0') 794 i--; 795 } 796 797 for (option = cp; *cp; cp++) 798 *cp = tolower((unsigned char)*cp); 799 800 for (i = 0; i < NOPT; i++) { 801 if (strcmp(option, opt_names[i]) == 0) { 802 options[i].o_request = ++cp; 803 has_options = 1; 804 } 805 } 806 cp = ccp - 1; 807 } 808 809 return (has_options); 810} 811 812/* 813 * Handle initial connection protocol. 814 */ 815void 816tftp(struct tftp_client *client, struct tftphdr *tp, size_t size) 817{ 818 struct opt_client *options; 819 820 char *cp; 821 int i, first = 1, ecode, to; 822 struct formats *pf; 823 char *mode = NULL; 824 char filename[PATH_MAX]; 825 const char *errstr; 826 827 if (size < 5) { 828 ecode = EBADOP; 829 goto error; 830 } 831 832 cp = tp->th_stuff; 833again: 834 while (cp < client->buf + size) { 835 if (*cp == '\0') 836 break; 837 cp++; 838 } 839 if (*cp != '\0') { 840 ecode = EBADOP; 841 goto error; 842 } 843 i = cp - tp->th_stuff; 844 if (i >= sizeof(filename)) { 845 ecode = EBADOP; 846 goto error; 847 } 848 memcpy(filename, tp->th_stuff, i); 849 filename[i] = '\0'; 850 if (first) { 851 mode = ++cp; 852 first = 0; 853 goto again; 854 } 855 for (cp = mode; *cp; cp++) 856 *cp = tolower((unsigned char)*cp); 857 858 for (pf = formats; pf->f_mode; pf++) { 859 if (strcmp(pf->f_mode, mode) == 0) 860 break; 861 } 862 if (pf->f_mode == 0) { 863 ecode = EBADOP; 864 goto error; 865 } 866 client->fgetc = pf->f_getc; 867 client->fputc = pf->f_putc; 868 869 client->options = options = calloc(NOPT, sizeof(*client->options)); 870 if (options == NULL) { 871 ecode = 100 + ENOMEM; 872 goto error; 873 } 874 875 if (parse_options(client, cp, size, options)) { 876 if (options[OPT_TIMEOUT].o_request != NULL) { 877 to = strtonum(options[OPT_TIMEOUT].o_request, 878 TIMEOUT_MIN, TIMEOUT_MAX, &errstr); 879 if (errstr) { 880 ecode = EBADOP; 881 goto error; 882 } 883 options[OPT_TIMEOUT].o_reply = client->tv.tv_sec = to; 884 } 885 886 if (options[OPT_BLKSIZE].o_request) { 887 client->segment_size = strtonum( 888 options[OPT_BLKSIZE].o_request, 889 SEGSIZE_MIN, SEGSIZE_MAX, &errstr); 890 if (errstr) { 891 ecode = EBADOP; 892 goto error; 893 } 894 client->packet_size = client->segment_size + 4; 895 options[OPT_BLKSIZE].o_reply = client->segment_size; 896 } 897 } else { 898 free(options); 899 client->options = NULL; 900 } 901 902 if (verbose) { 903 char nicebuf[PATH_MAX]; 904 905 (void)strnvis(nicebuf, filename, PATH_MAX, 906 VIS_SAFE|VIS_OCTAL); 907 908 linfo("%s: %s request for '%s'", getip(&client->ss), 909 client->opcode == WRQ ? "write" : "read", nicebuf); 910 } 911 912 if (rwmap != NULL) 913 rewrite_map(client, filename); 914 else 915 tftp_open(client, filename); 916 917 return; 918 919error: 920 nak(client, ecode); 921} 922 923void 924tftp_open(struct tftp_client *client, const char *filename) 925{ 926 int ecode; 927 928 ecode = validate_access(client, filename); 929 if (ecode) 930 goto error; 931 932 if (client->options) { 933 if (oack(client) == -1) 934 goto error; 935 936 free(client->options); 937 client->options = NULL; 938 } else if (client->opcode == WRQ) { 939 recvfile(client); 940 } else 941 sendfile(client); 942 943 return; 944error: 945 nak(client, ecode); 946} 947 948/* 949 * Validate file access. Since we 950 * have no uid or gid, for now require 951 * file to exist and be publicly 952 * readable/writable. 953 * If we were invoked with arguments 954 * from inetd then the file must also be 955 * in one of the given directory prefixes. 956 * Note also, full path name must be 957 * given as we have no login directory. 958 */ 959int 960validate_access(struct tftp_client *client, const char *requested) 961{ 962 int mode = client->opcode; 963 struct opt_client *options = client->options; 964 struct stat stbuf; 965 int fd, wmode; 966 const char *errstr, *filename; 967 char rewritten[PATH_MAX]; 968 969 if (strcmp(requested, SEEDPATH) == 0) { 970 char *buf; 971 if (mode != RRQ) 972 return (EACCESS); 973 974 buf = client->buf + sizeof(client->buf) - 512; 975 arc4random_buf(buf, 512); 976 if (options != NULL && options[OPT_TSIZE].o_request) 977 options[OPT_TSIZE].o_reply = 512; 978 client->file = fmemopen(buf, 512, "r"); 979 if (client->file == NULL) 980 return (errno + 100); 981 982 return (0); 983 } 984 985 if (iflag) { 986 int ret; 987 988 /* 989 * In -i mode, look in the directory named after the 990 * client address. 991 */ 992 ret = snprintf(rewritten, sizeof(rewritten), "%s/%s", 993 getip(&client->ss), requested); 994 if (ret < 0 || ret >= sizeof(rewritten)) 995 return (ENAMETOOLONG + 100); 996 filename = rewritten; 997 } else { 998retryread: 999 filename = requested; 1000 } 1001 1002 /* 1003 * We use a different permissions scheme if `cancreate' is 1004 * set. 1005 */ 1006 wmode = O_TRUNC; 1007 if (stat(filename, &stbuf) == -1) { 1008 if (!cancreate) { 1009 /* 1010 * In -i mode, retry failed read requests from 1011 * the root directory. 1012 */ 1013 if (mode == RRQ && errno == ENOENT && 1014 filename == rewritten) 1015 goto retryread; 1016 return (errno == ENOENT ? ENOTFOUND : EACCESS); 1017 } else { 1018 if ((errno == ENOENT) && (mode != RRQ)) 1019 wmode |= O_CREAT; 1020 else 1021 return (EACCESS); 1022 } 1023 } else { 1024 if (mode == RRQ) { 1025 if ((stbuf.st_mode & (S_IRUSR >> 6)) == 0) 1026 return (EACCESS); 1027 } else { 1028 if ((stbuf.st_mode & (S_IWUSR >> 6)) == 0) 1029 return (EACCESS); 1030 } 1031 } 1032 1033 if (options != NULL && options[OPT_TSIZE].o_request) { 1034 if (mode == RRQ) 1035 options[OPT_TSIZE].o_reply = stbuf.st_size; 1036 else { 1037 /* allows writes of 65535 blocks * SEGSIZE_MAX bytes */ 1038 options[OPT_TSIZE].o_reply = 1039 strtonum(options[OPT_TSIZE].o_request, 1040 1, 65535LL * SEGSIZE_MAX, &errstr); 1041 if (errstr) 1042 return (EOPTNEG); 1043 } 1044 } 1045 fd = open(filename, mode == RRQ ? O_RDONLY : (O_WRONLY|wmode), 0666); 1046 if (fd == -1) 1047 return (errno + 100); 1048 /* 1049 * If the file was created, set default permissions. 1050 */ 1051 if ((wmode & O_CREAT) && fchmod(fd, 0666) == -1) { 1052 int serrno = errno; 1053 1054 close(fd); 1055 unlink(filename); 1056 1057 return (serrno + 100); 1058 } 1059 client->file = fdopen(fd, mode == RRQ ? "r" : "w"); 1060 if (client->file == NULL) { 1061 close(fd); 1062 return (errno + 100); 1063 } 1064 1065 return (0); 1066} 1067 1068int 1069fget_octet(struct tftp_client *client) 1070{ 1071 return (getc(client->file)); 1072} 1073 1074int 1075fput_octet(struct tftp_client *client, int c) 1076{ 1077 return (putc(c, client->file)); 1078} 1079 1080int 1081fget_netascii(struct tftp_client *client) 1082{ 1083 int c = -1; 1084 1085 switch (client->newline) { 1086 case 0: 1087 c = getc(client->file); 1088 if (c == EOF) 1089 break; 1090 1091 if (c == '\n' || c == '\r') { 1092 client->newline = c; 1093 c = '\r'; 1094 } 1095 break; 1096 case '\n': 1097 client->newline = 0; 1098 c = '\n'; 1099 break; 1100 case '\r': 1101 client->newline = 0; 1102 c = '\0'; 1103 break; 1104 } 1105 1106 return (c); 1107} 1108 1109int 1110fput_netascii(struct tftp_client *client, int c) 1111{ 1112 if (client->newline == '\r') { 1113 client->newline = 0; 1114 1115 if (c == '\0') 1116 c = '\r'; 1117 1118 } else if (c == '\r') { 1119 client->newline = c; 1120 return (c); 1121 } 1122 1123 return (putc(c, client->file)); 1124} 1125 1126void 1127sendfile(struct tftp_client *client) 1128{ 1129 event_set(&client->sev, client->sock, EV_READ, tftp_rrq_ack, client); 1130 client->block = 1; 1131 1132 file_read(client); 1133} 1134 1135void 1136file_read(struct tftp_client *client) 1137{ 1138 u_int8_t *buf; 1139 struct tftphdr *dp; 1140 int i; 1141 int c; 1142 1143 dp = (struct tftphdr *)client->buf; 1144 dp->th_opcode = htons((u_short)DATA); 1145 dp->th_block = htons(client->block); 1146 buf = (u_int8_t *)dp->th_data; 1147 1148 for (i = 0; i < client->segment_size; i++) { 1149 c = client->fgetc(client); 1150 if (c == EOF) { 1151 if (ferror(client->file)) { 1152 nak(client, 100 + EIO); 1153 return; 1154 } 1155 1156 break; 1157 } 1158 buf[i] = c; 1159 } 1160 1161 client->buflen = i + 4; 1162 client->retries = RETRIES; 1163 1164 if (send(client->sock, client->buf, client->buflen, 0) == -1) { 1165 lwarn("send(block)"); 1166 client_free(client); 1167 return; 1168 } 1169 1170 event_add(&client->sev, &client->tv); 1171} 1172 1173void 1174tftp_rrq_ack(int fd, short events, void *arg) 1175{ 1176 struct tftp_client *client = arg; 1177 struct tftphdr *ap; /* ack packet */ 1178 char rbuf[SEGSIZE_MIN]; 1179 ssize_t n; 1180 1181 if (events & EV_TIMEOUT) { 1182 if (retry(client) == -1) { 1183 lwarn("%s: retry", getip(&client->ss)); 1184 goto done; 1185 } 1186 1187 return; 1188 } 1189 1190 n = recv(fd, rbuf, sizeof(rbuf), 0); 1191 if (n == -1) { 1192 switch (errno) { 1193 case EINTR: 1194 case EAGAIN: 1195 event_add(&client->sev, &client->tv); 1196 return; 1197 1198 default: 1199 lwarn("%s: recv", getip(&client->ss)); 1200 goto done; 1201 } 1202 } 1203 1204 ap = (struct tftphdr *)rbuf; 1205 ap->th_opcode = ntohs((u_short)ap->th_opcode); 1206 ap->th_block = ntohs((u_short)ap->th_block); 1207 1208 switch (ap->th_opcode) { 1209 case ERROR: 1210 goto done; 1211 case ACK: 1212 break; 1213 default: 1214 goto retry; 1215 } 1216 1217 if (ap->th_block != client->block) { 1218 if (tftp_flush(client) == -1) { 1219 lwarnx("%s: flush", getip(&client->ss)); 1220 goto done; 1221 } 1222 1223 if (ap->th_block != (client->block - 1)) 1224 goto done; 1225 1226 goto retry; 1227 } 1228 1229 if (client->buflen != client->packet_size) { 1230 /* this was the last packet in the stream */ 1231 goto done; 1232 } 1233 1234 client->block++; 1235 file_read(client); 1236 return; 1237 1238retry: 1239 event_add(&client->sev, &client->tv); 1240 return; 1241 1242done: 1243 client_free(client); 1244} 1245 1246int 1247tftp_flush(struct tftp_client *client) 1248{ 1249 char rbuf[SEGSIZE_MIN]; 1250 ssize_t n; 1251 1252 for (;;) { 1253 n = recv(client->sock, rbuf, sizeof(rbuf), 0); 1254 if (n == -1) { 1255 switch (errno) { 1256 case EAGAIN: 1257 return (0); 1258 1259 case EINTR: 1260 break; 1261 1262 default: 1263 return (-1); 1264 } 1265 } 1266 } 1267} 1268 1269void 1270recvfile(struct tftp_client *client) 1271{ 1272 event_set(&client->sev, client->sock, EV_READ, tftp_wrq, client); 1273 tftp_wrq_ack(client); 1274} 1275 1276int 1277tftp_wrq_ack_packet(struct tftp_client *client) 1278{ 1279 struct tftphdr *ap; /* ack packet */ 1280 1281 ap = (struct tftphdr *)client->buf; 1282 ap->th_opcode = htons((u_short)ACK); 1283 ap->th_block = htons(client->block); 1284 1285 client->buflen = 4; 1286 client->retries = RETRIES; 1287 1288 return (send(client->sock, client->buf, client->buflen, 0) != 4); 1289} 1290 1291void 1292tftp_wrq_ack(struct tftp_client *client) 1293{ 1294 if (tftp_wrq_ack_packet(client) != 0) { 1295 lwarn("tftp wrq ack"); 1296 client_free(client); 1297 return; 1298 } 1299 1300 client->block++; 1301 event_add(&client->sev, &client->tv); 1302} 1303 1304void 1305tftp_wrq(int fd, short events, void *arg) 1306{ 1307 char wbuf[SEGSIZE_MAX + 4]; 1308 struct tftp_client *client = arg; 1309 struct tftphdr *dp; 1310 ssize_t n; 1311 int i; 1312 1313 if (events & EV_TIMEOUT) { 1314 if (retry(client) == -1) { 1315 lwarn("%s", getip(&client->ss)); 1316 goto done; 1317 } 1318 1319 return; 1320 } 1321 1322 n = recv(fd, wbuf, client->packet_size, 0); 1323 if (n == -1) { 1324 switch (errno) { 1325 case EINTR: 1326 case EAGAIN: 1327 goto retry; 1328 1329 default: 1330 lwarn("tftp_wrq recv"); 1331 goto done; 1332 } 1333 } 1334 1335 if (n < 4) 1336 goto done; 1337 1338 dp = (struct tftphdr *)wbuf; 1339 dp->th_opcode = ntohs((u_short)dp->th_opcode); 1340 dp->th_block = ntohs((u_short)dp->th_block); 1341 1342 switch (dp->th_opcode) { 1343 case ERROR: 1344 goto done; 1345 case DATA: 1346 break; 1347 default: 1348 goto retry; 1349 } 1350 1351 if (dp->th_block != client->block) { 1352 if (tftp_flush(client) == -1) { 1353 lwarnx("%s: flush", getip(&client->ss)); 1354 goto done; 1355 } 1356 1357 if (dp->th_block != (client->block - 1)) 1358 goto done; 1359 1360 goto retry; 1361 } 1362 1363 for (i = 4; i < n; i++) { 1364 if (client->fputc(client, wbuf[i]) == EOF) { 1365 lwarn("tftp wrq"); 1366 goto done; 1367 } 1368 } 1369 1370 if (n < client->packet_size) { 1371 tftp_wrq_ack_packet(client); 1372 fclose(client->file); 1373 client->file = NULL; 1374 event_set(&client->sev, client->sock, EV_READ, 1375 tftp_wrq_end, client); 1376 event_add(&client->sev, &client->tv); 1377 return; 1378 } 1379 1380 tftp_wrq_ack(client); 1381 return; 1382 1383retry: 1384 event_add(&client->sev, &client->tv); 1385 return; 1386done: 1387 client_free(client); 1388} 1389 1390void 1391tftp_wrq_end(int fd, short events, void *arg) 1392{ 1393 char wbuf[SEGSIZE_MAX + 4]; 1394 struct tftp_client *client = arg; 1395 struct tftphdr *dp; 1396 ssize_t n; 1397 1398 if (events & EV_TIMEOUT) { 1399 /* this was the last packet, we can clean up */ 1400 goto done; 1401 } 1402 1403 n = recv(fd, wbuf, client->packet_size, 0); 1404 if (n == -1) { 1405 switch (errno) { 1406 case EINTR: 1407 case EAGAIN: 1408 goto retry; 1409 1410 default: 1411 lwarn("tftp_wrq_end recv"); 1412 goto done; 1413 } 1414 } 1415 1416 if (n < 4) 1417 goto done; 1418 1419 dp = (struct tftphdr *)wbuf; 1420 dp->th_opcode = ntohs((u_short)dp->th_opcode); 1421 dp->th_block = ntohs((u_short)dp->th_block); 1422 1423 switch (dp->th_opcode) { 1424 case ERROR: 1425 goto done; 1426 case DATA: 1427 break; 1428 default: 1429 goto retry; 1430 } 1431 1432 if (dp->th_block != client->block) 1433 goto done; 1434 1435retry: 1436 if (retry(client) == -1) { 1437 lwarn("%s", getip(&client->ss)); 1438 goto done; 1439 } 1440 return; 1441done: 1442 client_free(client); 1443 return; 1444} 1445 1446 1447/* 1448 * Send a nak packet (error message). 1449 * Error code passed in is one of the 1450 * standard TFTP codes, or a UNIX errno 1451 * offset by 100. 1452 */ 1453void 1454nak(struct tftp_client *client, int error) 1455{ 1456 struct tftphdr *tp; 1457 struct errmsg *pe; 1458 size_t length; 1459 1460 tp = (struct tftphdr *)client->buf; 1461 tp->th_opcode = htons((u_short)ERROR); 1462 tp->th_code = htons((u_short)error); 1463 1464 for (pe = errmsgs; pe->e_code >= 0; pe++) { 1465 if (pe->e_code == error) 1466 break; 1467 } 1468 if (pe->e_code < 0) { 1469 pe->e_msg = strerror(error - 100); 1470 tp->th_code = htons(EUNDEF); /* set 'undef' errorcode */ 1471 } 1472 1473 length = strlcpy(tp->th_msg, pe->e_msg, client->packet_size - 5) + 5; 1474 if (length > client->packet_size) 1475 length = client->packet_size; 1476 1477 if (send(client->sock, client->buf, length, 0) != length) 1478 lwarn("nak"); 1479 1480 client_free(client); 1481} 1482 1483/* 1484 * Send an oack packet (option acknowledgement). 1485 */ 1486int 1487oack(struct tftp_client *client) 1488{ 1489 struct opt_client *options = client->options; 1490 struct tftphdr *tp; 1491 char *bp; 1492 int i, n, size; 1493 1494 tp = (struct tftphdr *)client->buf; 1495 bp = (char *)tp->th_stuff; 1496 size = sizeof(client->buf) - 2; 1497 1498 tp->th_opcode = htons((u_short)OACK); 1499 for (i = 0; i < NOPT; i++) { 1500 if (options[i].o_request == NULL) 1501 continue; 1502 1503 n = snprintf(bp, size, "%s%c%lld", opt_names[i], '\0', 1504 options[i].o_reply); 1505 if (n < 0 || n >= size) { 1506 lwarnx("oack: no buffer space"); 1507 goto error; 1508 } 1509 1510 bp += n + 1; 1511 size -= n + 1; 1512 if (size < 0) { 1513 lwarnx("oack: no buffer space"); 1514 goto error; 1515 } 1516 } 1517 1518 client->buflen = bp - client->buf; 1519 client->retries = RETRIES; 1520 1521 if (send(client->sock, client->buf, client->buflen, 0) == -1) { 1522 lwarn("oack"); 1523 goto error; 1524 } 1525 1526 /* no client ACK for write requests with options */ 1527 if (client->opcode == WRQ) { 1528 client->block = 1; 1529 event_set(&client->sev, client->sock, EV_READ, 1530 tftp_wrq, client); 1531 } else 1532 event_set(&client->sev, client->sock, EV_READ, 1533 oack_done, client); 1534 1535 event_add(&client->sev, &client->tv); 1536 return (0); 1537 1538error: 1539 return (-1); 1540} 1541 1542int 1543retry(struct tftp_client *client) 1544{ 1545 if (--client->retries == 0) { 1546 errno = ETIMEDOUT; 1547 return (-1); 1548 } 1549 1550 if (send(client->sock, client->buf, client->buflen, 0) == -1) 1551 return (-1); 1552 1553 event_add(&client->sev, &client->tv); 1554 1555 return (0); 1556} 1557 1558void 1559oack_done(int fd, short events, void *arg) 1560{ 1561 struct tftp_client *client = arg; 1562 struct tftphdr *ap; 1563 ssize_t n; 1564 1565 if (events & EV_TIMEOUT) { 1566 if (retry(client) == -1) { 1567 lwarn("%s", getip(&client->ss)); 1568 goto done; 1569 } 1570 1571 return; 1572 } 1573 1574 n = recv(client->sock, client->buf, client->packet_size, 0); 1575 if (n == -1) { 1576 switch (errno) { 1577 case EINTR: 1578 case EAGAIN: 1579 event_add(&client->sev, &client->tv); 1580 return; 1581 1582 default: 1583 lwarn("%s: recv", getip(&client->ss)); 1584 goto done; 1585 } 1586 } 1587 1588 if (n < 4) 1589 goto done; 1590 1591 ap = (struct tftphdr *)client->buf; 1592 ap->th_opcode = ntohs((u_short)ap->th_opcode); 1593 ap->th_block = ntohs((u_short)ap->th_block); 1594 1595 if (ap->th_opcode != ACK || ap->th_block != 0) 1596 goto done; 1597 1598 sendfile(client); 1599 return; 1600 1601done: 1602 client_free(client); 1603} 1604 1605const char * 1606getip(void *s) 1607{ 1608 struct sockaddr *sa = s; 1609 static char hbuf[NI_MAXHOST]; 1610 1611 if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), 1612 NULL, 0, NI_NUMERICHOST)) 1613 strlcpy(hbuf, "0.0.0.0", sizeof(hbuf)); 1614 1615 return(hbuf); 1616} 1617 1618/* daemon(3) clone, intended to be used in a "r"estricted environment */ 1619int 1620rdaemon(int devnull) 1621{ 1622 if (devnull == -1) { 1623 errno = EBADF; 1624 return (-1); 1625 } 1626 if (fcntl(devnull, F_GETFL) == -1) 1627 return (-1); 1628 1629 switch (fork()) { 1630 case -1: 1631 return (-1); 1632 case 0: 1633 break; 1634 default: 1635 _exit(0); 1636 } 1637 1638 if (setsid() == -1) 1639 return (-1); 1640 1641 (void)dup2(devnull, STDIN_FILENO); 1642 (void)dup2(devnull, STDOUT_FILENO); 1643 (void)dup2(devnull, STDERR_FILENO); 1644 if (devnull > 2) 1645 (void)close(devnull); 1646 1647 return (0); 1648} 1649 1650void 1651syslog_vstrerror(int e, int priority, const char *fmt, va_list ap) 1652{ 1653 char *s; 1654 1655 if (vasprintf(&s, fmt, ap) == -1) { 1656 syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror"); 1657 exit(1); 1658 } 1659 1660 syslog(priority, "%s: %s", s, strerror(e)); 1661 1662 free(s); 1663} 1664 1665void 1666syslog_err(int ecode, const char *fmt, ...) 1667{ 1668 va_list ap; 1669 1670 va_start(ap, fmt); 1671 syslog_vstrerror(errno, LOG_CRIT, fmt, ap); 1672 va_end(ap); 1673 1674 exit(ecode); 1675} 1676 1677void 1678syslog_errx(int ecode, const char *fmt, ...) 1679{ 1680 va_list ap; 1681 1682 va_start(ap, fmt); 1683 vsyslog(LOG_CRIT, fmt, ap); 1684 va_end(ap); 1685 1686 exit(ecode); 1687} 1688 1689void 1690syslog_warn(const char *fmt, ...) 1691{ 1692 va_list ap; 1693 1694 va_start(ap, fmt); 1695 syslog_vstrerror(errno, LOG_ERR, fmt, ap); 1696 va_end(ap); 1697} 1698 1699void 1700syslog_warnx(const char *fmt, ...) 1701{ 1702 va_list ap; 1703 1704 va_start(ap, fmt); 1705 vsyslog(LOG_ERR, fmt, ap); 1706 va_end(ap); 1707} 1708 1709void 1710syslog_info(const char *fmt, ...) 1711{ 1712 va_list ap; 1713 1714 va_start(ap, fmt); 1715 vsyslog(LOG_INFO, fmt, ap); 1716 va_end(ap); 1717} 1718 1719void 1720syslog_debug(const char *fmt, ...) 1721{ 1722 va_list ap; 1723 1724 if (!debug) 1725 return; 1726 1727 va_start(ap, fmt); 1728 vsyslog(LOG_DEBUG, fmt, ap); 1729 va_end(ap); 1730} 1731