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 76 #define PKTSIZE SEGSIZE+4 77 char ackbuf[PKTSIZE]; 78 int timeout; 79 jmp_buf toplevel; 80 jmp_buf timeoutbuf; 81 82 static void nak(int, struct sockaddr *); 83 static int makerequest(int, const char *, struct tftphdr *, const char *); 84 static void printstats(const char *, unsigned long); 85 static void startclock(void); 86 static void stopclock(void); 87 static void timer(int); 88 static void tpacket(const char *, struct tftphdr *, int); 89 static int cmpport(struct sockaddr *, struct sockaddr *); 90 91 /* 92 * Send the requested file. 93 */ 94 void 95 xmitfile(fd, name, mode) 96 int fd; 97 char *name; 98 char *mode; 99 { 100 struct tftphdr *ap; /* data and ack packets */ 101 struct tftphdr *dp; 102 int n; 103 volatile unsigned short block; 104 volatile int size, convert; 105 volatile unsigned long amount; 106 struct sockaddr_storage from; 107 int fromlen; 108 FILE *file; 109 struct sockaddr_storage peer; 110 struct sockaddr_storage serv; /* valid server port number */ 111 112 startclock(); /* start stat's clock */ 113 dp = r_init(); /* reset fillbuf/read-ahead code */ 114 ap = (struct tftphdr *)ackbuf; 115 file = fdopen(fd, "r"); 116 convert = !strcmp(mode, "netascii"); 117 block = 0; 118 amount = 0; 119 memcpy(&peer, &peeraddr, peeraddr.ss_len); 120 memset(&serv, 0, sizeof(serv)); 121 122 signal(SIGALRM, timer); 123 do { 124 if (block == 0) 125 size = makerequest(WRQ, name, dp, mode) - 4; 126 else { 127 /* size = read(fd, dp->th_data, SEGSIZE); */ 128 size = readit(file, &dp, convert); 129 if (size < 0) { 130 nak(errno + 100, (struct sockaddr *)&peer); 131 break; 132 } 133 dp->th_opcode = htons((u_short)DATA); 134 dp->th_block = htons((u_short)block); 135 } 136 timeout = 0; 137 (void) setjmp(timeoutbuf); 138 send_data: 139 if (trace) 140 tpacket("sent", dp, size + 4); 141 n = sendto(f, dp, size + 4, 0, 142 (struct sockaddr *)&peer, peer.ss_len); 143 if (n != size + 4) { 144 warn("sendto"); 145 goto abort; 146 } 147 read_ahead(file, convert); 148 for ( ; ; ) { 149 alarm(rexmtval); 150 do { 151 fromlen = sizeof(from); 152 n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, 153 (struct sockaddr *)&from, &fromlen); 154 } while (n <= 0); 155 alarm(0); 156 if (n < 0) { 157 warn("recvfrom"); 158 goto abort; 159 } 160 if (!serv.ss_family) 161 serv = from; 162 else if (!cmpport((struct sockaddr *)&serv, 163 (struct sockaddr *)&from)) { 164 warn("server port mismatch"); 165 goto abort; 166 } 167 peer = from; 168 if (trace) 169 tpacket("received", ap, n); 170 /* should verify packet came from server */ 171 ap->th_opcode = ntohs(ap->th_opcode); 172 ap->th_block = ntohs(ap->th_block); 173 if (ap->th_opcode == ERROR) { 174 printf("Error code %d: %s\n", ap->th_code, 175 ap->th_msg); 176 goto abort; 177 } 178 if (ap->th_opcode == ACK) { 179 int j; 180 181 if (ap->th_block == block) { 182 break; 183 } 184 /* On an error, try to synchronize 185 * both sides. 186 */ 187 j = synchnet(f); 188 if (j && trace) { 189 printf("discarded %d packets\n", 190 j); 191 } 192 if (ap->th_block == (block-1)) { 193 goto send_data; 194 } 195 } 196 } 197 if (block > 0) 198 amount += size; 199 block++; 200 } while (size == SEGSIZE || block == 1); 201 abort: 202 fclose(file); 203 stopclock(); 204 if (amount > 0) 205 printstats("Sent", amount); 206 } 207 208 /* 209 * Receive a file. 210 */ 211 void 212 recvfile(fd, name, mode) 213 int fd; 214 char *name; 215 char *mode; 216 { 217 struct tftphdr *ap; 218 struct tftphdr *dp; 219 int n; 220 volatile unsigned short block; 221 volatile int size, firsttrip; 222 volatile unsigned long amount; 223 struct sockaddr_storage from; 224 int fromlen; 225 FILE *file; 226 volatile int convert; /* true if converting crlf -> lf */ 227 struct sockaddr_storage peer; 228 struct sockaddr_storage serv; /* valid server port number */ 229 230 startclock(); 231 dp = w_init(); 232 ap = (struct tftphdr *)ackbuf; 233 file = fdopen(fd, "w"); 234 convert = !strcmp(mode, "netascii"); 235 block = 1; 236 firsttrip = 1; 237 amount = 0; 238 memcpy(&peer, &peeraddr, peeraddr.ss_len); 239 memset(&serv, 0, sizeof(serv)); 240 241 signal(SIGALRM, timer); 242 do { 243 if (firsttrip) { 244 size = makerequest(RRQ, name, ap, mode); 245 firsttrip = 0; 246 } else { 247 ap->th_opcode = htons((u_short)ACK); 248 ap->th_block = htons((u_short)(block)); 249 size = 4; 250 block++; 251 } 252 timeout = 0; 253 (void) setjmp(timeoutbuf); 254 send_ack: 255 if (trace) 256 tpacket("sent", ap, size); 257 if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peer, 258 peer.ss_len) != size) { 259 alarm(0); 260 warn("sendto"); 261 goto abort; 262 } 263 write_behind(file, convert); 264 for ( ; ; ) { 265 alarm(rexmtval); 266 do { 267 fromlen = sizeof(from); 268 n = recvfrom(f, dp, PKTSIZE, 0, 269 (struct sockaddr *)&from, &fromlen); 270 } while (n <= 0); 271 alarm(0); 272 if (n < 0) { 273 warn("recvfrom"); 274 goto abort; 275 } 276 if (!serv.ss_family) 277 serv = from; 278 else if (!cmpport((struct sockaddr *)&serv, 279 (struct sockaddr *)&from)) { 280 warn("server port mismatch"); 281 goto abort; 282 } 283 peer = from; 284 if (trace) 285 tpacket("received", dp, n); 286 /* should verify client address */ 287 dp->th_opcode = ntohs(dp->th_opcode); 288 dp->th_block = ntohs(dp->th_block); 289 if (dp->th_opcode == ERROR) { 290 printf("Error code %d: %s\n", dp->th_code, 291 dp->th_msg); 292 goto abort; 293 } 294 if (dp->th_opcode == DATA) { 295 int j; 296 297 if (dp->th_block == block) { 298 break; /* have next packet */ 299 } 300 /* On an error, try to synchronize 301 * both sides. 302 */ 303 j = synchnet(f); 304 if (j && trace) { 305 printf("discarded %d packets\n", j); 306 } 307 if (dp->th_block == (block-1)) { 308 goto send_ack; /* resend ack */ 309 } 310 } 311 } 312 /* size = write(fd, dp->th_data, n - 4); */ 313 size = writeit(file, &dp, n - 4, convert); 314 if (size < 0) { 315 nak(errno + 100, (struct sockaddr *)&peer); 316 break; 317 } 318 amount += size; 319 } while (size == SEGSIZE); 320 abort: /* ok to ack, since user */ 321 ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ 322 ap->th_block = htons((u_short)block); 323 (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer, 324 peer.ss_len); 325 write_behind(file, convert); /* flush last buffer */ 326 fclose(file); 327 stopclock(); 328 if (amount > 0) 329 printstats("Received", amount); 330 } 331 332 static int 333 makerequest(request, name, tp, mode) 334 int request; 335 const char *name; 336 struct tftphdr *tp; 337 const char *mode; 338 { 339 char *cp; 340 341 tp->th_opcode = htons((u_short)request); 342 cp = tp->th_stuff; 343 strcpy(cp, name); 344 cp += strlen(name); 345 *cp++ = '\0'; 346 strcpy(cp, mode); 347 cp += strlen(mode); 348 *cp++ = '\0'; 349 return (cp - (char *)tp); 350 } 351 352 struct errmsg { 353 int e_code; 354 const char *e_msg; 355 } errmsgs[] = { 356 { EUNDEF, "Undefined error code" }, 357 { ENOTFOUND, "File not found" }, 358 { EACCESS, "Access violation" }, 359 { ENOSPACE, "Disk full or allocation exceeded" }, 360 { EBADOP, "Illegal TFTP operation" }, 361 { EBADID, "Unknown transfer ID" }, 362 { EEXISTS, "File already exists" }, 363 { ENOUSER, "No such user" }, 364 { -1, 0 } 365 }; 366 367 /* 368 * Send a nak packet (error message). 369 * Error code passed in is one of the 370 * standard TFTP codes, or a UNIX errno 371 * offset by 100. 372 */ 373 static void 374 nak(error, peer) 375 int error; 376 struct sockaddr *peer; 377 { 378 struct errmsg *pe; 379 struct tftphdr *tp; 380 int length; 381 382 tp = (struct tftphdr *)ackbuf; 383 tp->th_opcode = htons((u_short)ERROR); 384 tp->th_code = htons((u_short)error); 385 for (pe = errmsgs; pe->e_code >= 0; pe++) 386 if (pe->e_code == error) 387 break; 388 if (pe->e_code < 0) { 389 pe->e_msg = strerror(error - 100); 390 tp->th_code = EUNDEF; 391 } 392 strcpy(tp->th_msg, pe->e_msg); 393 length = strlen(pe->e_msg) + 4; 394 if (trace) 395 tpacket("sent", tp, length); 396 if (sendto(f, ackbuf, length, 0, peer, peer->sa_len) != length) 397 warn("nak"); 398 } 399 400 static void 401 tpacket(s, tp, n) 402 const char *s; 403 struct tftphdr *tp; 404 int n; 405 { 406 static const char *opcodes[] = 407 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; 408 char *cp, *file; 409 u_short op = ntohs(tp->th_opcode); 410 411 if (op < RRQ || op > ERROR) 412 printf("%s opcode=%x ", s, op); 413 else 414 printf("%s %s ", s, opcodes[op]); 415 switch (op) { 416 417 case RRQ: 418 case WRQ: 419 n -= 2; 420 file = cp = tp->th_stuff; 421 cp = index(cp, '\0'); 422 printf("<file=%s, mode=%s>\n", file, cp + 1); 423 break; 424 425 case DATA: 426 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); 427 break; 428 429 case ACK: 430 printf("<block=%d>\n", ntohs(tp->th_block)); 431 break; 432 433 case ERROR: 434 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); 435 break; 436 } 437 } 438 439 struct timeval tstart; 440 struct timeval tstop; 441 442 static void 443 startclock() 444 { 445 446 (void)gettimeofday(&tstart, NULL); 447 } 448 449 static void 450 stopclock() 451 { 452 453 (void)gettimeofday(&tstop, NULL); 454 } 455 456 static void 457 printstats(direction, amount) 458 const char *direction; 459 unsigned long amount; 460 { 461 double delta; 462 /* compute delta in 1/10's second units */ 463 delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - 464 ((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); 465 delta = delta/10.; /* back to seconds */ 466 printf("%s %ld bytes in %.1f seconds", direction, amount, delta); 467 if (verbose) 468 printf(" [%.0f bits/sec]", (amount*8.)/delta); 469 putchar('\n'); 470 } 471 472 static void 473 timer(sig) 474 int sig __unused; 475 { 476 477 timeout += rexmtval; 478 if (timeout >= maxtimeout) { 479 printf("Transfer timed out.\n"); 480 longjmp(toplevel, -1); 481 } 482 longjmp(timeoutbuf, 1); 483 } 484 485 static int 486 cmpport(sa, sb) 487 struct sockaddr *sa; 488 struct sockaddr *sb; 489 { 490 char a[NI_MAXSERV], b[NI_MAXSERV]; 491 492 if (getnameinfo(sa, sa->sa_len, NULL, 0, a, sizeof(a), NI_NUMERICSERV)) 493 return 0; 494 if (getnameinfo(sb, sb->sa_len, NULL, 0, b, sizeof(b), NI_NUMERICSERV)) 495 return 0; 496 if (strcmp(a, b) != 0) 497 return 0; 498 499 return 1; 500 } 501