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