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