1888651fcSAlan Somers /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3888651fcSAlan Somers * 4809a8352SAlan Somers * Copyright (c) 2018 Alan Somers. 5809a8352SAlan Somers * 6888651fcSAlan Somers * Redistribution and use in source and binary forms, with or without 7888651fcSAlan Somers * modification, are permitted provided that the following conditions 8888651fcSAlan Somers * are met: 9888651fcSAlan Somers * 1. Redistributions of source code must retain the above copyright 10888651fcSAlan Somers * notice, this list of conditions and the following disclaimer. 11888651fcSAlan Somers * 2. Redistributions in binary form must reproduce the above copyright 12888651fcSAlan Somers * notice, this list of conditions and the following disclaimer in the 13888651fcSAlan Somers * documentation and/or other materials provided with the distribution. 14888651fcSAlan Somers * 15888651fcSAlan Somers * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16888651fcSAlan Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17888651fcSAlan Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18888651fcSAlan Somers * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 19888651fcSAlan Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20888651fcSAlan Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21888651fcSAlan Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22888651fcSAlan Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23888651fcSAlan Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24888651fcSAlan Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25888651fcSAlan Somers * SUCH DAMAGE. 26888651fcSAlan Somers */ 27888651fcSAlan Somers 28888651fcSAlan Somers #include <sys/param.h> 29888651fcSAlan Somers #include <sys/socket.h> 30888651fcSAlan Somers #include <sys/stat.h> 31ae285a8cSDag-Erling Smørgrav #include <sys/time.h> 32888651fcSAlan Somers #include <sys/wait.h> 33888651fcSAlan Somers 34888651fcSAlan Somers #include <netinet/in.h> 35888651fcSAlan Somers 36888651fcSAlan Somers #include <errno.h> 37888651fcSAlan Somers #include <fcntl.h> 38888651fcSAlan Somers #include <signal.h> 39fdf929ffSJohn Baldwin #include <stdalign.h> 40888651fcSAlan Somers #include <stdio.h> 41888651fcSAlan Somers #include <unistd.h> 42888651fcSAlan Somers 43888651fcSAlan Somers #include <atf-c.h> 44888651fcSAlan Somers #include <libutil.h> 45888651fcSAlan Somers 46888651fcSAlan Somers static const uint16_t BASEPORT = 6969; 47888651fcSAlan Somers static const char pidfile[] = "tftpd.pid"; 48888651fcSAlan Somers static int protocol = PF_UNSPEC; 49888651fcSAlan Somers static int s = -1; /* tftp client socket */ 50888651fcSAlan Somers static struct sockaddr_storage addr; /* Destination address for the client */ 51888651fcSAlan Somers static bool s_flag = false; /* Pass -s to tftpd */ 52888651fcSAlan Somers static bool w_flag = false; /* Pass -w to tftpd */ 53888651fcSAlan Somers 54888651fcSAlan Somers /* Helper functions*/ 551ed44fccSDag-Erling Smørgrav static void require_bufeq(const char *expected, size_t expected_len, 561ed44fccSDag-Erling Smørgrav const char *actual, size_t len); 57888651fcSAlan Somers 58888651fcSAlan Somers /* 59888651fcSAlan Somers * Receive a response from tftpd 60888651fcSAlan Somers * @param hdr The reply's expected header, as a char array 61888651fcSAlan Somers * @param contents The reply's expected contents, as a char array 62888651fcSAlan Somers * @param contents_len Length of contents 63888651fcSAlan Somers */ 64888651fcSAlan Somers #define RECV(hdr, contents, contents_len) do { \ 65888651fcSAlan Somers char buffer[1024]; \ 66888651fcSAlan Somers struct sockaddr_storage from; \ 67888651fcSAlan Somers socklen_t fromlen = sizeof(from); \ 68888651fcSAlan Somers ssize_t r = recvfrom(s, buffer, sizeof(buffer), 0, \ 69888651fcSAlan Somers (struct sockaddr *)&from, &fromlen); \ 70888651fcSAlan Somers ATF_REQUIRE(r > 0); \ 71888651fcSAlan Somers require_bufeq((hdr), sizeof(hdr), buffer, \ 721ed44fccSDag-Erling Smørgrav MIN((size_t)r, sizeof(hdr))); \ 73888651fcSAlan Somers require_bufeq((const char *) (contents), (contents_len), \ 74888651fcSAlan Somers &buffer[sizeof(hdr)], r - sizeof(hdr)); \ 75888651fcSAlan Somers if (protocol == PF_INET) { \ 76888651fcSAlan Somers ((struct sockaddr_in *)&addr)->sin_port = \ 77888651fcSAlan Somers ((struct sockaddr_in *)&from)->sin_port; \ 78888651fcSAlan Somers } else { \ 79888651fcSAlan Somers ((struct sockaddr_in6 *)&addr)->sin6_port = \ 80888651fcSAlan Somers ((struct sockaddr_in6 *)&from)->sin6_port; \ 81888651fcSAlan Somers } \ 82888651fcSAlan Somers } while(0) 83888651fcSAlan Somers 84888651fcSAlan Somers static void 85888651fcSAlan Somers recv_ack(uint16_t blocknum) 86888651fcSAlan Somers { 87888651fcSAlan Somers char hdr[] = {0, 4, blocknum >> 8, blocknum & 0xFF}; 88888651fcSAlan Somers RECV(hdr, NULL, 0); 89888651fcSAlan Somers } 90888651fcSAlan Somers 91fdf929ffSJohn Baldwin static void 92fdf929ffSJohn Baldwin recv_oack(const char *options, size_t options_len) 93fdf929ffSJohn Baldwin { 94fdf929ffSJohn Baldwin char hdr[] = {0, 6}; 95fdf929ffSJohn Baldwin RECV(hdr, options, options_len); 96fdf929ffSJohn Baldwin } 97fdf929ffSJohn Baldwin 98888651fcSAlan Somers /* 99888651fcSAlan Somers * Receive a data packet from tftpd 100888651fcSAlan Somers * @param blocknum Expected block number to be received 101888651fcSAlan Somers * @param contents Pointer to expected contents 102888651fcSAlan Somers * @param contents_len Length of contents expected to receive 103888651fcSAlan Somers */ 104888651fcSAlan Somers static void 105888651fcSAlan Somers recv_data(uint16_t blocknum, const char *contents, size_t contents_len) 106888651fcSAlan Somers { 107888651fcSAlan Somers char hdr[] = {0, 3, blocknum >> 8, blocknum & 0xFF}; 108888651fcSAlan Somers RECV(hdr, contents, contents_len); 109888651fcSAlan Somers } 110888651fcSAlan Somers 111888651fcSAlan Somers #define RECV_ERROR(code, msg) do { \ 112888651fcSAlan Somers char hdr[] = {0, 5, code >> 8, code & 0xFF}; \ 113888651fcSAlan Somers RECV(hdr, msg, sizeof(msg)); \ 114888651fcSAlan Somers } while (0) 115888651fcSAlan Somers 116888651fcSAlan Somers /* 117888651fcSAlan Somers * send a command to tftpd. 118888651fcSAlan Somers * @param cmd Command to send, as a char array 119888651fcSAlan Somers */ 120888651fcSAlan Somers static void 1211ed44fccSDag-Erling Smørgrav send_bytes(const void *cmd, size_t len) 122888651fcSAlan Somers { 123888651fcSAlan Somers ssize_t r; 124888651fcSAlan Somers 125888651fcSAlan Somers r = sendto(s, cmd, len, 0, (struct sockaddr *)(&addr), addr.ss_len); 1261ed44fccSDag-Erling Smørgrav ATF_REQUIRE(r >= 0); 1271ed44fccSDag-Erling Smørgrav ATF_REQUIRE_EQ(len, (size_t)r); 128888651fcSAlan Somers } 129888651fcSAlan Somers 130888651fcSAlan Somers static void 131888651fcSAlan Somers send_data(uint16_t blocknum, const char *contents, size_t contents_len) 132888651fcSAlan Somers { 133888651fcSAlan Somers char buffer[1024]; 134888651fcSAlan Somers 135888651fcSAlan Somers buffer[0] = 0; /* DATA opcode high byte */ 136888651fcSAlan Somers buffer[1] = 3; /* DATA opcode low byte */ 137888651fcSAlan Somers buffer[2] = blocknum >> 8; 138888651fcSAlan Somers buffer[3] = blocknum & 0xFF; 139888651fcSAlan Somers memmove(&buffer[4], contents, contents_len); 140888651fcSAlan Somers send_bytes(buffer, 4 + contents_len); 141888651fcSAlan Somers } 142888651fcSAlan Somers 143888651fcSAlan Somers /* 144888651fcSAlan Somers * send a command to tftpd. 145888651fcSAlan Somers * @param cmd Command to send, as a const string 146888651fcSAlan Somers * (terminating NUL will be ignored) 147888651fcSAlan Somers */ 1487ab7ecfcSDag-Erling Smørgrav #define SEND_STR(cmd) \ 1497ab7ecfcSDag-Erling Smørgrav ATF_REQUIRE_EQ(sizeof(cmd) - 1, \ 1507ab7ecfcSDag-Erling Smørgrav sendto(s, (cmd), sizeof(cmd) - 1, 0, \ 1517ab7ecfcSDag-Erling Smørgrav (struct sockaddr *)(&addr), addr.ss_len)) 152888651fcSAlan Somers 153888651fcSAlan Somers /* 154888651fcSAlan Somers * Acknowledge block blocknum 155888651fcSAlan Somers */ 156888651fcSAlan Somers static void 157888651fcSAlan Somers send_ack(uint16_t blocknum) 158888651fcSAlan Somers { 159888651fcSAlan Somers char packet[] = { 160888651fcSAlan Somers 0, 4, /* ACK opcode in BE */ 161888651fcSAlan Somers blocknum >> 8, 162888651fcSAlan Somers blocknum & 0xFF 163888651fcSAlan Somers }; 164888651fcSAlan Somers 165888651fcSAlan Somers send_bytes(packet, sizeof(packet)); 166888651fcSAlan Somers } 167888651fcSAlan Somers 168888651fcSAlan Somers /* 169fdf929ffSJohn Baldwin * build an option string 170fdf929ffSJohn Baldwin */ 171fdf929ffSJohn Baldwin #define OPTION_STR(name, value) name "\000" value "\000" 172fdf929ffSJohn Baldwin 173fdf929ffSJohn Baldwin /* 174888651fcSAlan Somers * send a read request to tftpd. 175888651fcSAlan Somers * @param filename filename as a string, absolute or relative 176888651fcSAlan Somers * @param mode either "octet" or "netascii" 177888651fcSAlan Somers */ 1787ab7ecfcSDag-Erling Smørgrav #define SEND_RRQ(filename, mode) \ 1797ab7ecfcSDag-Erling Smørgrav SEND_STR("\0\001" filename "\0" mode "\0") 180888651fcSAlan Somers 181888651fcSAlan Somers /* 182fdf929ffSJohn Baldwin * send a read request with options 183fdf929ffSJohn Baldwin */ 1847ab7ecfcSDag-Erling Smørgrav #define SEND_RRQ_OPT(filename, mode, options) \ 1857ab7ecfcSDag-Erling Smørgrav SEND_STR("\0\001" filename "\0" mode "\000" options) 186fdf929ffSJohn Baldwin 187fdf929ffSJohn Baldwin /* 188888651fcSAlan Somers * send a write request to tftpd. 189888651fcSAlan Somers * @param filename filename as a string, absolute or relative 190888651fcSAlan Somers * @param mode either "octet" or "netascii" 191888651fcSAlan Somers */ 1927ab7ecfcSDag-Erling Smørgrav #define SEND_WRQ(filename, mode) \ 1937ab7ecfcSDag-Erling Smørgrav SEND_STR("\0\002" filename "\0" mode "\0") 194888651fcSAlan Somers 195fdf929ffSJohn Baldwin /* 196fdf929ffSJohn Baldwin * send a write request with options 197fdf929ffSJohn Baldwin */ 1987ab7ecfcSDag-Erling Smørgrav #define SEND_WRQ_OPT(filename, mode, options) \ 1997ab7ecfcSDag-Erling Smørgrav SEND_STR("\0\002" filename "\0" mode "\000" options) 200fdf929ffSJohn Baldwin 201888651fcSAlan Somers /* Define a test case, for both IPv4 and IPv6 */ 202888651fcSAlan Somers #define TFTPD_TC_DEFINE(name, head, ...) \ 203888651fcSAlan Somers static void \ 204888651fcSAlan Somers name ## _body(void); \ 205888651fcSAlan Somers ATF_TC_WITH_CLEANUP(name ## _v4); \ 206888651fcSAlan Somers ATF_TC_HEAD(name ## _v4, tc) \ 207888651fcSAlan Somers { \ 208888651fcSAlan Somers head \ 209888651fcSAlan Somers } \ 210888651fcSAlan Somers ATF_TC_BODY(name ## _v4, tc) \ 211888651fcSAlan Somers { \ 21283a6e984SDag-Erling Smørgrav int exitcode = 0; \ 213888651fcSAlan Somers __VA_ARGS__; \ 214888651fcSAlan Somers protocol = AF_INET; \ 215888651fcSAlan Somers s = setup(&addr, __COUNTER__); \ 216888651fcSAlan Somers name ## _body(); \ 217888651fcSAlan Somers close(s); \ 21883a6e984SDag-Erling Smørgrav if (exitcode >= 0) \ 21983a6e984SDag-Erling Smørgrav check_server(exitcode); \ 220888651fcSAlan Somers } \ 221888651fcSAlan Somers ATF_TC_CLEANUP(name ## _v4, tc) \ 222888651fcSAlan Somers { \ 223888651fcSAlan Somers cleanup(); \ 224888651fcSAlan Somers } \ 225888651fcSAlan Somers ATF_TC_WITH_CLEANUP(name ## _v6); \ 226888651fcSAlan Somers ATF_TC_HEAD(name ## _v6, tc) \ 227888651fcSAlan Somers { \ 228888651fcSAlan Somers head \ 229888651fcSAlan Somers } \ 230888651fcSAlan Somers ATF_TC_BODY(name ## _v6, tc) \ 231888651fcSAlan Somers { \ 23283a6e984SDag-Erling Smørgrav int exitcode = 0; \ 233888651fcSAlan Somers __VA_ARGS__; \ 234888651fcSAlan Somers protocol = AF_INET6; \ 235888651fcSAlan Somers s = setup(&addr, __COUNTER__); \ 236888651fcSAlan Somers name ## _body(); \ 237888651fcSAlan Somers close(s); \ 23883a6e984SDag-Erling Smørgrav if (exitcode >= 0) \ 23983a6e984SDag-Erling Smørgrav check_server(exitcode); \ 240888651fcSAlan Somers } \ 241888651fcSAlan Somers ATF_TC_CLEANUP(name ## _v6, tc) \ 242888651fcSAlan Somers { \ 243888651fcSAlan Somers cleanup(); \ 244888651fcSAlan Somers } \ 245888651fcSAlan Somers static void \ 246888651fcSAlan Somers name ## _body(void) 247888651fcSAlan Somers 248888651fcSAlan Somers /* Add the IPv4 and IPv6 versions of a test case */ 2497ab7ecfcSDag-Erling Smørgrav #define TFTPD_TC_ADD(tp, name) do { \ 250888651fcSAlan Somers ATF_TP_ADD_TC(tp, name ## _v4); \ 251888651fcSAlan Somers ATF_TP_ADD_TC(tp, name ## _v6); \ 252888651fcSAlan Somers } while (0) 253888651fcSAlan Somers 25483a6e984SDag-Erling Smørgrav static void 25583a6e984SDag-Erling Smørgrav sigalrm(int signo __unused) 25683a6e984SDag-Erling Smørgrav { 25783a6e984SDag-Erling Smørgrav } 25883a6e984SDag-Erling Smørgrav 25983a6e984SDag-Erling Smørgrav /* Check that server exits with specific exit code */ 26083a6e984SDag-Erling Smørgrav static void 26183a6e984SDag-Erling Smørgrav check_server(int exitcode) 26283a6e984SDag-Erling Smørgrav { 26383a6e984SDag-Erling Smørgrav struct sigaction sa = { .sa_handler = sigalrm }; 26483a6e984SDag-Erling Smørgrav struct itimerval it = { .it_value = { .tv_sec = 30 } }; 26583a6e984SDag-Erling Smørgrav FILE *f; 26683a6e984SDag-Erling Smørgrav pid_t pid; 26783a6e984SDag-Erling Smørgrav int wstatus; 26883a6e984SDag-Erling Smørgrav 26983a6e984SDag-Erling Smørgrav f = fopen(pidfile, "r"); 27083a6e984SDag-Erling Smørgrav ATF_REQUIRE(f != NULL); 27183a6e984SDag-Erling Smørgrav ATF_REQUIRE_INTEQ(1, fscanf(f, "%d", &pid)); 27283a6e984SDag-Erling Smørgrav ATF_CHECK_INTEQ(0, fclose(f)); 27383a6e984SDag-Erling Smørgrav ATF_REQUIRE_INTEQ(0, sigaction(SIGALRM, &sa, NULL)); 27483a6e984SDag-Erling Smørgrav ATF_REQUIRE_EQ(0, setitimer(ITIMER_REAL, &it, NULL)); 27583a6e984SDag-Erling Smørgrav ATF_REQUIRE_EQ(pid, waitpid(pid, &wstatus, 0)); 27683a6e984SDag-Erling Smørgrav ATF_CHECK(WIFEXITED(wstatus)); 27783a6e984SDag-Erling Smørgrav ATF_CHECK_INTEQ(exitcode, WEXITSTATUS(wstatus)); 27883a6e984SDag-Erling Smørgrav unlink(pidfile); 27983a6e984SDag-Erling Smørgrav } 28083a6e984SDag-Erling Smørgrav 281888651fcSAlan Somers /* Standard cleanup used by all testcases */ 282888651fcSAlan Somers static void 283888651fcSAlan Somers cleanup(void) 284888651fcSAlan Somers { 285ad5c8bd6SAlan Somers FILE *f; 286888651fcSAlan Somers pid_t pid; 287888651fcSAlan Somers 288ad5c8bd6SAlan Somers f = fopen(pidfile, "r"); 289ad5c8bd6SAlan Somers if (f == NULL) 290888651fcSAlan Somers return; 29183a6e984SDag-Erling Smørgrav unlink(pidfile); 292ad5c8bd6SAlan Somers if (fscanf(f, "%d", &pid) == 1) { 293888651fcSAlan Somers kill(pid, SIGTERM); 294888651fcSAlan Somers waitpid(pid, NULL, 0); 295888651fcSAlan Somers } 296ad5c8bd6SAlan Somers fclose(f); 297888651fcSAlan Somers } 298888651fcSAlan Somers 299888651fcSAlan Somers /* Assert that two binary buffers are identical */ 300888651fcSAlan Somers static void 3017ab7ecfcSDag-Erling Smørgrav require_bufeq(const char *expected, size_t expected_len, 3027ab7ecfcSDag-Erling Smørgrav const char *actual, size_t len) 303888651fcSAlan Somers { 3041ed44fccSDag-Erling Smørgrav size_t i; 305888651fcSAlan Somers 306888651fcSAlan Somers ATF_REQUIRE_EQ_MSG(expected_len, len, 3071ed44fccSDag-Erling Smørgrav "Expected %zu bytes but got %zu", expected_len, len); 308888651fcSAlan Somers for (i = 0; i < len; i++) { 3097ab7ecfcSDag-Erling Smørgrav ATF_REQUIRE_EQ_MSG(expected[i], actual[i], 3101ed44fccSDag-Erling Smørgrav "Expected %#hhx at position %zu; got %hhx instead", 311888651fcSAlan Somers expected[i], i, actual[i]); 312888651fcSAlan Somers } 313888651fcSAlan Somers } 314888651fcSAlan Somers 315888651fcSAlan Somers /* 316888651fcSAlan Somers * Start tftpd and return its communicating socket 317888651fcSAlan Somers * @param to Will be filled in for use with sendto 318888651fcSAlan Somers * @param idx Unique identifier of the test case 319888651fcSAlan Somers * @return Socket ready to use 320888651fcSAlan Somers */ 321888651fcSAlan Somers static int 322888651fcSAlan Somers setup(struct sockaddr_storage *to, uint16_t idx) 323888651fcSAlan Somers { 324888651fcSAlan Somers int client_s, server_s, pid, argv_idx; 325888651fcSAlan Somers char execname[] = "/usr/libexec/tftpd"; 326*79c342aaSMark Johnston char b_flag_str[] = "-b"; 327888651fcSAlan Somers char s_flag_str[] = "-s"; 328888651fcSAlan Somers char w_flag_str[] = "-w"; 329888651fcSAlan Somers char pwd[MAXPATHLEN]; 330888651fcSAlan Somers char *argv[10]; 331888651fcSAlan Somers struct sockaddr_in addr4; 332888651fcSAlan Somers struct sockaddr_in6 addr6; 333888651fcSAlan Somers struct sockaddr *server_addr; 334888651fcSAlan Somers struct pidfh *pfh; 335888651fcSAlan Somers uint16_t port = BASEPORT + idx; 336888651fcSAlan Somers socklen_t len; 33783a6e984SDag-Erling Smørgrav int pd[2]; 33883a6e984SDag-Erling Smørgrav 33983a6e984SDag-Erling Smørgrav ATF_REQUIRE_EQ(0, pipe2(pd, O_CLOEXEC)); 340888651fcSAlan Somers 341888651fcSAlan Somers if (protocol == PF_INET) { 342888651fcSAlan Somers len = sizeof(addr4); 343888651fcSAlan Somers bzero(&addr4, len); 344888651fcSAlan Somers addr4.sin_len = len; 345888651fcSAlan Somers addr4.sin_family = PF_INET; 346888651fcSAlan Somers addr4.sin_port = htons(port); 347888651fcSAlan Somers server_addr = (struct sockaddr *)&addr4; 348888651fcSAlan Somers } else { 349888651fcSAlan Somers len = sizeof(addr6); 350888651fcSAlan Somers bzero(&addr6, len); 351888651fcSAlan Somers addr6.sin6_len = len; 352888651fcSAlan Somers addr6.sin6_family = PF_INET6; 353888651fcSAlan Somers addr6.sin6_port = htons(port); 354888651fcSAlan Somers server_addr = (struct sockaddr *)&addr6; 355888651fcSAlan Somers } 356888651fcSAlan Somers 3577ab7ecfcSDag-Erling Smørgrav ATF_REQUIRE_EQ(pwd, getcwd(pwd, sizeof(pwd))); 358888651fcSAlan Somers 359888651fcSAlan Somers /* Must bind(2) pre-fork so it happens before the client's send(2) */ 3601955ad42SDag-Erling Smørgrav server_s = socket(protocol, SOCK_DGRAM, 0); 3611955ad42SDag-Erling Smørgrav if (server_s < 0 && errno == EAFNOSUPPORT) { 3621955ad42SDag-Erling Smørgrav atf_tc_skip("This test requires IPv%d support", 3631955ad42SDag-Erling Smørgrav protocol == PF_INET ? 4 : 6); 3641955ad42SDag-Erling Smørgrav } 3651955ad42SDag-Erling Smørgrav ATF_REQUIRE_MSG(server_s >= 0, 3661955ad42SDag-Erling Smørgrav "socket failed with error %s", strerror(errno)); 3677ab7ecfcSDag-Erling Smørgrav ATF_REQUIRE_EQ_MSG(0, bind(server_s, server_addr, len), 368888651fcSAlan Somers "bind failed with error %s", strerror(errno)); 369888651fcSAlan Somers 370888651fcSAlan Somers pid = fork(); 371888651fcSAlan Somers switch (pid) { 372888651fcSAlan Somers case -1: 373888651fcSAlan Somers atf_tc_fail("fork failed"); 374888651fcSAlan Somers break; 375888651fcSAlan Somers case 0: 376888651fcSAlan Somers /* In child */ 377888651fcSAlan Somers pfh = pidfile_open(pidfile, 0644, NULL); 378888651fcSAlan Somers ATF_REQUIRE_MSG(pfh != NULL, 379888651fcSAlan Somers "pidfile_open: %s", strerror(errno)); 3807ab7ecfcSDag-Erling Smørgrav ATF_REQUIRE_EQ(0, pidfile_write(pfh)); 3817ab7ecfcSDag-Erling Smørgrav ATF_REQUIRE_EQ(0, pidfile_close(pfh)); 382888651fcSAlan Somers 383888651fcSAlan Somers bzero(argv, sizeof(argv)); 384888651fcSAlan Somers argv[0] = execname; 385888651fcSAlan Somers argv_idx = 1; 386*79c342aaSMark Johnston argv[argv_idx++] = b_flag_str; 387888651fcSAlan Somers if (w_flag) 388888651fcSAlan Somers argv[argv_idx++] = w_flag_str; 389888651fcSAlan Somers if (s_flag) 390888651fcSAlan Somers argv[argv_idx++] = s_flag_str; 391888651fcSAlan Somers argv[argv_idx++] = pwd; 3927ab7ecfcSDag-Erling Smørgrav ATF_REQUIRE_EQ(STDOUT_FILENO, dup2(server_s, STDOUT_FILENO)); 3937ab7ecfcSDag-Erling Smørgrav ATF_REQUIRE_EQ(STDIN_FILENO, dup2(server_s, STDIN_FILENO)); 3947ab7ecfcSDag-Erling Smørgrav ATF_REQUIRE_EQ(STDERR_FILENO, dup2(server_s, STDERR_FILENO)); 395888651fcSAlan Somers execv(execname, argv); 396888651fcSAlan Somers atf_tc_fail("exec failed"); 397888651fcSAlan Somers break; 398888651fcSAlan Somers default: 399888651fcSAlan Somers /* In parent */ 40083a6e984SDag-Erling Smørgrav ATF_REQUIRE_INTEQ(0, close(pd[1])); 40183a6e984SDag-Erling Smørgrav /* block until other end is closed on exec() or exit() */ 40283a6e984SDag-Erling Smørgrav ATF_REQUIRE_INTEQ(0, read(pd[0], &pd[1], sizeof(pd[1]))); 40383a6e984SDag-Erling Smørgrav ATF_REQUIRE_INTEQ(0, close(pd[0])); 404888651fcSAlan Somers bzero(to, sizeof(*to)); 405888651fcSAlan Somers if (protocol == PF_INET) { 406888651fcSAlan Somers struct sockaddr_in *to4 = (struct sockaddr_in *)to; 407888651fcSAlan Somers to4->sin_len = sizeof(*to4); 408888651fcSAlan Somers to4->sin_family = PF_INET; 409888651fcSAlan Somers to4->sin_port = htons(port); 410888651fcSAlan Somers to4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 411888651fcSAlan Somers } else { 412888651fcSAlan Somers struct in6_addr loopback = IN6ADDR_LOOPBACK_INIT; 413888651fcSAlan Somers struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)to; 414888651fcSAlan Somers to6->sin6_len = sizeof(*to6); 415888651fcSAlan Somers to6->sin6_family = PF_INET6; 416888651fcSAlan Somers to6->sin6_port = htons(port); 417888651fcSAlan Somers to6->sin6_addr = loopback; 418888651fcSAlan Somers } 419888651fcSAlan Somers 42083a6e984SDag-Erling Smørgrav ATF_REQUIRE_INTEQ(0, close(server_s)); 421888651fcSAlan Somers ATF_REQUIRE((client_s = socket(protocol, SOCK_DGRAM, 0)) > 0); 422888651fcSAlan Somers break; 423888651fcSAlan Somers } 424d89aca76SAlan Somers 425d89aca76SAlan Somers /* Clear the client's umask. Test cases will specify exact modes */ 426d89aca76SAlan Somers umask(0000); 427d89aca76SAlan Somers 428888651fcSAlan Somers return (client_s); 429888651fcSAlan Somers } 430888651fcSAlan Somers 431888651fcSAlan Somers /* Like write(2), but never returns less than the requested length */ 432888651fcSAlan Somers static void 433888651fcSAlan Somers write_all(int fd, const void *buf, size_t nbytes) 434888651fcSAlan Somers { 435888651fcSAlan Somers ssize_t r; 436888651fcSAlan Somers 437888651fcSAlan Somers while (nbytes > 0) { 438888651fcSAlan Somers r = write(fd, buf, nbytes); 439888651fcSAlan Somers ATF_REQUIRE(r > 0); 4401ed44fccSDag-Erling Smørgrav nbytes -= (size_t)r; 4411ed44fccSDag-Erling Smørgrav buf = (const char *)buf + (size_t)r; 442888651fcSAlan Somers } 443888651fcSAlan Somers } 444888651fcSAlan Somers 445888651fcSAlan Somers 446888651fcSAlan Somers /* 447888651fcSAlan Somers * Test Cases 448888651fcSAlan Somers */ 449888651fcSAlan Somers 450888651fcSAlan Somers /* 451888651fcSAlan Somers * Read a file, specified by absolute pathname. 452888651fcSAlan Somers */ 453888651fcSAlan Somers TFTPD_TC_DEFINE(abspath,) 454888651fcSAlan Somers { 455888651fcSAlan Somers int fd; 456888651fcSAlan Somers char command[1024]; 457888651fcSAlan Somers size_t pathlen; 458888651fcSAlan Somers char suffix[] = {'\0', 'o', 'c', 't', 'e', 't', '\0'}; 459888651fcSAlan Somers 460888651fcSAlan Somers command[0] = 0; /* RRQ high byte */ 461888651fcSAlan Somers command[1] = 1; /* RRQ low byte */ 462888651fcSAlan Somers ATF_REQUIRE(getcwd(&command[2], sizeof(command) - 2) != NULL); 463888651fcSAlan Somers pathlen = strlcat(&command[2], "/abspath.txt", sizeof(command) - 2); 464888651fcSAlan Somers ATF_REQUIRE(pathlen + sizeof(suffix) < sizeof(command) - 2); 465888651fcSAlan Somers memmove(&command[2 + pathlen], suffix, sizeof(suffix)); 466888651fcSAlan Somers 467888651fcSAlan Somers fd = open("abspath.txt", O_CREAT | O_RDONLY, 0644); 468888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 469888651fcSAlan Somers close(fd); 470888651fcSAlan Somers 471888651fcSAlan Somers send_bytes(command, 2 + pathlen + sizeof(suffix)); 472888651fcSAlan Somers recv_data(1, NULL, 0); 473888651fcSAlan Somers send_ack(1); 474888651fcSAlan Somers } 475888651fcSAlan Somers 476888651fcSAlan Somers /* 477888651fcSAlan Somers * Attempt to read a file outside of the allowed directory(ies) 478888651fcSAlan Somers */ 479888651fcSAlan Somers TFTPD_TC_DEFINE(dotdot,) 480888651fcSAlan Somers { 4817ab7ecfcSDag-Erling Smørgrav ATF_REQUIRE_EQ(0, mkdir("subdir", 0777)); 482888651fcSAlan Somers SEND_RRQ("../disallowed.txt", "octet"); 483888651fcSAlan Somers RECV_ERROR(2, "Access violation"); 4847ab7ecfcSDag-Erling Smørgrav s = setup(&addr, __COUNTER__); 485888651fcSAlan Somers SEND_RRQ("subdir/../../disallowed.txt", "octet"); 486888651fcSAlan Somers RECV_ERROR(2, "Access violation"); 4877ab7ecfcSDag-Erling Smørgrav s = setup(&addr, __COUNTER__); 488888651fcSAlan Somers SEND_RRQ("/etc/passwd", "octet"); 489888651fcSAlan Somers RECV_ERROR(2, "Access violation"); 490888651fcSAlan Somers } 491888651fcSAlan Somers 492888651fcSAlan Somers /* 493888651fcSAlan Somers * With "-s", tftpd should chroot to the specified directory 494888651fcSAlan Somers */ 4957ab7ecfcSDag-Erling Smørgrav TFTPD_TC_DEFINE(s_flag, 4967ab7ecfcSDag-Erling Smørgrav atf_tc_set_md_var(tc, "require.user", "root");, 497888651fcSAlan Somers s_flag = true) 498888651fcSAlan Somers { 499888651fcSAlan Somers int fd; 500888651fcSAlan Somers char contents[] = "small"; 501888651fcSAlan Somers 502888651fcSAlan Somers fd = open("small.txt", O_RDWR | O_CREAT, 0644); 503888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 504888651fcSAlan Somers write_all(fd, contents, strlen(contents) + 1); 505888651fcSAlan Somers close(fd); 506888651fcSAlan Somers 507888651fcSAlan Somers SEND_RRQ("/small.txt", "octet"); 508888651fcSAlan Somers recv_data(1, contents, strlen(contents) + 1); 509888651fcSAlan Somers send_ack(1); 510888651fcSAlan Somers } 511888651fcSAlan Somers 512888651fcSAlan Somers /* 513888651fcSAlan Somers * Read a file, and simulate a dropped ACK packet 514888651fcSAlan Somers */ 515888651fcSAlan Somers TFTPD_TC_DEFINE(rrq_dropped_ack,) 516888651fcSAlan Somers { 517888651fcSAlan Somers int fd; 518888651fcSAlan Somers char contents[] = "small"; 519888651fcSAlan Somers 520888651fcSAlan Somers fd = open("small.txt", O_RDWR | O_CREAT, 0644); 521888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 522888651fcSAlan Somers write_all(fd, contents, strlen(contents) + 1); 523888651fcSAlan Somers close(fd); 524888651fcSAlan Somers 525888651fcSAlan Somers SEND_RRQ("small.txt", "octet"); 526888651fcSAlan Somers recv_data(1, contents, strlen(contents) + 1); 527888651fcSAlan Somers /* 528888651fcSAlan Somers * client "sends" the ack, but network drops it 529888651fcSAlan Somers * Eventually, tftpd should resend the data packet 530888651fcSAlan Somers */ 531888651fcSAlan Somers recv_data(1, contents, strlen(contents) + 1); 532888651fcSAlan Somers send_ack(1); 533888651fcSAlan Somers } 534888651fcSAlan Somers 535888651fcSAlan Somers /* 536888651fcSAlan Somers * Read a file, and simulate a dropped DATA packet 537888651fcSAlan Somers */ 538888651fcSAlan Somers TFTPD_TC_DEFINE(rrq_dropped_data,) 539888651fcSAlan Somers { 540888651fcSAlan Somers int fd; 541888651fcSAlan Somers size_t i; 542888651fcSAlan Somers uint32_t contents[192]; 543888651fcSAlan Somers char buffer[1024]; 544888651fcSAlan Somers 545888651fcSAlan Somers for (i = 0; i < nitems(contents); i++) 546888651fcSAlan Somers contents[i] = i; 547888651fcSAlan Somers 548888651fcSAlan Somers fd = open("medium.txt", O_RDWR | O_CREAT, 0644); 549888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 550888651fcSAlan Somers write_all(fd, contents, sizeof(contents)); 551888651fcSAlan Somers close(fd); 552888651fcSAlan Somers 553888651fcSAlan Somers SEND_RRQ("medium.txt", "octet"); 554888651fcSAlan Somers recv_data(1, (const char *)&contents[0], 512); 555888651fcSAlan Somers send_ack(1); 556888651fcSAlan Somers (void) recvfrom(s, buffer, sizeof(buffer), 0, NULL, NULL); 557888651fcSAlan Somers /* 558888651fcSAlan Somers * server "sends" the data, but network drops it 559888651fcSAlan Somers * Eventually, client should resend the last ACK 560888651fcSAlan Somers */ 561888651fcSAlan Somers send_ack(1); 562888651fcSAlan Somers recv_data(2, (const char *)&contents[128], 256); 563888651fcSAlan Somers send_ack(2); 564888651fcSAlan Somers } 565888651fcSAlan Somers 566888651fcSAlan Somers /* 567888651fcSAlan Somers * Read a medium file, and simulate a duplicated ACK packet 568888651fcSAlan Somers */ 569888651fcSAlan Somers TFTPD_TC_DEFINE(rrq_duped_ack,) 570888651fcSAlan Somers { 571888651fcSAlan Somers int fd; 572888651fcSAlan Somers size_t i; 573888651fcSAlan Somers uint32_t contents[192]; 574888651fcSAlan Somers 575888651fcSAlan Somers for (i = 0; i < nitems(contents); i++) 576888651fcSAlan Somers contents[i] = i; 577888651fcSAlan Somers 578888651fcSAlan Somers fd = open("medium.txt", O_RDWR | O_CREAT, 0644); 579888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 580888651fcSAlan Somers write_all(fd, contents, sizeof(contents)); 581888651fcSAlan Somers close(fd); 582888651fcSAlan Somers 583888651fcSAlan Somers SEND_RRQ("medium.txt", "octet"); 584888651fcSAlan Somers recv_data(1, (const char *)&contents[0], 512); 585888651fcSAlan Somers send_ack(1); 586888651fcSAlan Somers send_ack(1); /* Dupe an ACK packet */ 587888651fcSAlan Somers recv_data(2, (const char *)&contents[128], 256); 588888651fcSAlan Somers recv_data(2, (const char *)&contents[128], 256); 589888651fcSAlan Somers send_ack(2); 590888651fcSAlan Somers } 591888651fcSAlan Somers 592888651fcSAlan Somers 593888651fcSAlan Somers /* 594888651fcSAlan Somers * Attempt to read a file without read permissions 595888651fcSAlan Somers */ 596888651fcSAlan Somers TFTPD_TC_DEFINE(rrq_eaccess,) 597888651fcSAlan Somers { 598888651fcSAlan Somers int fd; 599888651fcSAlan Somers 600888651fcSAlan Somers fd = open("empty.txt", O_CREAT | O_RDONLY, 0000); 601888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 602888651fcSAlan Somers close(fd); 603888651fcSAlan Somers 604888651fcSAlan Somers SEND_RRQ("empty.txt", "octet"); 605888651fcSAlan Somers RECV_ERROR(2, "Access violation"); 606888651fcSAlan Somers } 607888651fcSAlan Somers 608888651fcSAlan Somers /* 609888651fcSAlan Somers * Read an empty file 610888651fcSAlan Somers */ 611888651fcSAlan Somers TFTPD_TC_DEFINE(rrq_empty,) 612888651fcSAlan Somers { 613888651fcSAlan Somers int fd; 614888651fcSAlan Somers 615888651fcSAlan Somers fd = open("empty.txt", O_CREAT | O_RDONLY, 0644); 616888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 617888651fcSAlan Somers close(fd); 618888651fcSAlan Somers 619888651fcSAlan Somers SEND_RRQ("empty.txt", "octet"); 620888651fcSAlan Somers recv_data(1, NULL, 0); 621888651fcSAlan Somers send_ack(1); 622888651fcSAlan Somers } 623888651fcSAlan Somers 624888651fcSAlan Somers /* 625888651fcSAlan Somers * Read a medium file of more than one block 626888651fcSAlan Somers */ 627888651fcSAlan Somers TFTPD_TC_DEFINE(rrq_medium,) 628888651fcSAlan Somers { 629888651fcSAlan Somers int fd; 630888651fcSAlan Somers size_t i; 631888651fcSAlan Somers uint32_t contents[192]; 632888651fcSAlan Somers 633888651fcSAlan Somers for (i = 0; i < nitems(contents); i++) 634888651fcSAlan Somers contents[i] = i; 635888651fcSAlan Somers 636888651fcSAlan Somers fd = open("medium.txt", O_RDWR | O_CREAT, 0644); 637888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 638888651fcSAlan Somers write_all(fd, contents, sizeof(contents)); 639888651fcSAlan Somers close(fd); 640888651fcSAlan Somers 641888651fcSAlan Somers SEND_RRQ("medium.txt", "octet"); 642888651fcSAlan Somers recv_data(1, (const char *)&contents[0], 512); 643888651fcSAlan Somers send_ack(1); 644888651fcSAlan Somers recv_data(2, (const char *)&contents[128], 256); 645888651fcSAlan Somers send_ack(2); 646888651fcSAlan Somers } 647888651fcSAlan Somers 648888651fcSAlan Somers /* 649fdf929ffSJohn Baldwin * Read a medium file with a window size of 2. 650fdf929ffSJohn Baldwin */ 651fdf929ffSJohn Baldwin TFTPD_TC_DEFINE(rrq_medium_window,) 652fdf929ffSJohn Baldwin { 653fdf929ffSJohn Baldwin int fd; 654fdf929ffSJohn Baldwin size_t i; 655fdf929ffSJohn Baldwin uint32_t contents[192]; 656fdf929ffSJohn Baldwin char options[] = OPTION_STR("windowsize", "2"); 657fdf929ffSJohn Baldwin 658fdf929ffSJohn Baldwin for (i = 0; i < nitems(contents); i++) 659fdf929ffSJohn Baldwin contents[i] = i; 660fdf929ffSJohn Baldwin 661fdf929ffSJohn Baldwin fd = open("medium.txt", O_RDWR | O_CREAT, 0644); 662fdf929ffSJohn Baldwin ATF_REQUIRE(fd >= 0); 663fdf929ffSJohn Baldwin write_all(fd, contents, sizeof(contents)); 664fdf929ffSJohn Baldwin close(fd); 665fdf929ffSJohn Baldwin 666fdf929ffSJohn Baldwin SEND_RRQ_OPT("medium.txt", "octet", OPTION_STR("windowsize", "2")); 667fdf929ffSJohn Baldwin recv_oack(options, sizeof(options) - 1); 668fdf929ffSJohn Baldwin send_ack(0); 669fdf929ffSJohn Baldwin recv_data(1, (const char *)&contents[0], 512); 670fdf929ffSJohn Baldwin recv_data(2, (const char *)&contents[128], 256); 671fdf929ffSJohn Baldwin send_ack(2); 672fdf929ffSJohn Baldwin } 673fdf929ffSJohn Baldwin 674fdf929ffSJohn Baldwin /* 675888651fcSAlan Somers * Read a file in netascii format 676888651fcSAlan Somers */ 677888651fcSAlan Somers TFTPD_TC_DEFINE(rrq_netascii,) 678888651fcSAlan Somers { 679888651fcSAlan Somers int fd; 680888651fcSAlan Somers char contents[] = "foo\nbar\rbaz\n"; 681888651fcSAlan Somers /* 682888651fcSAlan Somers * Weirdly, RFC-764 says that CR must be followed by NUL if a line feed 683888651fcSAlan Somers * is not intended 684888651fcSAlan Somers */ 685888651fcSAlan Somers char expected[] = "foo\r\nbar\r\0baz\r\n"; 686888651fcSAlan Somers 687888651fcSAlan Somers fd = open("unix.txt", O_RDWR | O_CREAT, 0644); 688888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 689888651fcSAlan Somers write_all(fd, contents, strlen(contents) + 1); 690888651fcSAlan Somers close(fd); 691888651fcSAlan Somers 692888651fcSAlan Somers SEND_RRQ("unix.txt", "netascii"); 693888651fcSAlan Somers recv_data(1, expected, sizeof(expected)); 694888651fcSAlan Somers send_ack(1); 695888651fcSAlan Somers } 696888651fcSAlan Somers 697888651fcSAlan Somers /* 698888651fcSAlan Somers * Read a file that doesn't exist 699888651fcSAlan Somers */ 700888651fcSAlan Somers TFTPD_TC_DEFINE(rrq_nonexistent,) 701888651fcSAlan Somers { 702888651fcSAlan Somers SEND_RRQ("nonexistent.txt", "octet"); 703888651fcSAlan Somers RECV_ERROR(1, "File not found"); 704888651fcSAlan Somers } 705888651fcSAlan Somers 706888651fcSAlan Somers /* 707888651fcSAlan Somers * Attempt to read a file whose name exceeds PATH_MAX 708888651fcSAlan Somers */ 709888651fcSAlan Somers TFTPD_TC_DEFINE(rrq_path_max,) 710888651fcSAlan Somers { 711888651fcSAlan Somers #define AReallyBigFileName \ 712888651fcSAlan Somers "AReallyBigFileNameXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 713888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 714888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 715888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 716888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 717888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 718888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 719888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 720888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 721888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 722888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 723888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 724888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 725888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 726888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 727888651fcSAlan Somers "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\ 728888651fcSAlan Somers ".txt" 729888651fcSAlan Somers ATF_REQUIRE_MSG(strlen(AReallyBigFileName) > PATH_MAX, 730888651fcSAlan Somers "Somebody increased PATH_MAX. Update the test"); 731888651fcSAlan Somers SEND_RRQ(AReallyBigFileName, "octet"); 732888651fcSAlan Somers RECV_ERROR(4, "Illegal TFTP operation"); 733888651fcSAlan Somers } 734888651fcSAlan Somers 735888651fcSAlan Somers /* 736888651fcSAlan Somers * Read a small file of less than one block 737888651fcSAlan Somers */ 738888651fcSAlan Somers TFTPD_TC_DEFINE(rrq_small,) 739888651fcSAlan Somers { 740888651fcSAlan Somers int fd; 741888651fcSAlan Somers char contents[] = "small"; 742888651fcSAlan Somers 743888651fcSAlan Somers fd = open("small.txt", O_RDWR | O_CREAT, 0644); 744888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 745888651fcSAlan Somers write_all(fd, contents, strlen(contents) + 1); 746888651fcSAlan Somers close(fd); 747888651fcSAlan Somers 748888651fcSAlan Somers SEND_RRQ("small.txt", "octet"); 749888651fcSAlan Somers recv_data(1, contents, strlen(contents) + 1); 750888651fcSAlan Somers send_ack(1); 751888651fcSAlan Somers } 752888651fcSAlan Somers 753888651fcSAlan Somers /* 754fdf929ffSJohn Baldwin * Read a file following the example in RFC 7440. 755fdf929ffSJohn Baldwin */ 756fdf929ffSJohn Baldwin TFTPD_TC_DEFINE(rrq_window_rfc7440,) 757fdf929ffSJohn Baldwin { 758fdf929ffSJohn Baldwin int fd; 759fdf929ffSJohn Baldwin size_t i; 760fdf929ffSJohn Baldwin char options[] = OPTION_STR("windowsize", "4"); 761fdf929ffSJohn Baldwin alignas(uint32_t) char contents[13 * 512 - 4]; 762fdf929ffSJohn Baldwin uint32_t *u32p; 763fdf929ffSJohn Baldwin 764fdf929ffSJohn Baldwin u32p = (uint32_t *)contents; 765fdf929ffSJohn Baldwin for (i = 0; i < sizeof(contents) / sizeof(uint32_t); i++) 766fdf929ffSJohn Baldwin u32p[i] = i; 767fdf929ffSJohn Baldwin 768fdf929ffSJohn Baldwin fd = open("rfc7440.txt", O_RDWR | O_CREAT, 0644); 769fdf929ffSJohn Baldwin ATF_REQUIRE(fd >= 0); 770fdf929ffSJohn Baldwin write_all(fd, contents, sizeof(contents)); 771fdf929ffSJohn Baldwin close(fd); 772fdf929ffSJohn Baldwin 773fdf929ffSJohn Baldwin SEND_RRQ_OPT("rfc7440.txt", "octet", OPTION_STR("windowsize", "4")); 774fdf929ffSJohn Baldwin recv_oack(options, sizeof(options) - 1); 775fdf929ffSJohn Baldwin send_ack(0); 776fdf929ffSJohn Baldwin recv_data(1, &contents[0 * 512], 512); 777fdf929ffSJohn Baldwin recv_data(2, &contents[1 * 512], 512); 778fdf929ffSJohn Baldwin recv_data(3, &contents[2 * 512], 512); 779fdf929ffSJohn Baldwin recv_data(4, &contents[3 * 512], 512); 780fdf929ffSJohn Baldwin send_ack(4); 781fdf929ffSJohn Baldwin recv_data(5, &contents[4 * 512], 512); 782fdf929ffSJohn Baldwin recv_data(6, &contents[5 * 512], 512); 783fdf929ffSJohn Baldwin recv_data(7, &contents[6 * 512], 512); 784fdf929ffSJohn Baldwin recv_data(8, &contents[7 * 512], 512); 785fdf929ffSJohn Baldwin 786fdf929ffSJohn Baldwin /* ACK 5 as if 6-8 were dropped. */ 787fdf929ffSJohn Baldwin send_ack(5); 788fdf929ffSJohn Baldwin recv_data(6, &contents[5 * 512], 512); 789fdf929ffSJohn Baldwin recv_data(7, &contents[6 * 512], 512); 790fdf929ffSJohn Baldwin recv_data(8, &contents[7 * 512], 512); 791fdf929ffSJohn Baldwin recv_data(9, &contents[8 * 512], 512); 792fdf929ffSJohn Baldwin send_ack(9); 793fdf929ffSJohn Baldwin recv_data(10, &contents[9 * 512], 512); 794fdf929ffSJohn Baldwin recv_data(11, &contents[10 * 512], 512); 795fdf929ffSJohn Baldwin recv_data(12, &contents[11 * 512], 512); 796fdf929ffSJohn Baldwin recv_data(13, &contents[12 * 512], 508); 797fdf929ffSJohn Baldwin 798fdf929ffSJohn Baldwin /* Drop ACK and after timeout receive 10-13. */ 799fdf929ffSJohn Baldwin recv_data(10, &contents[9 * 512], 512); 800fdf929ffSJohn Baldwin recv_data(11, &contents[10 * 512], 512); 801fdf929ffSJohn Baldwin recv_data(12, &contents[11 * 512], 512); 802fdf929ffSJohn Baldwin recv_data(13, &contents[12 * 512], 508); 803fdf929ffSJohn Baldwin send_ack(13); 804fdf929ffSJohn Baldwin } 805fdf929ffSJohn Baldwin 806fdf929ffSJohn Baldwin /* 807888651fcSAlan Somers * Try to transfer a file with an unknown mode. 808888651fcSAlan Somers */ 809888651fcSAlan Somers TFTPD_TC_DEFINE(unknown_modes,) 810888651fcSAlan Somers { 811888651fcSAlan Somers SEND_RRQ("foo.txt", "ascii"); /* Misspelling of "ascii" */ 812888651fcSAlan Somers RECV_ERROR(4, "Illegal TFTP operation"); 8137ab7ecfcSDag-Erling Smørgrav s = setup(&addr, __COUNTER__); 814888651fcSAlan Somers SEND_RRQ("foo.txt", "binary"); /* Obsolete. Use "octet" instead */ 815888651fcSAlan Somers RECV_ERROR(4, "Illegal TFTP operation"); 8167ab7ecfcSDag-Erling Smørgrav s = setup(&addr, __COUNTER__); 817888651fcSAlan Somers SEND_RRQ("foo.txt", "en_US.UTF-8"); 818888651fcSAlan Somers RECV_ERROR(4, "Illegal TFTP operation"); 8197ab7ecfcSDag-Erling Smørgrav s = setup(&addr, __COUNTER__); 820888651fcSAlan Somers SEND_RRQ("foo.txt", "mail"); /* Obsolete in RFC-1350 */ 821888651fcSAlan Somers RECV_ERROR(4, "Illegal TFTP operation"); 822888651fcSAlan Somers } 823888651fcSAlan Somers 824888651fcSAlan Somers /* 825888651fcSAlan Somers * Send an unknown opcode. tftpd should respond with the appropriate error 826888651fcSAlan Somers */ 827888651fcSAlan Somers TFTPD_TC_DEFINE(unknown_opcode,) 828888651fcSAlan Somers { 829888651fcSAlan Somers /* Looks like an RRQ or WRQ request, but with a bad opcode */ 830888651fcSAlan Somers SEND_STR("\0\007foo.txt\0octet\0"); 831888651fcSAlan Somers RECV_ERROR(4, "Illegal TFTP operation"); 832888651fcSAlan Somers } 833888651fcSAlan Somers 834888651fcSAlan Somers /* 835888651fcSAlan Somers * Invoke tftpd with "-w" and write to a nonexistent file. 836888651fcSAlan Somers */ 837888651fcSAlan Somers TFTPD_TC_DEFINE(w_flag,, w_flag = 1;) 838888651fcSAlan Somers { 839888651fcSAlan Somers int fd; 840888651fcSAlan Somers ssize_t r; 841888651fcSAlan Somers char contents[] = "small"; 842888651fcSAlan Somers char buffer[1024]; 843888651fcSAlan Somers size_t contents_len; 844888651fcSAlan Somers 845888651fcSAlan Somers contents_len = strlen(contents) + 1; 846888651fcSAlan Somers SEND_WRQ("small.txt", "octet"); 847888651fcSAlan Somers recv_ack(0); 848888651fcSAlan Somers send_data(1, contents, contents_len); 849888651fcSAlan Somers recv_ack(1); 850888651fcSAlan Somers 851888651fcSAlan Somers fd = open("small.txt", O_RDONLY); 852ad5c8bd6SAlan Somers ATF_REQUIRE(fd >= 0); 853888651fcSAlan Somers r = read(fd, buffer, sizeof(buffer)); 8541ed44fccSDag-Erling Smørgrav ATF_REQUIRE(r > 0); 855888651fcSAlan Somers close(fd); 8561ed44fccSDag-Erling Smørgrav require_bufeq(contents, contents_len, buffer, (size_t)r); 857888651fcSAlan Somers } 858888651fcSAlan Somers 859888651fcSAlan Somers /* 860888651fcSAlan Somers * Write a medium file, and simulate a dropped ACK packet 861888651fcSAlan Somers */ 862888651fcSAlan Somers TFTPD_TC_DEFINE(wrq_dropped_ack,) 863888651fcSAlan Somers { 864888651fcSAlan Somers int fd; 865888651fcSAlan Somers size_t i; 866888651fcSAlan Somers ssize_t r; 867888651fcSAlan Somers uint32_t contents[192]; 868888651fcSAlan Somers char buffer[1024]; 869888651fcSAlan Somers 870888651fcSAlan Somers for (i = 0; i < nitems(contents); i++) 871888651fcSAlan Somers contents[i] = i; 872888651fcSAlan Somers 873d89aca76SAlan Somers fd = open("medium.txt", O_RDWR | O_CREAT, 0666); 874888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 875888651fcSAlan Somers close(fd); 876888651fcSAlan Somers 877888651fcSAlan Somers SEND_WRQ("medium.txt", "octet"); 878888651fcSAlan Somers recv_ack(0); 879888651fcSAlan Somers send_data(1, (const char *)&contents[0], 512); 880888651fcSAlan Somers /* 881888651fcSAlan Somers * Servers "sends" an ACK packet, but network drops it. 882888651fcSAlan Somers * Eventually, server should resend the last ACK 883888651fcSAlan Somers */ 884888651fcSAlan Somers (void) recvfrom(s, buffer, sizeof(buffer), 0, NULL, NULL); 885888651fcSAlan Somers recv_ack(1); 886888651fcSAlan Somers send_data(2, (const char *)&contents[128], 256); 887888651fcSAlan Somers recv_ack(2); 888888651fcSAlan Somers 889888651fcSAlan Somers fd = open("medium.txt", O_RDONLY); 890ad5c8bd6SAlan Somers ATF_REQUIRE(fd >= 0); 891888651fcSAlan Somers r = read(fd, buffer, sizeof(buffer)); 8921ed44fccSDag-Erling Smørgrav ATF_REQUIRE(r > 0); 893888651fcSAlan Somers close(fd); 8941ed44fccSDag-Erling Smørgrav require_bufeq((const char *)contents, 768, buffer, (size_t)r); 895888651fcSAlan Somers } 896888651fcSAlan Somers 897888651fcSAlan Somers /* 898888651fcSAlan Somers * Write a small file, and simulate a dropped DATA packet 899888651fcSAlan Somers */ 900888651fcSAlan Somers TFTPD_TC_DEFINE(wrq_dropped_data,) 901888651fcSAlan Somers { 902888651fcSAlan Somers int fd; 903888651fcSAlan Somers ssize_t r; 904888651fcSAlan Somers char contents[] = "small"; 905888651fcSAlan Somers size_t contents_len; 906888651fcSAlan Somers char buffer[1024]; 907888651fcSAlan Somers 908d89aca76SAlan Somers fd = open("small.txt", O_RDWR | O_CREAT, 0666); 909888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 910888651fcSAlan Somers close(fd); 911888651fcSAlan Somers contents_len = strlen(contents) + 1; 912888651fcSAlan Somers 913888651fcSAlan Somers SEND_WRQ("small.txt", "octet"); 914888651fcSAlan Somers recv_ack(0); 915888651fcSAlan Somers /* 916888651fcSAlan Somers * Client "sends" a DATA packet, but network drops it. 917888651fcSAlan Somers * Eventually, server should resend the last ACK 918888651fcSAlan Somers */ 919888651fcSAlan Somers recv_ack(0); 920888651fcSAlan Somers send_data(1, contents, contents_len); 921888651fcSAlan Somers recv_ack(1); 922888651fcSAlan Somers 923888651fcSAlan Somers fd = open("small.txt", O_RDONLY); 924ad5c8bd6SAlan Somers ATF_REQUIRE(fd >= 0); 925888651fcSAlan Somers r = read(fd, buffer, sizeof(buffer)); 9261ed44fccSDag-Erling Smørgrav ATF_REQUIRE(r > 0); 927888651fcSAlan Somers close(fd); 9281ed44fccSDag-Erling Smørgrav require_bufeq(contents, contents_len, buffer, (size_t)r); 929888651fcSAlan Somers } 930888651fcSAlan Somers 931888651fcSAlan Somers /* 932888651fcSAlan Somers * Write a medium file, and simulate a duplicated DATA packet 933888651fcSAlan Somers */ 934888651fcSAlan Somers TFTPD_TC_DEFINE(wrq_duped_data,) 935888651fcSAlan Somers { 936888651fcSAlan Somers int fd; 937888651fcSAlan Somers size_t i; 938888651fcSAlan Somers ssize_t r; 939888651fcSAlan Somers uint32_t contents[192]; 940888651fcSAlan Somers char buffer[1024]; 941888651fcSAlan Somers 942888651fcSAlan Somers for (i = 0; i < nitems(contents); i++) 943888651fcSAlan Somers contents[i] = i; 944888651fcSAlan Somers 945d89aca76SAlan Somers fd = open("medium.txt", O_RDWR | O_CREAT, 0666); 946888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 947888651fcSAlan Somers close(fd); 948888651fcSAlan Somers 949888651fcSAlan Somers SEND_WRQ("medium.txt", "octet"); 950888651fcSAlan Somers recv_ack(0); 951888651fcSAlan Somers send_data(1, (const char *)&contents[0], 512); 952888651fcSAlan Somers send_data(1, (const char *)&contents[0], 512); 953888651fcSAlan Somers recv_ack(1); 954888651fcSAlan Somers recv_ack(1); 955888651fcSAlan Somers send_data(2, (const char *)&contents[128], 256); 956888651fcSAlan Somers recv_ack(2); 957888651fcSAlan Somers 958888651fcSAlan Somers fd = open("medium.txt", O_RDONLY); 959ad5c8bd6SAlan Somers ATF_REQUIRE(fd >= 0); 960888651fcSAlan Somers r = read(fd, buffer, sizeof(buffer)); 9611ed44fccSDag-Erling Smørgrav ATF_REQUIRE(r > 0); 962888651fcSAlan Somers close(fd); 9631ed44fccSDag-Erling Smørgrav require_bufeq((const char *)contents, 768, buffer, (size_t)r); 964888651fcSAlan Somers } 965888651fcSAlan Somers 966888651fcSAlan Somers /* 967888651fcSAlan Somers * Attempt to write a file without write permissions 968888651fcSAlan Somers */ 969888651fcSAlan Somers TFTPD_TC_DEFINE(wrq_eaccess,) 970888651fcSAlan Somers { 971888651fcSAlan Somers int fd; 972888651fcSAlan Somers 973888651fcSAlan Somers fd = open("empty.txt", O_CREAT | O_RDONLY, 0440); 974888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 975888651fcSAlan Somers close(fd); 976888651fcSAlan Somers 977888651fcSAlan Somers SEND_WRQ("empty.txt", "octet"); 978888651fcSAlan Somers RECV_ERROR(2, "Access violation"); 979888651fcSAlan Somers } 980888651fcSAlan Somers 981888651fcSAlan Somers /* 982888651fcSAlan Somers * Attempt to write a file without world write permissions, but with world 983888651fcSAlan Somers * read permissions 984888651fcSAlan Somers */ 985888651fcSAlan Somers TFTPD_TC_DEFINE(wrq_eaccess_world_readable,) 986888651fcSAlan Somers { 987888651fcSAlan Somers int fd; 988888651fcSAlan Somers 989888651fcSAlan Somers fd = open("empty.txt", O_CREAT | O_RDONLY, 0444); 990888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 991888651fcSAlan Somers close(fd); 992888651fcSAlan Somers 993888651fcSAlan Somers SEND_WRQ("empty.txt", "octet"); 994888651fcSAlan Somers RECV_ERROR(2, "Access violation"); 995888651fcSAlan Somers } 996888651fcSAlan Somers 997888651fcSAlan Somers 998888651fcSAlan Somers /* 999888651fcSAlan Somers * Write a medium file of more than one block 1000888651fcSAlan Somers */ 1001888651fcSAlan Somers TFTPD_TC_DEFINE(wrq_medium,) 1002888651fcSAlan Somers { 1003888651fcSAlan Somers int fd; 1004888651fcSAlan Somers size_t i; 1005888651fcSAlan Somers ssize_t r; 1006888651fcSAlan Somers uint32_t contents[192]; 1007888651fcSAlan Somers char buffer[1024]; 1008888651fcSAlan Somers 1009888651fcSAlan Somers for (i = 0; i < nitems(contents); i++) 1010888651fcSAlan Somers contents[i] = i; 1011888651fcSAlan Somers 1012888651fcSAlan Somers fd = open("medium.txt", O_RDWR | O_CREAT, 0666); 1013888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 1014888651fcSAlan Somers close(fd); 1015888651fcSAlan Somers 1016888651fcSAlan Somers SEND_WRQ("medium.txt", "octet"); 1017888651fcSAlan Somers recv_ack(0); 1018888651fcSAlan Somers send_data(1, (const char *)&contents[0], 512); 1019888651fcSAlan Somers recv_ack(1); 1020888651fcSAlan Somers send_data(2, (const char *)&contents[128], 256); 1021888651fcSAlan Somers recv_ack(2); 1022888651fcSAlan Somers 1023888651fcSAlan Somers fd = open("medium.txt", O_RDONLY); 1024ad5c8bd6SAlan Somers ATF_REQUIRE(fd >= 0); 1025888651fcSAlan Somers r = read(fd, buffer, sizeof(buffer)); 10261ed44fccSDag-Erling Smørgrav ATF_REQUIRE(r > 0); 1027888651fcSAlan Somers close(fd); 10281ed44fccSDag-Erling Smørgrav require_bufeq((const char *)contents, 768, buffer, (size_t)r); 1029888651fcSAlan Somers } 1030888651fcSAlan Somers 1031888651fcSAlan Somers /* 1032fdf929ffSJohn Baldwin * Write a medium file with a window size of 2. 1033fdf929ffSJohn Baldwin */ 1034fdf929ffSJohn Baldwin TFTPD_TC_DEFINE(wrq_medium_window,) 1035fdf929ffSJohn Baldwin { 1036fdf929ffSJohn Baldwin int fd; 1037fdf929ffSJohn Baldwin size_t i; 1038fdf929ffSJohn Baldwin ssize_t r; 1039fdf929ffSJohn Baldwin uint32_t contents[192]; 1040fdf929ffSJohn Baldwin char buffer[1024]; 1041fdf929ffSJohn Baldwin char options[] = OPTION_STR("windowsize", "2"); 1042fdf929ffSJohn Baldwin 1043fdf929ffSJohn Baldwin for (i = 0; i < nitems(contents); i++) 1044fdf929ffSJohn Baldwin contents[i] = i; 1045fdf929ffSJohn Baldwin 1046fdf929ffSJohn Baldwin fd = open("medium.txt", O_RDWR | O_CREAT, 0666); 1047fdf929ffSJohn Baldwin ATF_REQUIRE(fd >= 0); 1048fdf929ffSJohn Baldwin close(fd); 1049fdf929ffSJohn Baldwin 1050fdf929ffSJohn Baldwin SEND_WRQ_OPT("medium.txt", "octet", OPTION_STR("windowsize", "2")); 1051fdf929ffSJohn Baldwin recv_oack(options, sizeof(options) - 1); 1052fdf929ffSJohn Baldwin send_data(1, (const char *)&contents[0], 512); 1053fdf929ffSJohn Baldwin send_data(2, (const char *)&contents[128], 256); 1054fdf929ffSJohn Baldwin recv_ack(2); 1055fdf929ffSJohn Baldwin 1056fdf929ffSJohn Baldwin fd = open("medium.txt", O_RDONLY); 1057fdf929ffSJohn Baldwin ATF_REQUIRE(fd >= 0); 1058fdf929ffSJohn Baldwin r = read(fd, buffer, sizeof(buffer)); 10591ed44fccSDag-Erling Smørgrav ATF_REQUIRE(r > 0); 1060fdf929ffSJohn Baldwin close(fd); 10611ed44fccSDag-Erling Smørgrav require_bufeq((const char *)contents, 768, buffer, (size_t)r); 1062fdf929ffSJohn Baldwin } 1063fdf929ffSJohn Baldwin 1064fdf929ffSJohn Baldwin /* 1065888651fcSAlan Somers * Write a file in netascii format 1066888651fcSAlan Somers */ 1067888651fcSAlan Somers TFTPD_TC_DEFINE(wrq_netascii,) 1068888651fcSAlan Somers { 1069888651fcSAlan Somers int fd; 1070888651fcSAlan Somers ssize_t r; 1071888651fcSAlan Somers /* 1072888651fcSAlan Somers * Weirdly, RFC-764 says that CR must be followed by NUL if a line feed 1073888651fcSAlan Somers * is not intended 1074888651fcSAlan Somers */ 1075888651fcSAlan Somers char contents[] = "foo\r\nbar\r\0baz\r\n"; 1076888651fcSAlan Somers char expected[] = "foo\nbar\rbaz\n"; 1077888651fcSAlan Somers size_t contents_len; 1078888651fcSAlan Somers char buffer[1024]; 1079888651fcSAlan Somers 1080888651fcSAlan Somers fd = open("unix.txt", O_RDWR | O_CREAT, 0666); 1081888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 1082888651fcSAlan Somers close(fd); 1083d3953c1fSAlan Somers contents_len = sizeof(contents); 1084888651fcSAlan Somers 1085888651fcSAlan Somers SEND_WRQ("unix.txt", "netascii"); 1086888651fcSAlan Somers recv_ack(0); 1087888651fcSAlan Somers send_data(1, contents, contents_len); 1088888651fcSAlan Somers recv_ack(1); 1089888651fcSAlan Somers 1090888651fcSAlan Somers fd = open("unix.txt", O_RDONLY); 1091ad5c8bd6SAlan Somers ATF_REQUIRE(fd >= 0); 1092888651fcSAlan Somers r = read(fd, buffer, sizeof(buffer)); 10931ed44fccSDag-Erling Smørgrav ATF_REQUIRE(r > 0); 1094888651fcSAlan Somers close(fd); 10951ed44fccSDag-Erling Smørgrav require_bufeq(expected, sizeof(expected), buffer, (size_t)r); 1096888651fcSAlan Somers } 1097888651fcSAlan Somers 1098888651fcSAlan Somers /* 1099888651fcSAlan Somers * Attempt to write to a nonexistent file. With the default options, this 1100888651fcSAlan Somers * isn't allowed. 1101888651fcSAlan Somers */ 1102888651fcSAlan Somers TFTPD_TC_DEFINE(wrq_nonexistent,) 1103888651fcSAlan Somers { 1104888651fcSAlan Somers SEND_WRQ("nonexistent.txt", "octet"); 1105888651fcSAlan Somers RECV_ERROR(1, "File not found"); 1106888651fcSAlan Somers } 1107888651fcSAlan Somers 1108888651fcSAlan Somers /* 1109888651fcSAlan Somers * Write a small file of less than one block 1110888651fcSAlan Somers */ 1111888651fcSAlan Somers TFTPD_TC_DEFINE(wrq_small,) 1112888651fcSAlan Somers { 1113888651fcSAlan Somers int fd; 1114888651fcSAlan Somers ssize_t r; 1115888651fcSAlan Somers char contents[] = "small"; 1116888651fcSAlan Somers size_t contents_len; 1117888651fcSAlan Somers char buffer[1024]; 1118888651fcSAlan Somers 1119888651fcSAlan Somers fd = open("small.txt", O_RDWR | O_CREAT, 0666); 1120888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 1121888651fcSAlan Somers close(fd); 1122888651fcSAlan Somers contents_len = strlen(contents) + 1; 1123888651fcSAlan Somers 1124888651fcSAlan Somers SEND_WRQ("small.txt", "octet"); 1125888651fcSAlan Somers recv_ack(0); 1126888651fcSAlan Somers send_data(1, contents, contents_len); 1127888651fcSAlan Somers recv_ack(1); 1128888651fcSAlan Somers 1129888651fcSAlan Somers fd = open("small.txt", O_RDONLY); 1130ad5c8bd6SAlan Somers ATF_REQUIRE(fd >= 0); 1131888651fcSAlan Somers r = read(fd, buffer, sizeof(buffer)); 11321ed44fccSDag-Erling Smørgrav ATF_REQUIRE(r > 0); 1133888651fcSAlan Somers close(fd); 11341ed44fccSDag-Erling Smørgrav require_bufeq(contents, contents_len, buffer, (size_t)r); 1135888651fcSAlan Somers } 1136888651fcSAlan Somers 1137888651fcSAlan Somers /* 1138888651fcSAlan Somers * Write an empty file over a non-empty one 1139888651fcSAlan Somers */ 1140888651fcSAlan Somers TFTPD_TC_DEFINE(wrq_truncate,) 1141888651fcSAlan Somers { 1142888651fcSAlan Somers int fd; 1143888651fcSAlan Somers char contents[] = "small"; 1144888651fcSAlan Somers struct stat sb; 1145888651fcSAlan Somers 1146888651fcSAlan Somers fd = open("small.txt", O_RDWR | O_CREAT, 0666); 1147888651fcSAlan Somers ATF_REQUIRE(fd >= 0); 1148888651fcSAlan Somers write_all(fd, contents, strlen(contents) + 1); 1149888651fcSAlan Somers close(fd); 1150888651fcSAlan Somers 1151888651fcSAlan Somers SEND_WRQ("small.txt", "octet"); 1152888651fcSAlan Somers recv_ack(0); 1153888651fcSAlan Somers send_data(1, NULL, 0); 1154888651fcSAlan Somers recv_ack(1); 1155888651fcSAlan Somers 11567ab7ecfcSDag-Erling Smørgrav ATF_REQUIRE_EQ(0, stat("small.txt", &sb)); 11577ab7ecfcSDag-Erling Smørgrav ATF_REQUIRE_EQ(0, sb.st_size); 1158888651fcSAlan Somers } 1159888651fcSAlan Somers 1160fdf929ffSJohn Baldwin /* 1161fdf929ffSJohn Baldwin * Write a file following the example in RFC 7440. 1162fdf929ffSJohn Baldwin */ 1163fdf929ffSJohn Baldwin TFTPD_TC_DEFINE(wrq_window_rfc7440,) 1164fdf929ffSJohn Baldwin { 1165fdf929ffSJohn Baldwin int fd; 1166fdf929ffSJohn Baldwin size_t i; 1167fdf929ffSJohn Baldwin ssize_t r; 1168fdf929ffSJohn Baldwin char options[] = OPTION_STR("windowsize", "4"); 1169fdf929ffSJohn Baldwin alignas(uint32_t) char contents[13 * 512 - 4]; 1170fdf929ffSJohn Baldwin char buffer[sizeof(contents)]; 1171fdf929ffSJohn Baldwin uint32_t *u32p; 1172fdf929ffSJohn Baldwin 1173fdf929ffSJohn Baldwin u32p = (uint32_t *)contents; 1174fdf929ffSJohn Baldwin for (i = 0; i < sizeof(contents) / sizeof(uint32_t); i++) 1175fdf929ffSJohn Baldwin u32p[i] = i; 1176fdf929ffSJohn Baldwin 1177fdf929ffSJohn Baldwin fd = open("rfc7440.txt", O_RDWR | O_CREAT, 0666); 1178fdf929ffSJohn Baldwin ATF_REQUIRE(fd >= 0); 1179fdf929ffSJohn Baldwin close(fd); 1180fdf929ffSJohn Baldwin 1181fdf929ffSJohn Baldwin SEND_WRQ_OPT("rfc7440.txt", "octet", OPTION_STR("windowsize", "4")); 1182fdf929ffSJohn Baldwin recv_oack(options, sizeof(options) - 1); 1183fdf929ffSJohn Baldwin send_data(1, &contents[0 * 512], 512); 1184fdf929ffSJohn Baldwin send_data(2, &contents[1 * 512], 512); 1185fdf929ffSJohn Baldwin send_data(3, &contents[2 * 512], 512); 1186fdf929ffSJohn Baldwin send_data(4, &contents[3 * 512], 512); 1187fdf929ffSJohn Baldwin recv_ack(4); 1188fdf929ffSJohn Baldwin send_data(5, &contents[4 * 512], 512); 1189fdf929ffSJohn Baldwin 1190fdf929ffSJohn Baldwin /* Drop 6-8. */ 1191fdf929ffSJohn Baldwin recv_ack(5); 1192fdf929ffSJohn Baldwin send_data(6, &contents[5 * 512], 512); 1193fdf929ffSJohn Baldwin send_data(7, &contents[6 * 512], 512); 1194fdf929ffSJohn Baldwin send_data(8, &contents[7 * 512], 512); 1195fdf929ffSJohn Baldwin send_data(9, &contents[8 * 512], 512); 1196fdf929ffSJohn Baldwin recv_ack(9); 1197fdf929ffSJohn Baldwin 1198fdf929ffSJohn Baldwin /* Drop 11. */ 1199fdf929ffSJohn Baldwin send_data(10, &contents[9 * 512], 512); 1200fdf929ffSJohn Baldwin send_data(12, &contents[11 * 512], 512); 1201fdf929ffSJohn Baldwin 1202fdf929ffSJohn Baldwin /* 1203fdf929ffSJohn Baldwin * We can't send 13 here as tftpd has probably already seen 12 1204fdf929ffSJohn Baldwin * and sent the ACK of 10 if running locally. While it would 1205fdf929ffSJohn Baldwin * recover by sending another ACK of 10, our state machine 1206fdf929ffSJohn Baldwin * would be out of sync. 1207fdf929ffSJohn Baldwin */ 1208fdf929ffSJohn Baldwin 1209fdf929ffSJohn Baldwin /* Ignore ACK for 10 and resend 10-13. */ 1210fdf929ffSJohn Baldwin recv_ack(10); 1211fdf929ffSJohn Baldwin send_data(10, &contents[9 * 512], 512); 1212fdf929ffSJohn Baldwin send_data(11, &contents[10 * 512], 512); 1213fdf929ffSJohn Baldwin send_data(12, &contents[11 * 512], 512); 1214fdf929ffSJohn Baldwin send_data(13, &contents[12 * 512], 508); 1215fdf929ffSJohn Baldwin recv_ack(13); 1216fdf929ffSJohn Baldwin 1217fdf929ffSJohn Baldwin fd = open("rfc7440.txt", O_RDONLY); 1218fdf929ffSJohn Baldwin ATF_REQUIRE(fd >= 0); 1219fdf929ffSJohn Baldwin r = read(fd, buffer, sizeof(buffer)); 12201ed44fccSDag-Erling Smørgrav ATF_REQUIRE(r > 0); 1221fdf929ffSJohn Baldwin close(fd); 12221ed44fccSDag-Erling Smørgrav require_bufeq(contents, sizeof(contents), buffer, (size_t)r); 1223fdf929ffSJohn Baldwin } 1224fdf929ffSJohn Baldwin 12259f231af3SDag-Erling Smørgrav /* 12269f231af3SDag-Erling Smørgrav * Send less than four bytes 12279f231af3SDag-Erling Smørgrav */ 12289f231af3SDag-Erling Smørgrav TFTPD_TC_DEFINE(short_packet1, /* no head */, exitcode = 1) 12299f231af3SDag-Erling Smørgrav { 12309f231af3SDag-Erling Smørgrav SEND_STR("\1"); 12319f231af3SDag-Erling Smørgrav } 12329f231af3SDag-Erling Smørgrav TFTPD_TC_DEFINE(short_packet2, /* no head */, exitcode = 1) 12339f231af3SDag-Erling Smørgrav { 12349f231af3SDag-Erling Smørgrav SEND_STR("\1\2"); 12359f231af3SDag-Erling Smørgrav } 12369f231af3SDag-Erling Smørgrav TFTPD_TC_DEFINE(short_packet3, /* no head */, exitcode = 1) 12379f231af3SDag-Erling Smørgrav { 12389f231af3SDag-Erling Smørgrav SEND_STR("\1\2\3"); 12399f231af3SDag-Erling Smørgrav } 12409f231af3SDag-Erling Smørgrav 1241888651fcSAlan Somers 1242888651fcSAlan Somers /* 1243888651fcSAlan Somers * Main 1244888651fcSAlan Somers */ 1245888651fcSAlan Somers 1246888651fcSAlan Somers ATF_TP_ADD_TCS(tp) 1247888651fcSAlan Somers { 1248888651fcSAlan Somers TFTPD_TC_ADD(tp, abspath); 1249888651fcSAlan Somers TFTPD_TC_ADD(tp, dotdot); 1250888651fcSAlan Somers TFTPD_TC_ADD(tp, s_flag); 1251888651fcSAlan Somers TFTPD_TC_ADD(tp, rrq_dropped_ack); 1252888651fcSAlan Somers TFTPD_TC_ADD(tp, rrq_dropped_data); 1253888651fcSAlan Somers TFTPD_TC_ADD(tp, rrq_duped_ack); 1254888651fcSAlan Somers TFTPD_TC_ADD(tp, rrq_eaccess); 1255888651fcSAlan Somers TFTPD_TC_ADD(tp, rrq_empty); 1256888651fcSAlan Somers TFTPD_TC_ADD(tp, rrq_medium); 1257fdf929ffSJohn Baldwin TFTPD_TC_ADD(tp, rrq_medium_window); 1258888651fcSAlan Somers TFTPD_TC_ADD(tp, rrq_netascii); 1259888651fcSAlan Somers TFTPD_TC_ADD(tp, rrq_nonexistent); 1260888651fcSAlan Somers TFTPD_TC_ADD(tp, rrq_path_max); 1261888651fcSAlan Somers TFTPD_TC_ADD(tp, rrq_small); 1262fdf929ffSJohn Baldwin TFTPD_TC_ADD(tp, rrq_window_rfc7440); 1263888651fcSAlan Somers TFTPD_TC_ADD(tp, unknown_modes); 1264888651fcSAlan Somers TFTPD_TC_ADD(tp, unknown_opcode); 1265888651fcSAlan Somers TFTPD_TC_ADD(tp, w_flag); 1266888651fcSAlan Somers TFTPD_TC_ADD(tp, wrq_dropped_ack); 1267888651fcSAlan Somers TFTPD_TC_ADD(tp, wrq_dropped_data); 1268888651fcSAlan Somers TFTPD_TC_ADD(tp, wrq_duped_data); 1269888651fcSAlan Somers TFTPD_TC_ADD(tp, wrq_eaccess); 1270888651fcSAlan Somers TFTPD_TC_ADD(tp, wrq_eaccess_world_readable); 1271888651fcSAlan Somers TFTPD_TC_ADD(tp, wrq_medium); 1272fdf929ffSJohn Baldwin TFTPD_TC_ADD(tp, wrq_medium_window); 1273888651fcSAlan Somers TFTPD_TC_ADD(tp, wrq_netascii); 1274888651fcSAlan Somers TFTPD_TC_ADD(tp, wrq_nonexistent); 1275888651fcSAlan Somers TFTPD_TC_ADD(tp, wrq_small); 1276888651fcSAlan Somers TFTPD_TC_ADD(tp, wrq_truncate); 1277fdf929ffSJohn Baldwin TFTPD_TC_ADD(tp, wrq_window_rfc7440); 12789f231af3SDag-Erling Smørgrav TFTPD_TC_ADD(tp, short_packet1); 12799f231af3SDag-Erling Smørgrav TFTPD_TC_ADD(tp, short_packet2); 12809f231af3SDag-Erling Smørgrav TFTPD_TC_ADD(tp, short_packet3); 1281888651fcSAlan Somers 1282888651fcSAlan Somers return (atf_no_error()); 1283888651fcSAlan Somers } 1284