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