1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018 Alan Somers. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 #include <sys/param.h> 30 #include <sys/socket.h> 31 #include <sys/stat.h> 32 #include <sys/wait.h> 33 34 #include <netinet/in.h> 35 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <signal.h> 39 #include <stdalign.h> 40 #include <stdio.h> 41 #include <unistd.h> 42 43 #include <atf-c.h> 44 #include <libutil.h> 45 46 static const uint16_t BASEPORT = 6969; 47 static const char pidfile[] = "tftpd.pid"; 48 static int protocol = PF_UNSPEC; 49 static int s = -1; /* tftp client socket */ 50 static struct sockaddr_storage addr; /* Destination address for the client */ 51 static bool s_flag = false; /* Pass -s to tftpd */ 52 static bool w_flag = false; /* Pass -w to tftpd */ 53 54 /* Helper functions*/ 55 static void require_bufeq(const char *expected, ssize_t expected_len, 56 const char *actual, ssize_t len); 57 58 /* 59 * Receive a response from tftpd 60 * @param hdr The reply's expected header, as a char array 61 * @param contents The reply's expected contents, as a char array 62 * @param contents_len Length of contents 63 */ 64 #define RECV(hdr, contents, contents_len) do { \ 65 char buffer[1024]; \ 66 struct sockaddr_storage from; \ 67 socklen_t fromlen = sizeof(from); \ 68 ssize_t r = recvfrom(s, buffer, sizeof(buffer), 0, \ 69 (struct sockaddr*)&from, &fromlen); \ 70 ATF_REQUIRE(r > 0); \ 71 require_bufeq((hdr), sizeof(hdr), buffer, \ 72 MIN(r, (ssize_t)sizeof(hdr))); \ 73 require_bufeq((const char*) (contents), (contents_len), \ 74 &buffer[sizeof(hdr)], r - sizeof(hdr)); \ 75 if (protocol == PF_INET) { \ 76 ((struct sockaddr_in*)&addr)->sin_port = \ 77 ((struct sockaddr_in*)&from)->sin_port; \ 78 } else { \ 79 ((struct sockaddr_in6*)&addr)->sin6_port = \ 80 ((struct sockaddr_in6*)&from)->sin6_port; \ 81 } \ 82 } while(0) 83 84 static void 85 recv_ack(uint16_t blocknum) 86 { 87 char hdr[] = {0, 4, blocknum >> 8, blocknum & 0xFF}; 88 RECV(hdr, NULL, 0); 89 } 90 91 static void 92 recv_oack(const char *options, size_t options_len) 93 { 94 char hdr[] = {0, 6}; 95 RECV(hdr, options, options_len); 96 } 97 98 /* 99 * Receive a data packet from tftpd 100 * @param blocknum Expected block number to be received 101 * @param contents Pointer to expected contents 102 * @param contents_len Length of contents expected to receive 103 */ 104 static void 105 recv_data(uint16_t blocknum, const char* contents, size_t contents_len) 106 { 107 char hdr[] = {0, 3, blocknum >> 8, blocknum & 0xFF}; 108 RECV(hdr, contents, contents_len); 109 } 110 111 #define RECV_ERROR(code, msg) do { \ 112 char hdr[] = {0, 5, code >> 8, code & 0xFF}; \ 113 RECV(hdr, msg, sizeof(msg)); \ 114 } while (0) 115 116 /* 117 * send a command to tftpd. 118 * @param cmd Command to send, as a char array 119 */ 120 static void 121 send_bytes(const void* cmd, ssize_t len) 122 { 123 ssize_t r; 124 125 r = sendto(s, cmd, len, 0, (struct sockaddr*)(&addr), addr.ss_len); 126 ATF_REQUIRE_EQ(r, len); 127 } 128 129 static void 130 send_data(uint16_t blocknum, const char* contents, size_t contents_len) 131 { 132 char buffer[1024]; 133 134 buffer[0] = 0; /* DATA opcode high byte */ 135 buffer[1] = 3; /* DATA opcode low byte */ 136 buffer[2] = blocknum >> 8; 137 buffer[3] = blocknum & 0xFF; 138 memmove(&buffer[4], contents, contents_len); 139 send_bytes(buffer, 4 + contents_len); 140 } 141 142 /* 143 * send a command to tftpd. 144 * @param cmd Command to send, as a const string 145 * (terminating NUL will be ignored) 146 */ 147 #define SEND_STR(cmd) ATF_REQUIRE_EQ( \ 148 sendto(s, (cmd), sizeof(cmd) - 1, 0, (struct sockaddr*)(&addr), \ 149 addr.ss_len), \ 150 sizeof(cmd) - 1) 151 152 /* 153 * Acknowledge block blocknum 154 */ 155 static void 156 send_ack(uint16_t blocknum) 157 { 158 char packet[] = { 159 0, 4, /* ACK opcode in BE */ 160 blocknum >> 8, 161 blocknum & 0xFF 162 }; 163 164 send_bytes(packet, sizeof(packet)); 165 166 } 167 168 /* 169 * build an option string 170 */ 171 #define OPTION_STR(name, value) name "\000" value "\000" 172 173 /* 174 * send a read request to tftpd. 175 * @param filename filename as a string, absolute or relative 176 * @param mode either "octet" or "netascii" 177 */ 178 #define SEND_RRQ(filename, mode) SEND_STR("\0\001" filename "\0" mode "\0") 179 180 /* 181 * send a read request with options 182 */ 183 #define SEND_RRQ_OPT(filename, mode, options) SEND_STR("\0\001" filename "\0" mode "\000" options) 184 185 /* 186 * send a write request to tftpd. 187 * @param filename filename as a string, absolute or relative 188 * @param mode either "octet" or "netascii" 189 */ 190 #define SEND_WRQ(filename, mode) SEND_STR("\0\002" filename "\0" mode "\0") 191 192 /* 193 * send a write request with options 194 */ 195 #define SEND_WRQ_OPT(filename, mode, options) SEND_STR("\0\002" filename "\0" mode "\000" options) 196 197 /* Define a test case, for both IPv4 and IPv6 */ 198 #define TFTPD_TC_DEFINE(name, head, ...) \ 199 static void \ 200 name ## _body(void); \ 201 ATF_TC_WITH_CLEANUP(name ## _v4); \ 202 ATF_TC_HEAD(name ## _v4, tc) \ 203 { \ 204 head \ 205 } \ 206 ATF_TC_BODY(name ## _v4, tc) \ 207 { \ 208 __VA_ARGS__; \ 209 protocol = AF_INET; \ 210 s = setup(&addr, __COUNTER__); \ 211 name ## _body(); \ 212 close(s); \ 213 } \ 214 ATF_TC_CLEANUP(name ## _v4, tc) \ 215 { \ 216 cleanup(); \ 217 } \ 218 ATF_TC_WITH_CLEANUP(name ## _v6); \ 219 ATF_TC_HEAD(name ## _v6, tc) \ 220 { \ 221 head \ 222 } \ 223 ATF_TC_BODY(name ## _v6, tc) \ 224 { \ 225 __VA_ARGS__; \ 226 protocol = AF_INET6; \ 227 s = setup(&addr, __COUNTER__); \ 228 name ## _body(); \ 229 close(s); \ 230 } \ 231 ATF_TC_CLEANUP(name ## _v6, tc) \ 232 { \ 233 cleanup(); \ 234 } \ 235 static void \ 236 name ## _body(void) 237 238 /* Add the IPv4 and IPv6 versions of a test case */ 239 #define TFTPD_TC_ADD(tp, name ) \ 240 do { \ 241 ATF_TP_ADD_TC(tp, name ## _v4); \ 242 ATF_TP_ADD_TC(tp, name ## _v6); \ 243 } while (0) 244 245 /* Standard cleanup used by all testcases */ 246 static void 247 cleanup(void) 248 { 249 FILE *f; 250 pid_t pid; 251 252 f = fopen(pidfile, "r"); 253 if (f == NULL) 254 return; 255 if (fscanf(f, "%d", &pid) == 1) { 256 kill(pid, SIGTERM); 257 waitpid(pid, NULL, 0); 258 } 259 fclose(f); 260 unlink(pidfile); 261 } 262 263 /* Assert that two binary buffers are identical */ 264 static void 265 require_bufeq(const char *expected, ssize_t expected_len, const char *actual, 266 ssize_t len) 267 { 268 ssize_t i; 269 270 ATF_REQUIRE_EQ_MSG(expected_len, len, 271 "Expected %zd bytes but got %zd", expected_len, len); 272 for (i = 0; i < len; i++) { 273 ATF_REQUIRE_EQ_MSG(actual[i], expected[i], 274 "Expected %#hhx at position %zd; got %hhx instead", 275 expected[i], i, actual[i]); 276 } 277 } 278 279 /* 280 * Start tftpd and return its communicating socket 281 * @param to Will be filled in for use with sendto 282 * @param idx Unique identifier of the test case 283 * @return Socket ready to use 284 */ 285 static int 286 setup(struct sockaddr_storage *to, uint16_t idx) 287 { 288 int client_s, server_s, pid, argv_idx; 289 char execname[] = "/usr/libexec/tftpd"; 290 char s_flag_str[] = "-s"; 291 char w_flag_str[] = "-w"; 292 char pwd[MAXPATHLEN]; 293 char *argv[10]; 294 struct sockaddr_in addr4; 295 struct sockaddr_in6 addr6; 296 struct sockaddr *server_addr; 297 struct pidfh *pfh; 298 uint16_t port = BASEPORT + idx; 299 socklen_t len; 300 301 if (protocol == PF_INET) { 302 len = sizeof(addr4); 303 bzero(&addr4, len); 304 addr4.sin_len = len; 305 addr4.sin_family = PF_INET; 306 addr4.sin_port = htons(port); 307 server_addr = (struct sockaddr*)&addr4; 308 } else { 309 len = sizeof(addr6); 310 bzero(&addr6, len); 311 addr6.sin6_len = len; 312 addr6.sin6_family = PF_INET6; 313 addr6.sin6_port = htons(port); 314 server_addr = (struct sockaddr*)&addr6; 315 } 316 317 ATF_REQUIRE_EQ(getcwd(pwd, sizeof(pwd)), pwd); 318 319 /* Must bind(2) pre-fork so it happens before the client's send(2) */ 320 server_s = socket(protocol, SOCK_DGRAM, 0); 321 if (server_s < 0 && errno == EAFNOSUPPORT) { 322 atf_tc_skip("This test requires IPv%d support", 323 protocol == PF_INET ? 4 : 6); 324 } 325 ATF_REQUIRE_MSG(server_s >= 0, 326 "socket failed with error %s", strerror(errno)); 327 ATF_REQUIRE_EQ_MSG(bind(server_s, server_addr, len), 0, 328 "bind failed with error %s", strerror(errno)); 329 330 pid = fork(); 331 switch (pid) { 332 case -1: 333 atf_tc_fail("fork failed"); 334 break; 335 case 0: 336 /* In child */ 337 pfh = pidfile_open(pidfile, 0644, NULL); 338 ATF_REQUIRE_MSG(pfh != NULL, 339 "pidfile_open: %s", strerror(errno)); 340 ATF_REQUIRE_EQ(pidfile_write(pfh), 0); 341 ATF_REQUIRE_EQ(pidfile_close(pfh), 0); 342 343 bzero(argv, sizeof(argv)); 344 argv[0] = execname; 345 argv_idx = 1; 346 if (w_flag) 347 argv[argv_idx++] = w_flag_str; 348 if (s_flag) 349 argv[argv_idx++] = s_flag_str; 350 argv[argv_idx++] = pwd; 351 ATF_REQUIRE_EQ(dup2(server_s, STDOUT_FILENO), STDOUT_FILENO); 352 ATF_REQUIRE_EQ(dup2(server_s, STDIN_FILENO), STDIN_FILENO); 353 ATF_REQUIRE_EQ(dup2(server_s, STDERR_FILENO), STDERR_FILENO); 354 execv(execname, argv); 355 atf_tc_fail("exec failed"); 356 break; 357 default: 358 /* In parent */ 359 bzero(to, sizeof(*to)); 360 if (protocol == PF_INET) { 361 struct sockaddr_in *to4 = (struct sockaddr_in*)to; 362 to4->sin_len = sizeof(*to4); 363 to4->sin_family = PF_INET; 364 to4->sin_port = htons(port); 365 to4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 366 } else { 367 struct in6_addr loopback = IN6ADDR_LOOPBACK_INIT; 368 struct sockaddr_in6 *to6 = (struct sockaddr_in6*)to; 369 to6->sin6_len = sizeof(*to6); 370 to6->sin6_family = PF_INET6; 371 to6->sin6_port = htons(port); 372 to6->sin6_addr = loopback; 373 } 374 375 close(server_s); 376 ATF_REQUIRE((client_s = socket(protocol, SOCK_DGRAM, 0)) > 0); 377 break; 378 } 379 380 /* Clear the client's umask. Test cases will specify exact modes */ 381 umask(0000); 382 383 return (client_s); 384 } 385 386 /* Like write(2), but never returns less than the requested length */ 387 static void 388 write_all(int fd, const void *buf, size_t nbytes) 389 { 390 ssize_t r; 391 392 while (nbytes > 0) { 393 r = write(fd, buf, nbytes); 394 ATF_REQUIRE(r > 0); 395 nbytes -= r; 396 buf = (const char*)buf + r; 397 } 398 } 399 400 401 /* 402 * Test Cases 403 */ 404 405 /* 406 * Read a file, specified by absolute pathname. 407 */ 408 TFTPD_TC_DEFINE(abspath,) 409 { 410 int fd; 411 char command[1024]; 412 size_t pathlen; 413 char suffix[] = {'\0', 'o', 'c', 't', 'e', 't', '\0'}; 414 415 command[0] = 0; /* RRQ high byte */ 416 command[1] = 1; /* RRQ low byte */ 417 ATF_REQUIRE(getcwd(&command[2], sizeof(command) - 2) != NULL); 418 pathlen = strlcat(&command[2], "/abspath.txt", sizeof(command) - 2); 419 ATF_REQUIRE(pathlen + sizeof(suffix) < sizeof(command) - 2); 420 memmove(&command[2 + pathlen], suffix, sizeof(suffix)); 421 422 fd = open("abspath.txt", O_CREAT | O_RDONLY, 0644); 423 ATF_REQUIRE(fd >= 0); 424 close(fd); 425 426 send_bytes(command, 2 + pathlen + sizeof(suffix)); 427 recv_data(1, NULL, 0); 428 send_ack(1); 429 } 430 431 /* 432 * Attempt to read a file outside of the allowed directory(ies) 433 */ 434 TFTPD_TC_DEFINE(dotdot,) 435 { 436 ATF_REQUIRE_EQ(mkdir("subdir", 0777), 0); 437 SEND_RRQ("../disallowed.txt", "octet"); 438 RECV_ERROR(2, "Access violation"); 439 s = setup(&addr, __COUNTER__); \ 440 SEND_RRQ("subdir/../../disallowed.txt", "octet"); 441 RECV_ERROR(2, "Access violation"); 442 s = setup(&addr, __COUNTER__); \ 443 SEND_RRQ("/etc/passwd", "octet"); 444 RECV_ERROR(2, "Access violation"); 445 } 446 447 /* 448 * With "-s", tftpd should chroot to the specified directory 449 */ 450 TFTPD_TC_DEFINE(s_flag, atf_tc_set_md_var(tc, "require.user", "root");, 451 s_flag = true) 452 { 453 int fd; 454 char contents[] = "small"; 455 456 fd = open("small.txt", O_RDWR | O_CREAT, 0644); 457 ATF_REQUIRE(fd >= 0); 458 write_all(fd, contents, strlen(contents) + 1); 459 close(fd); 460 461 SEND_RRQ("/small.txt", "octet"); 462 recv_data(1, contents, strlen(contents) + 1); 463 send_ack(1); 464 } 465 466 /* 467 * Read a file, and simulate a dropped ACK packet 468 */ 469 TFTPD_TC_DEFINE(rrq_dropped_ack,) 470 { 471 int fd; 472 char contents[] = "small"; 473 474 fd = open("small.txt", O_RDWR | O_CREAT, 0644); 475 ATF_REQUIRE(fd >= 0); 476 write_all(fd, contents, strlen(contents) + 1); 477 close(fd); 478 479 SEND_RRQ("small.txt", "octet"); 480 recv_data(1, contents, strlen(contents) + 1); 481 /* 482 * client "sends" the ack, but network drops it 483 * Eventually, tftpd should resend the data packet 484 */ 485 recv_data(1, contents, strlen(contents) + 1); 486 send_ack(1); 487 } 488 489 /* 490 * Read a file, and simulate a dropped DATA packet 491 */ 492 TFTPD_TC_DEFINE(rrq_dropped_data,) 493 { 494 int fd; 495 size_t i; 496 uint32_t contents[192]; 497 char buffer[1024]; 498 499 for (i = 0; i < nitems(contents); i++) 500 contents[i] = i; 501 502 fd = open("medium.txt", O_RDWR | O_CREAT, 0644); 503 ATF_REQUIRE(fd >= 0); 504 write_all(fd, contents, sizeof(contents)); 505 close(fd); 506 507 SEND_RRQ("medium.txt", "octet"); 508 recv_data(1, (const char*)&contents[0], 512); 509 send_ack(1); 510 (void) recvfrom(s, buffer, sizeof(buffer), 0, NULL, NULL); 511 /* 512 * server "sends" the data, but network drops it 513 * Eventually, client should resend the last ACK 514 */ 515 send_ack(1); 516 recv_data(2, (const char*)&contents[128], 256); 517 send_ack(2); 518 } 519 520 /* 521 * Read a medium file, and simulate a duplicated ACK packet 522 */ 523 TFTPD_TC_DEFINE(rrq_duped_ack,) 524 { 525 int fd; 526 size_t i; 527 uint32_t contents[192]; 528 529 for (i = 0; i < nitems(contents); i++) 530 contents[i] = i; 531 532 fd = open("medium.txt", O_RDWR | O_CREAT, 0644); 533 ATF_REQUIRE(fd >= 0); 534 write_all(fd, contents, sizeof(contents)); 535 close(fd); 536 537 SEND_RRQ("medium.txt", "octet"); 538 recv_data(1, (const char*)&contents[0], 512); 539 send_ack(1); 540 send_ack(1); /* Dupe an ACK packet */ 541 recv_data(2, (const char*)&contents[128], 256); 542 recv_data(2, (const char*)&contents[128], 256); 543 send_ack(2); 544 } 545 546 547 /* 548 * Attempt to read a file without read permissions 549 */ 550 TFTPD_TC_DEFINE(rrq_eaccess,) 551 { 552 int fd; 553 554 fd = open("empty.txt", O_CREAT | O_RDONLY, 0000); 555 ATF_REQUIRE(fd >= 0); 556 close(fd); 557 558 SEND_RRQ("empty.txt", "octet"); 559 RECV_ERROR(2, "Access violation"); 560 } 561 562 /* 563 * Read an empty file 564 */ 565 TFTPD_TC_DEFINE(rrq_empty,) 566 { 567 int fd; 568 569 fd = open("empty.txt", O_CREAT | O_RDONLY, 0644); 570 ATF_REQUIRE(fd >= 0); 571 close(fd); 572 573 SEND_RRQ("empty.txt", "octet"); 574 recv_data(1, NULL, 0); 575 send_ack(1); 576 } 577 578 /* 579 * Read a medium file of more than one block 580 */ 581 TFTPD_TC_DEFINE(rrq_medium,) 582 { 583 int fd; 584 size_t i; 585 uint32_t contents[192]; 586 587 for (i = 0; i < nitems(contents); i++) 588 contents[i] = i; 589 590 fd = open("medium.txt", O_RDWR | O_CREAT, 0644); 591 ATF_REQUIRE(fd >= 0); 592 write_all(fd, contents, sizeof(contents)); 593 close(fd); 594 595 SEND_RRQ("medium.txt", "octet"); 596 recv_data(1, (const char*)&contents[0], 512); 597 send_ack(1); 598 recv_data(2, (const char*)&contents[128], 256); 599 send_ack(2); 600 } 601 602 /* 603 * Read a medium file with a window size of 2. 604 */ 605 TFTPD_TC_DEFINE(rrq_medium_window,) 606 { 607 int fd; 608 size_t i; 609 uint32_t contents[192]; 610 char options[] = OPTION_STR("windowsize", "2"); 611 612 for (i = 0; i < nitems(contents); i++) 613 contents[i] = i; 614 615 fd = open("medium.txt", O_RDWR | O_CREAT, 0644); 616 ATF_REQUIRE(fd >= 0); 617 write_all(fd, contents, sizeof(contents)); 618 close(fd); 619 620 SEND_RRQ_OPT("medium.txt", "octet", OPTION_STR("windowsize", "2")); 621 recv_oack(options, sizeof(options) - 1); 622 send_ack(0); 623 recv_data(1, (const char*)&contents[0], 512); 624 recv_data(2, (const char*)&contents[128], 256); 625 send_ack(2); 626 } 627 628 /* 629 * Read a file in netascii format 630 */ 631 TFTPD_TC_DEFINE(rrq_netascii,) 632 { 633 int fd; 634 char contents[] = "foo\nbar\rbaz\n"; 635 /* 636 * Weirdly, RFC-764 says that CR must be followed by NUL if a line feed 637 * is not intended 638 */ 639 char expected[] = "foo\r\nbar\r\0baz\r\n"; 640 641 fd = open("unix.txt", O_RDWR | O_CREAT, 0644); 642 ATF_REQUIRE(fd >= 0); 643 write_all(fd, contents, strlen(contents) + 1); 644 close(fd); 645 646 SEND_RRQ("unix.txt", "netascii"); 647 recv_data(1, expected, sizeof(expected)); 648 send_ack(1); 649 } 650 651 /* 652 * Read a file that doesn't exist 653 */ 654 TFTPD_TC_DEFINE(rrq_nonexistent,) 655 { 656 SEND_RRQ("nonexistent.txt", "octet"); 657 RECV_ERROR(1, "File not found"); 658 } 659 660 /* 661 * Attempt to read a file whose name exceeds PATH_MAX 662 */ 663 TFTPD_TC_DEFINE(rrq_path_max,) 664 { 665 #define AReallyBigFileName \ 666 "AReallyBigFileNameXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 667 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 668 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 669 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 670 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 671 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 672 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 673 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 674 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 675 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 676 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 677 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 678 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 679 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 680 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 681 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 682 ".txt" 683 ATF_REQUIRE_MSG(strlen(AReallyBigFileName) > PATH_MAX, 684 "Somebody increased PATH_MAX. Update the test"); 685 SEND_RRQ(AReallyBigFileName, "octet"); 686 RECV_ERROR(4, "Illegal TFTP operation"); 687 } 688 689 /* 690 * Read a small file of less than one block 691 */ 692 TFTPD_TC_DEFINE(rrq_small,) 693 { 694 int fd; 695 char contents[] = "small"; 696 697 fd = open("small.txt", O_RDWR | O_CREAT, 0644); 698 ATF_REQUIRE(fd >= 0); 699 write_all(fd, contents, strlen(contents) + 1); 700 close(fd); 701 702 SEND_RRQ("small.txt", "octet"); 703 recv_data(1, contents, strlen(contents) + 1); 704 send_ack(1); 705 } 706 707 /* 708 * Read a file following the example in RFC 7440. 709 */ 710 TFTPD_TC_DEFINE(rrq_window_rfc7440,) 711 { 712 int fd; 713 size_t i; 714 char options[] = OPTION_STR("windowsize", "4"); 715 alignas(uint32_t) char contents[13 * 512 - 4]; 716 uint32_t *u32p; 717 718 u32p = (uint32_t *)contents; 719 for (i = 0; i < sizeof(contents) / sizeof(uint32_t); i++) 720 u32p[i] = i; 721 722 fd = open("rfc7440.txt", O_RDWR | O_CREAT, 0644); 723 ATF_REQUIRE(fd >= 0); 724 write_all(fd, contents, sizeof(contents)); 725 close(fd); 726 727 SEND_RRQ_OPT("rfc7440.txt", "octet", OPTION_STR("windowsize", "4")); 728 recv_oack(options, sizeof(options) - 1); 729 send_ack(0); 730 recv_data(1, &contents[0 * 512], 512); 731 recv_data(2, &contents[1 * 512], 512); 732 recv_data(3, &contents[2 * 512], 512); 733 recv_data(4, &contents[3 * 512], 512); 734 send_ack(4); 735 recv_data(5, &contents[4 * 512], 512); 736 recv_data(6, &contents[5 * 512], 512); 737 recv_data(7, &contents[6 * 512], 512); 738 recv_data(8, &contents[7 * 512], 512); 739 740 /* ACK 5 as if 6-8 were dropped. */ 741 send_ack(5); 742 recv_data(6, &contents[5 * 512], 512); 743 recv_data(7, &contents[6 * 512], 512); 744 recv_data(8, &contents[7 * 512], 512); 745 recv_data(9, &contents[8 * 512], 512); 746 send_ack(9); 747 recv_data(10, &contents[9 * 512], 512); 748 recv_data(11, &contents[10 * 512], 512); 749 recv_data(12, &contents[11 * 512], 512); 750 recv_data(13, &contents[12 * 512], 508); 751 752 /* Drop ACK and after timeout receive 10-13. */ 753 recv_data(10, &contents[9 * 512], 512); 754 recv_data(11, &contents[10 * 512], 512); 755 recv_data(12, &contents[11 * 512], 512); 756 recv_data(13, &contents[12 * 512], 508); 757 send_ack(13); 758 } 759 760 /* 761 * Try to transfer a file with an unknown mode. 762 */ 763 TFTPD_TC_DEFINE(unknown_modes,) 764 { 765 SEND_RRQ("foo.txt", "ascii"); /* Misspelling of "ascii" */ 766 RECV_ERROR(4, "Illegal TFTP operation"); 767 s = setup(&addr, __COUNTER__); \ 768 SEND_RRQ("foo.txt", "binary"); /* Obsolete. Use "octet" instead */ 769 RECV_ERROR(4, "Illegal TFTP operation"); 770 s = setup(&addr, __COUNTER__); \ 771 SEND_RRQ("foo.txt", "en_US.UTF-8"); 772 RECV_ERROR(4, "Illegal TFTP operation"); 773 s = setup(&addr, __COUNTER__); \ 774 SEND_RRQ("foo.txt", "mail"); /* Obsolete in RFC-1350 */ 775 RECV_ERROR(4, "Illegal TFTP operation"); 776 } 777 778 /* 779 * Send an unknown opcode. tftpd should respond with the appropriate error 780 */ 781 TFTPD_TC_DEFINE(unknown_opcode,) 782 { 783 /* Looks like an RRQ or WRQ request, but with a bad opcode */ 784 SEND_STR("\0\007foo.txt\0octet\0"); 785 RECV_ERROR(4, "Illegal TFTP operation"); 786 } 787 788 /* 789 * Invoke tftpd with "-w" and write to a nonexistent file. 790 */ 791 TFTPD_TC_DEFINE(w_flag,, w_flag = 1;) 792 { 793 int fd; 794 ssize_t r; 795 char contents[] = "small"; 796 char buffer[1024]; 797 size_t contents_len; 798 799 contents_len = strlen(contents) + 1; 800 SEND_WRQ("small.txt", "octet"); 801 recv_ack(0); 802 send_data(1, contents, contents_len); 803 recv_ack(1); 804 805 fd = open("small.txt", O_RDONLY); 806 ATF_REQUIRE(fd >= 0); 807 r = read(fd, buffer, sizeof(buffer)); 808 close(fd); 809 require_bufeq(contents, contents_len, buffer, r); 810 } 811 812 /* 813 * Write a medium file, and simulate a dropped ACK packet 814 */ 815 TFTPD_TC_DEFINE(wrq_dropped_ack,) 816 { 817 int fd; 818 size_t i; 819 ssize_t r; 820 uint32_t contents[192]; 821 char buffer[1024]; 822 823 for (i = 0; i < nitems(contents); i++) 824 contents[i] = i; 825 826 fd = open("medium.txt", O_RDWR | O_CREAT, 0666); 827 ATF_REQUIRE(fd >= 0); 828 close(fd); 829 830 SEND_WRQ("medium.txt", "octet"); 831 recv_ack(0); 832 send_data(1, (const char*)&contents[0], 512); 833 /* 834 * Servers "sends" an ACK packet, but network drops it. 835 * Eventually, server should resend the last ACK 836 */ 837 (void) recvfrom(s, buffer, sizeof(buffer), 0, NULL, NULL); 838 recv_ack(1); 839 send_data(2, (const char*)&contents[128], 256); 840 recv_ack(2); 841 842 fd = open("medium.txt", O_RDONLY); 843 ATF_REQUIRE(fd >= 0); 844 r = read(fd, buffer, sizeof(buffer)); 845 close(fd); 846 require_bufeq((const char*)contents, 768, buffer, r); 847 } 848 849 /* 850 * Write a small file, and simulate a dropped DATA packet 851 */ 852 TFTPD_TC_DEFINE(wrq_dropped_data,) 853 { 854 int fd; 855 ssize_t r; 856 char contents[] = "small"; 857 size_t contents_len; 858 char buffer[1024]; 859 860 fd = open("small.txt", O_RDWR | O_CREAT, 0666); 861 ATF_REQUIRE(fd >= 0); 862 close(fd); 863 contents_len = strlen(contents) + 1; 864 865 SEND_WRQ("small.txt", "octet"); 866 recv_ack(0); 867 /* 868 * Client "sends" a DATA packet, but network drops it. 869 * Eventually, server should resend the last ACK 870 */ 871 recv_ack(0); 872 send_data(1, contents, contents_len); 873 recv_ack(1); 874 875 fd = open("small.txt", O_RDONLY); 876 ATF_REQUIRE(fd >= 0); 877 r = read(fd, buffer, sizeof(buffer)); 878 close(fd); 879 require_bufeq(contents, contents_len, buffer, r); 880 } 881 882 /* 883 * Write a medium file, and simulate a duplicated DATA packet 884 */ 885 TFTPD_TC_DEFINE(wrq_duped_data,) 886 { 887 int fd; 888 size_t i; 889 ssize_t r; 890 uint32_t contents[192]; 891 char buffer[1024]; 892 893 for (i = 0; i < nitems(contents); i++) 894 contents[i] = i; 895 896 fd = open("medium.txt", O_RDWR | O_CREAT, 0666); 897 ATF_REQUIRE(fd >= 0); 898 close(fd); 899 900 SEND_WRQ("medium.txt", "octet"); 901 recv_ack(0); 902 send_data(1, (const char*)&contents[0], 512); 903 send_data(1, (const char*)&contents[0], 512); 904 recv_ack(1); 905 recv_ack(1); 906 send_data(2, (const char*)&contents[128], 256); 907 recv_ack(2); 908 909 fd = open("medium.txt", O_RDONLY); 910 ATF_REQUIRE(fd >= 0); 911 r = read(fd, buffer, sizeof(buffer)); 912 close(fd); 913 require_bufeq((const char*)contents, 768, buffer, r); 914 } 915 916 /* 917 * Attempt to write a file without write permissions 918 */ 919 TFTPD_TC_DEFINE(wrq_eaccess,) 920 { 921 int fd; 922 923 fd = open("empty.txt", O_CREAT | O_RDONLY, 0440); 924 ATF_REQUIRE(fd >= 0); 925 close(fd); 926 927 SEND_WRQ("empty.txt", "octet"); 928 RECV_ERROR(2, "Access violation"); 929 } 930 931 /* 932 * Attempt to write a file without world write permissions, but with world 933 * read permissions 934 */ 935 TFTPD_TC_DEFINE(wrq_eaccess_world_readable,) 936 { 937 int fd; 938 939 fd = open("empty.txt", O_CREAT | O_RDONLY, 0444); 940 ATF_REQUIRE(fd >= 0); 941 close(fd); 942 943 SEND_WRQ("empty.txt", "octet"); 944 RECV_ERROR(2, "Access violation"); 945 } 946 947 948 /* 949 * Write a medium file of more than one block 950 */ 951 TFTPD_TC_DEFINE(wrq_medium,) 952 { 953 int fd; 954 size_t i; 955 ssize_t r; 956 uint32_t contents[192]; 957 char buffer[1024]; 958 959 for (i = 0; i < nitems(contents); i++) 960 contents[i] = i; 961 962 fd = open("medium.txt", O_RDWR | O_CREAT, 0666); 963 ATF_REQUIRE(fd >= 0); 964 close(fd); 965 966 SEND_WRQ("medium.txt", "octet"); 967 recv_ack(0); 968 send_data(1, (const char*)&contents[0], 512); 969 recv_ack(1); 970 send_data(2, (const char*)&contents[128], 256); 971 recv_ack(2); 972 973 fd = open("medium.txt", O_RDONLY); 974 ATF_REQUIRE(fd >= 0); 975 r = read(fd, buffer, sizeof(buffer)); 976 close(fd); 977 require_bufeq((const char*)contents, 768, buffer, r); 978 } 979 980 /* 981 * Write a medium file with a window size of 2. 982 */ 983 TFTPD_TC_DEFINE(wrq_medium_window,) 984 { 985 int fd; 986 size_t i; 987 ssize_t r; 988 uint32_t contents[192]; 989 char buffer[1024]; 990 char options[] = OPTION_STR("windowsize", "2"); 991 992 for (i = 0; i < nitems(contents); i++) 993 contents[i] = i; 994 995 fd = open("medium.txt", O_RDWR | O_CREAT, 0666); 996 ATF_REQUIRE(fd >= 0); 997 close(fd); 998 999 SEND_WRQ_OPT("medium.txt", "octet", OPTION_STR("windowsize", "2")); 1000 recv_oack(options, sizeof(options) - 1); 1001 send_data(1, (const char*)&contents[0], 512); 1002 send_data(2, (const char*)&contents[128], 256); 1003 recv_ack(2); 1004 1005 fd = open("medium.txt", O_RDONLY); 1006 ATF_REQUIRE(fd >= 0); 1007 r = read(fd, buffer, sizeof(buffer)); 1008 close(fd); 1009 require_bufeq((const char*)contents, 768, buffer, r); 1010 } 1011 1012 /* 1013 * Write a file in netascii format 1014 */ 1015 TFTPD_TC_DEFINE(wrq_netascii,) 1016 { 1017 int fd; 1018 ssize_t r; 1019 /* 1020 * Weirdly, RFC-764 says that CR must be followed by NUL if a line feed 1021 * is not intended 1022 */ 1023 char contents[] = "foo\r\nbar\r\0baz\r\n"; 1024 char expected[] = "foo\nbar\rbaz\n"; 1025 size_t contents_len; 1026 char buffer[1024]; 1027 1028 fd = open("unix.txt", O_RDWR | O_CREAT, 0666); 1029 ATF_REQUIRE(fd >= 0); 1030 close(fd); 1031 contents_len = sizeof(contents); 1032 1033 SEND_WRQ("unix.txt", "netascii"); 1034 recv_ack(0); 1035 send_data(1, contents, contents_len); 1036 recv_ack(1); 1037 1038 fd = open("unix.txt", O_RDONLY); 1039 ATF_REQUIRE(fd >= 0); 1040 r = read(fd, buffer, sizeof(buffer)); 1041 close(fd); 1042 require_bufeq(expected, sizeof(expected), buffer, r); 1043 } 1044 1045 /* 1046 * Attempt to write to a nonexistent file. With the default options, this 1047 * isn't allowed. 1048 */ 1049 TFTPD_TC_DEFINE(wrq_nonexistent,) 1050 { 1051 SEND_WRQ("nonexistent.txt", "octet"); 1052 RECV_ERROR(1, "File not found"); 1053 } 1054 1055 /* 1056 * Write a small file of less than one block 1057 */ 1058 TFTPD_TC_DEFINE(wrq_small,) 1059 { 1060 int fd; 1061 ssize_t r; 1062 char contents[] = "small"; 1063 size_t contents_len; 1064 char buffer[1024]; 1065 1066 fd = open("small.txt", O_RDWR | O_CREAT, 0666); 1067 ATF_REQUIRE(fd >= 0); 1068 close(fd); 1069 contents_len = strlen(contents) + 1; 1070 1071 SEND_WRQ("small.txt", "octet"); 1072 recv_ack(0); 1073 send_data(1, contents, contents_len); 1074 recv_ack(1); 1075 1076 fd = open("small.txt", O_RDONLY); 1077 ATF_REQUIRE(fd >= 0); 1078 r = read(fd, buffer, sizeof(buffer)); 1079 close(fd); 1080 require_bufeq(contents, contents_len, buffer, r); 1081 } 1082 1083 /* 1084 * Write an empty file over a non-empty one 1085 */ 1086 TFTPD_TC_DEFINE(wrq_truncate,) 1087 { 1088 int fd; 1089 char contents[] = "small"; 1090 struct stat sb; 1091 1092 fd = open("small.txt", O_RDWR | O_CREAT, 0666); 1093 ATF_REQUIRE(fd >= 0); 1094 write_all(fd, contents, strlen(contents) + 1); 1095 close(fd); 1096 1097 SEND_WRQ("small.txt", "octet"); 1098 recv_ack(0); 1099 send_data(1, NULL, 0); 1100 recv_ack(1); 1101 1102 ATF_REQUIRE_EQ(stat("small.txt", &sb), 0); 1103 ATF_REQUIRE_EQ(sb.st_size, 0); 1104 } 1105 1106 /* 1107 * Write a file following the example in RFC 7440. 1108 */ 1109 TFTPD_TC_DEFINE(wrq_window_rfc7440,) 1110 { 1111 int fd; 1112 size_t i; 1113 ssize_t r; 1114 char options[] = OPTION_STR("windowsize", "4"); 1115 alignas(uint32_t) char contents[13 * 512 - 4]; 1116 char buffer[sizeof(contents)]; 1117 uint32_t *u32p; 1118 1119 u32p = (uint32_t *)contents; 1120 for (i = 0; i < sizeof(contents) / sizeof(uint32_t); i++) 1121 u32p[i] = i; 1122 1123 fd = open("rfc7440.txt", O_RDWR | O_CREAT, 0666); 1124 ATF_REQUIRE(fd >= 0); 1125 close(fd); 1126 1127 SEND_WRQ_OPT("rfc7440.txt", "octet", OPTION_STR("windowsize", "4")); 1128 recv_oack(options, sizeof(options) - 1); 1129 send_data(1, &contents[0 * 512], 512); 1130 send_data(2, &contents[1 * 512], 512); 1131 send_data(3, &contents[2 * 512], 512); 1132 send_data(4, &contents[3 * 512], 512); 1133 recv_ack(4); 1134 send_data(5, &contents[4 * 512], 512); 1135 1136 /* Drop 6-8. */ 1137 recv_ack(5); 1138 send_data(6, &contents[5 * 512], 512); 1139 send_data(7, &contents[6 * 512], 512); 1140 send_data(8, &contents[7 * 512], 512); 1141 send_data(9, &contents[8 * 512], 512); 1142 recv_ack(9); 1143 1144 /* Drop 11. */ 1145 send_data(10, &contents[9 * 512], 512); 1146 send_data(12, &contents[11 * 512], 512); 1147 1148 /* 1149 * We can't send 13 here as tftpd has probably already seen 12 1150 * and sent the ACK of 10 if running locally. While it would 1151 * recover by sending another ACK of 10, our state machine 1152 * would be out of sync. 1153 */ 1154 1155 /* Ignore ACK for 10 and resend 10-13. */ 1156 recv_ack(10); 1157 send_data(10, &contents[9 * 512], 512); 1158 send_data(11, &contents[10 * 512], 512); 1159 send_data(12, &contents[11 * 512], 512); 1160 send_data(13, &contents[12 * 512], 508); 1161 recv_ack(13); 1162 1163 fd = open("rfc7440.txt", O_RDONLY); 1164 ATF_REQUIRE(fd >= 0); 1165 r = read(fd, buffer, sizeof(buffer)); 1166 close(fd); 1167 require_bufeq(contents, sizeof(contents), buffer, r); 1168 } 1169 1170 1171 /* 1172 * Main 1173 */ 1174 1175 ATF_TP_ADD_TCS(tp) 1176 { 1177 TFTPD_TC_ADD(tp, abspath); 1178 TFTPD_TC_ADD(tp, dotdot); 1179 TFTPD_TC_ADD(tp, s_flag); 1180 TFTPD_TC_ADD(tp, rrq_dropped_ack); 1181 TFTPD_TC_ADD(tp, rrq_dropped_data); 1182 TFTPD_TC_ADD(tp, rrq_duped_ack); 1183 TFTPD_TC_ADD(tp, rrq_eaccess); 1184 TFTPD_TC_ADD(tp, rrq_empty); 1185 TFTPD_TC_ADD(tp, rrq_medium); 1186 TFTPD_TC_ADD(tp, rrq_medium_window); 1187 TFTPD_TC_ADD(tp, rrq_netascii); 1188 TFTPD_TC_ADD(tp, rrq_nonexistent); 1189 TFTPD_TC_ADD(tp, rrq_path_max); 1190 TFTPD_TC_ADD(tp, rrq_small); 1191 TFTPD_TC_ADD(tp, rrq_window_rfc7440); 1192 TFTPD_TC_ADD(tp, unknown_modes); 1193 TFTPD_TC_ADD(tp, unknown_opcode); 1194 TFTPD_TC_ADD(tp, w_flag); 1195 TFTPD_TC_ADD(tp, wrq_dropped_ack); 1196 TFTPD_TC_ADD(tp, wrq_dropped_data); 1197 TFTPD_TC_ADD(tp, wrq_duped_data); 1198 TFTPD_TC_ADD(tp, wrq_eaccess); 1199 TFTPD_TC_ADD(tp, wrq_eaccess_world_readable); 1200 TFTPD_TC_ADD(tp, wrq_medium); 1201 TFTPD_TC_ADD(tp, wrq_medium_window); 1202 TFTPD_TC_ADD(tp, wrq_netascii); 1203 TFTPD_TC_ADD(tp, wrq_nonexistent); 1204 TFTPD_TC_ADD(tp, wrq_small); 1205 TFTPD_TC_ADD(tp, wrq_truncate); 1206 TFTPD_TC_ADD(tp, wrq_window_rfc7440); 1207 1208 return (atf_no_error()); 1209 } 1210