1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #if 0 35 #ifndef lint 36 static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93"; 37 #endif /* not lint */ 38 #endif 39 40 #include <sys/cdefs.h> 41 __FBSDID("$FreeBSD$"); 42 43 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 44 45 /* 46 * TFTP User Program -- Protocol Machines 47 */ 48 #include <sys/types.h> 49 #include <sys/socket.h> 50 #include <sys/time.h> 51 52 #include <netinet/in.h> 53 54 #include <arpa/inet.h> 55 #include <arpa/tftp.h> 56 57 #include <err.h> 58 #include <errno.h> 59 #include <setjmp.h> 60 #include <signal.h> 61 #include <stdio.h> 62 #include <string.h> 63 #include <unistd.h> 64 #include <netdb.h> 65 66 #include "extern.h" 67 #include "tftpsubs.h" 68 69 extern struct sockaddr_storage peeraddr; /* filled in by main */ 70 extern int f; /* the opened socket */ 71 extern int trace; 72 extern int verbose; 73 extern int rexmtval; 74 extern int maxtimeout; 75 extern volatile int txrx_error; 76 77 #define PKTSIZE SEGSIZE+4 78 char ackbuf[PKTSIZE]; 79 int timeout; 80 jmp_buf toplevel; 81 jmp_buf timeoutbuf; 82 83 static void nak(int, const struct sockaddr *); 84 static int makerequest(int, const char *, struct tftphdr *, const char *); 85 static void printstats(const char *, unsigned long); 86 static void startclock(void); 87 static void stopclock(void); 88 static void timer(int); 89 static void tpacket(const char *, struct tftphdr *, int); 90 static int cmpport(const struct sockaddr *, const struct sockaddr *); 91 92 /* 93 * Send the requested file. 94 */ 95 void 96 xmitfile(int fd, const char *name, const char *mode) 97 { 98 struct tftphdr *ap; /* data and ack packets */ 99 struct tftphdr *dp; 100 int n; 101 volatile unsigned short block; 102 volatile int size, convert; 103 volatile unsigned long amount; 104 struct sockaddr_storage from; 105 socklen_t fromlen; 106 FILE *file; 107 struct sockaddr_storage peer; 108 struct sockaddr_storage serv; /* valid server port number */ 109 110 startclock(); /* start stat's clock */ 111 dp = r_init(); /* reset fillbuf/read-ahead code */ 112 ap = (struct tftphdr *)ackbuf; 113 file = fdopen(fd, "r"); 114 convert = !strcmp(mode, "netascii"); 115 block = 0; 116 amount = 0; 117 memcpy(&peer, &peeraddr, peeraddr.ss_len); 118 memset(&serv, 0, sizeof(serv)); 119 120 signal(SIGALRM, timer); 121 do { 122 if (block == 0) 123 size = makerequest(WRQ, name, dp, mode) - 4; 124 else { 125 /* size = read(fd, dp->th_data, SEGSIZE); */ 126 size = readit(file, &dp, convert); 127 if (size < 0) { 128 nak(errno + 100, (struct sockaddr *)&peer); 129 break; 130 } 131 dp->th_opcode = htons((u_short)DATA); 132 dp->th_block = htons((u_short)block); 133 } 134 timeout = 0; 135 (void) setjmp(timeoutbuf); 136 send_data: 137 if (trace) 138 tpacket("sent", dp, size + 4); 139 n = sendto(f, dp, size + 4, 0, 140 (struct sockaddr *)&peer, peer.ss_len); 141 if (n != size + 4) { 142 warn("sendto"); 143 goto abort; 144 } 145 read_ahead(file, convert); 146 for ( ; ; ) { 147 alarm(rexmtval); 148 do { 149 fromlen = sizeof(from); 150 n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, 151 (struct sockaddr *)&from, &fromlen); 152 } while (n <= 0); 153 alarm(0); 154 if (n < 0) { 155 warn("recvfrom"); 156 goto abort; 157 } 158 if (!serv.ss_family) 159 serv = from; 160 else if (!cmpport((struct sockaddr *)&serv, 161 (struct sockaddr *)&from)) { 162 warn("server port mismatch"); 163 goto abort; 164 } 165 peer = from; 166 if (trace) 167 tpacket("received", ap, n); 168 /* should verify packet came from server */ 169 ap->th_opcode = ntohs(ap->th_opcode); 170 ap->th_block = ntohs(ap->th_block); 171 if (ap->th_opcode == ERROR) { 172 printf("Error code %d: %s\n", ap->th_code, 173 ap->th_msg); 174 txrx_error = 1; 175 goto abort; 176 } 177 if (ap->th_opcode == ACK) { 178 int j; 179 180 if (ap->th_block == block) { 181 break; 182 } 183 /* On an error, try to synchronize 184 * both sides. 185 */ 186 j = synchnet(f); 187 if (j && trace) { 188 printf("discarded %d packets\n", 189 j); 190 } 191 if (ap->th_block == (block-1)) { 192 goto send_data; 193 } 194 } 195 } 196 if (block > 0) 197 amount += size; 198 block++; 199 } while (size == SEGSIZE || block == 1); 200 abort: 201 fclose(file); 202 stopclock(); 203 if (amount > 0) 204 printstats("Sent", amount); 205 txrx_error = 1; 206 } 207 208 /* 209 * Receive a file. 210 */ 211 void 212 recvfile(int fd, const char *name, const char *mode) 213 { 214 struct tftphdr *ap; 215 struct tftphdr *dp; 216 int n; 217 volatile unsigned short block; 218 volatile int size, firsttrip; 219 volatile unsigned long amount; 220 struct sockaddr_storage from; 221 socklen_t fromlen; 222 FILE *file; 223 volatile int convert; /* true if converting crlf -> lf */ 224 struct sockaddr_storage peer; 225 struct sockaddr_storage serv; /* valid server port number */ 226 227 startclock(); 228 dp = w_init(); 229 ap = (struct tftphdr *)ackbuf; 230 file = fdopen(fd, "w"); 231 convert = !strcmp(mode, "netascii"); 232 block = 1; 233 firsttrip = 1; 234 amount = 0; 235 memcpy(&peer, &peeraddr, peeraddr.ss_len); 236 memset(&serv, 0, sizeof(serv)); 237 238 signal(SIGALRM, timer); 239 do { 240 if (firsttrip) { 241 size = makerequest(RRQ, name, ap, mode); 242 firsttrip = 0; 243 } else { 244 ap->th_opcode = htons((u_short)ACK); 245 ap->th_block = htons((u_short)(block)); 246 size = 4; 247 block++; 248 } 249 timeout = 0; 250 (void) setjmp(timeoutbuf); 251 send_ack: 252 if (trace) 253 tpacket("sent", ap, size); 254 if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peer, 255 peer.ss_len) != size) { 256 alarm(0); 257 warn("sendto"); 258 goto abort; 259 } 260 write_behind(file, convert); 261 for ( ; ; ) { 262 alarm(rexmtval); 263 do { 264 fromlen = sizeof(from); 265 n = recvfrom(f, dp, PKTSIZE, 0, 266 (struct sockaddr *)&from, &fromlen); 267 } while (n <= 0); 268 alarm(0); 269 if (n < 0) { 270 warn("recvfrom"); 271 goto abort; 272 } 273 if (!serv.ss_family) 274 serv = from; 275 else if (!cmpport((struct sockaddr *)&serv, 276 (struct sockaddr *)&from)) { 277 warn("server port mismatch"); 278 goto abort; 279 } 280 peer = from; 281 if (trace) 282 tpacket("received", dp, n); 283 /* should verify client address */ 284 dp->th_opcode = ntohs(dp->th_opcode); 285 dp->th_block = ntohs(dp->th_block); 286 if (dp->th_opcode == ERROR) { 287 printf("Error code %d: %s\n", dp->th_code, 288 dp->th_msg); 289 txrx_error = 1; 290 goto abort; 291 } 292 if (dp->th_opcode == DATA) { 293 int j; 294 295 if (dp->th_block == block) { 296 break; /* have next packet */ 297 } 298 /* On an error, try to synchronize 299 * both sides. 300 */ 301 j = synchnet(f); 302 if (j && trace) { 303 printf("discarded %d packets\n", j); 304 } 305 if (dp->th_block == (block-1)) { 306 goto send_ack; /* resend ack */ 307 } 308 } 309 } 310 /* size = write(fd, dp->th_data, n - 4); */ 311 size = writeit(file, &dp, n - 4, convert); 312 if (size < 0) { 313 nak(errno + 100, (struct sockaddr *)&peer); 314 break; 315 } 316 amount += size; 317 } while (size == SEGSIZE); 318 abort: /* ok to ack, since user */ 319 ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ 320 ap->th_block = htons((u_short)block); 321 (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer, 322 peer.ss_len); 323 write_behind(file, convert); /* flush last buffer */ 324 fclose(file); 325 stopclock(); 326 if (amount > 0) 327 printstats("Received", amount); 328 txrx_error = 1; 329 } 330 331 static int 332 makerequest(int request, const char *name, struct tftphdr *tp, const char *mode) 333 { 334 char *cp; 335 336 tp->th_opcode = htons((u_short)request); 337 cp = tp->th_stuff; 338 strcpy(cp, name); 339 cp += strlen(name); 340 *cp++ = '\0'; 341 strcpy(cp, mode); 342 cp += strlen(mode); 343 *cp++ = '\0'; 344 return (cp - (char *)tp); 345 } 346 347 struct errmsg { 348 int e_code; 349 const char *e_msg; 350 } errmsgs[] = { 351 { EUNDEF, "Undefined error code" }, 352 { ENOTFOUND, "File not found" }, 353 { EACCESS, "Access violation" }, 354 { ENOSPACE, "Disk full or allocation exceeded" }, 355 { EBADOP, "Illegal TFTP operation" }, 356 { EBADID, "Unknown transfer ID" }, 357 { EEXISTS, "File already exists" }, 358 { ENOUSER, "No such user" }, 359 { -1, 0 } 360 }; 361 362 /* 363 * Send a nak packet (error message). 364 * Error code passed in is one of the 365 * standard TFTP codes, or a UNIX errno 366 * offset by 100. 367 */ 368 static void 369 nak(int error, const struct sockaddr *peer) 370 { 371 struct errmsg *pe; 372 struct tftphdr *tp; 373 int length; 374 375 tp = (struct tftphdr *)ackbuf; 376 tp->th_opcode = htons((u_short)ERROR); 377 tp->th_code = htons((u_short)error); 378 for (pe = errmsgs; pe->e_code >= 0; pe++) 379 if (pe->e_code == error) 380 break; 381 if (pe->e_code < 0) { 382 pe->e_msg = strerror(error - 100); 383 tp->th_code = EUNDEF; 384 } 385 strcpy(tp->th_msg, pe->e_msg); 386 length = strlen(pe->e_msg) + 4; 387 if (trace) 388 tpacket("sent", tp, length); 389 if (sendto(f, ackbuf, length, 0, peer, peer->sa_len) != length) 390 warn("nak"); 391 } 392 393 static void 394 tpacket(const char *s, struct tftphdr *tp, int n) 395 { 396 static const char *opcodes[] = 397 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; 398 char *cp, *file; 399 u_short op = ntohs(tp->th_opcode); 400 401 if (op < RRQ || op > ERROR) 402 printf("%s opcode=%x ", s, op); 403 else 404 printf("%s %s ", s, opcodes[op]); 405 switch (op) { 406 407 case RRQ: 408 case WRQ: 409 n -= 2; 410 file = cp = tp->th_stuff; 411 cp = index(cp, '\0'); 412 printf("<file=%s, mode=%s>\n", file, cp + 1); 413 break; 414 415 case DATA: 416 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); 417 break; 418 419 case ACK: 420 printf("<block=%d>\n", ntohs(tp->th_block)); 421 break; 422 423 case ERROR: 424 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); 425 break; 426 } 427 } 428 429 struct timeval tstart; 430 struct timeval tstop; 431 432 static void 433 startclock(void) 434 { 435 436 (void)gettimeofday(&tstart, NULL); 437 } 438 439 static void 440 stopclock(void) 441 { 442 443 (void)gettimeofday(&tstop, NULL); 444 } 445 446 static void 447 printstats(const char *direction, unsigned long amount) 448 { 449 double delta; 450 /* compute delta in 1/10's second units */ 451 delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - 452 ((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); 453 delta = delta/10.; /* back to seconds */ 454 printf("%s %ld bytes in %.1f seconds", direction, amount, delta); 455 if (verbose) 456 printf(" [%.0f bits/sec]", (amount*8.)/delta); 457 putchar('\n'); 458 } 459 460 static void 461 timer(int sig __unused) 462 { 463 464 timeout += rexmtval; 465 if (timeout >= maxtimeout) { 466 printf("Transfer timed out.\n"); 467 longjmp(toplevel, -1); 468 } 469 txrx_error = 1; 470 longjmp(timeoutbuf, 1); 471 } 472 473 static int 474 cmpport(const struct sockaddr *sa, const struct sockaddr *sb) 475 { 476 char a[NI_MAXSERV], b[NI_MAXSERV]; 477 478 if (getnameinfo(sa, sa->sa_len, NULL, 0, a, sizeof(a), NI_NUMERICSERV)) 479 return 0; 480 if (getnameinfo(sb, sb->sa_len, NULL, 0, b, sizeof(b), NI_NUMERICSERV)) 481 return 0; 482 if (strcmp(a, b) != 0) 483 return 0; 484 485 return 1; 486 } 487