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
recv_ack(uint16_t blocknum)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
recv_oack(const char * options,size_t options_len)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
recv_data(uint16_t blocknum,const char * contents,size_t contents_len)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
send_bytes(const void * cmd,size_t len)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
send_data(uint16_t blocknum,const char * contents,size_t contents_len)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
send_ack(uint16_t blocknum)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
sigalrm(int signo __unused)255 sigalrm(int signo __unused)
256 {
257 }
258
259 /* Check that server exits with specific exit code */
260 static void
check_server(int exitcode)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
cleanup(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
require_bufeq(const char * expected,size_t expected_len,const char * actual,size_t len)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
setup(struct sockaddr_storage * to,uint16_t idx)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
write_all(int fd,const void * buf,size_t nbytes)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
ATF_TP_ADD_TCS(tp)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