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