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