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 #ifndef lint 35 #if 0 36 static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93"; 37 #endif 38 static const char rcsid[] = 39 "$FreeBSD: src/usr.bin/tftp/tftp.c,v 1.5.2.3 2002/05/14 22:08:07 bsd Exp $"; 40 #endif /* not lint */ 41 42 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 43 44 /* 45 * TFTP User Program -- Protocol Machines 46 */ 47 #include <sys/types.h> 48 #include <sys/socket.h> 49 #include <sys/time.h> 50 51 #include <netinet/in.h> 52 53 #include <arpa/tftp.h> 54 55 #include <err.h> 56 #include <errno.h> 57 #include <setjmp.h> 58 #include <signal.h> 59 #include <stdio.h> 60 #include <string.h> 61 #include <unistd.h> 62 #include <netdb.h> 63 64 #include "extern.h" 65 #include "tftpsubs.h" 66 67 extern struct sockaddr_storage peeraddr; /* filled in by main */ 68 extern int f; /* the opened socket */ 69 extern int trace; 70 extern int verbose; 71 extern int rexmtval; 72 extern int maxtimeout; 73 extern volatile int txrx_error; 74 75 #define PKTSIZE SEGSIZE+4 76 char ackbuf[PKTSIZE]; 77 int timeout; 78 jmp_buf toplevel; 79 jmp_buf timeoutbuf; 80 81 static void nak __P((int, struct sockaddr *)); 82 static int makerequest __P((int, const char *, struct tftphdr *, const char *)); 83 static void printstats __P((const char *, unsigned long)); 84 static void startclock __P((void)); 85 static void stopclock __P((void)); 86 static void timer __P((int)); 87 static void tpacket __P((const char *, struct tftphdr *, int)); 88 static int cmpport __P((struct sockaddr *, struct sockaddr *)); 89 90 /* 91 * Send the requested file. 92 */ 93 void 94 xmitfile(fd, name, mode) 95 int fd; 96 char *name; 97 char *mode; 98 { 99 register struct tftphdr *ap; /* data and ack packets */ 100 struct tftphdr *r_init(), *dp; 101 register int n; 102 volatile unsigned short block; 103 volatile int size, convert; 104 volatile unsigned long amount; 105 struct sockaddr_storage from; 106 int fromlen; 107 FILE *file; 108 struct sockaddr_storage peer; 109 struct sockaddr_storage serv; /* valid server port number */ 110 111 startclock(); /* start stat's clock */ 112 dp = r_init(); /* reset fillbuf/read-ahead code */ 113 ap = (struct tftphdr *)ackbuf; 114 file = fdopen(fd, "r"); 115 convert = !strcmp(mode, "netascii"); 116 block = 0; 117 amount = 0; 118 memcpy(&peer, &peeraddr, peeraddr.ss_len); 119 memset(&serv, 0, sizeof(serv)); 120 121 signal(SIGALRM, timer); 122 do { 123 if (block == 0) 124 size = makerequest(WRQ, name, dp, mode) - 4; 125 else { 126 /* size = read(fd, dp->th_data, SEGSIZE); */ 127 size = readit(file, &dp, convert); 128 if (size < 0) { 129 nak(errno + 100, (struct sockaddr *)&peer); 130 break; 131 } 132 dp->th_opcode = htons((u_short)DATA); 133 dp->th_block = htons((u_short)block); 134 } 135 timeout = 0; 136 (void) setjmp(timeoutbuf); 137 send_data: 138 if (trace) 139 tpacket("sent", dp, size + 4); 140 n = sendto(f, dp, size + 4, 0, 141 (struct sockaddr *)&peer, peer.ss_len); 142 if (n != size + 4) { 143 warn("sendto"); 144 goto abort; 145 } 146 read_ahead(file, convert); 147 for ( ; ; ) { 148 alarm(rexmtval); 149 do { 150 fromlen = sizeof(from); 151 n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, 152 (struct sockaddr *)&from, &fromlen); 153 } while (n <= 0); 154 alarm(0); 155 if (n < 0) { 156 warn("recvfrom"); 157 goto abort; 158 } 159 if (!serv.ss_family) 160 serv = from; 161 else if (!cmpport((struct sockaddr *)&serv, 162 (struct sockaddr *)&from)) { 163 warn("server port mismatch"); 164 goto abort; 165 } 166 peer = from; 167 if (trace) 168 tpacket("received", ap, n); 169 /* should verify packet came from server */ 170 ap->th_opcode = ntohs(ap->th_opcode); 171 ap->th_block = ntohs(ap->th_block); 172 if (ap->th_opcode == ERROR) { 173 printf("Error code %d: %s\n", ap->th_code, 174 ap->th_msg); 175 txrx_error = 1; 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 register struct tftphdr *ap; 218 struct tftphdr *dp, *w_init(); 219 register 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 txrx_error = 1; 293 goto abort; 294 } 295 if (dp->th_opcode == DATA) { 296 int j; 297 298 if (dp->th_block == block) { 299 break; /* have next packet */ 300 } 301 /* On an error, try to synchronize 302 * both sides. 303 */ 304 j = synchnet(f); 305 if (j && trace) { 306 printf("discarded %d packets\n", j); 307 } 308 if (dp->th_block == (block-1)) { 309 goto send_ack; /* resend ack */ 310 } 311 } 312 } 313 /* size = write(fd, dp->th_data, n - 4); */ 314 size = writeit(file, &dp, n - 4, convert); 315 if (size < 0) { 316 nak(errno + 100, (struct sockaddr *)&peer); 317 break; 318 } 319 amount += size; 320 } while (size == SEGSIZE); 321 abort: /* ok to ack, since user */ 322 ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ 323 ap->th_block = htons((u_short)block); 324 (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer, 325 peer.ss_len); 326 write_behind(file, convert); /* flush last buffer */ 327 fclose(file); 328 stopclock(); 329 if (amount > 0) 330 printstats("Received", amount); 331 } 332 333 static int 334 makerequest(request, name, tp, mode) 335 int request; 336 const char *name; 337 struct tftphdr *tp; 338 const char *mode; 339 { 340 register char *cp; 341 342 tp->th_opcode = htons((u_short)request); 343 cp = tp->th_stuff; 344 strcpy(cp, name); 345 cp += strlen(name); 346 *cp++ = '\0'; 347 strcpy(cp, mode); 348 cp += strlen(mode); 349 *cp++ = '\0'; 350 return (cp - (char *)tp); 351 } 352 353 struct errmsg { 354 int e_code; 355 char *e_msg; 356 } errmsgs[] = { 357 { EUNDEF, "Undefined error code" }, 358 { ENOTFOUND, "File not found" }, 359 { EACCESS, "Access violation" }, 360 { ENOSPACE, "Disk full or allocation exceeded" }, 361 { EBADOP, "Illegal TFTP operation" }, 362 { EBADID, "Unknown transfer ID" }, 363 { EEXISTS, "File already exists" }, 364 { ENOUSER, "No such user" }, 365 { -1, 0 } 366 }; 367 368 /* 369 * Send a nak packet (error message). 370 * Error code passed in is one of the 371 * standard TFTP codes, or a UNIX errno 372 * offset by 100. 373 */ 374 static void 375 nak(error, peer) 376 int error; 377 struct sockaddr *peer; 378 { 379 register struct errmsg *pe; 380 register struct tftphdr *tp; 381 int length; 382 char *strerror(); 383 384 tp = (struct tftphdr *)ackbuf; 385 tp->th_opcode = htons((u_short)ERROR); 386 tp->th_code = htons((u_short)error); 387 for (pe = errmsgs; pe->e_code >= 0; pe++) 388 if (pe->e_code == error) 389 break; 390 if (pe->e_code < 0) { 391 pe->e_msg = strerror(error - 100); 392 tp->th_code = EUNDEF; 393 } 394 strcpy(tp->th_msg, pe->e_msg); 395 length = strlen(pe->e_msg) + 4; 396 if (trace) 397 tpacket("sent", tp, length); 398 if (sendto(f, ackbuf, length, 0, peer, peer->sa_len) != length) 399 warn("nak"); 400 } 401 402 static void 403 tpacket(s, tp, n) 404 const char *s; 405 struct tftphdr *tp; 406 int n; 407 { 408 static char *opcodes[] = 409 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; 410 register char *cp, *file; 411 u_short op = ntohs(tp->th_opcode); 412 char *index(); 413 414 if (op < RRQ || op > ERROR) 415 printf("%s opcode=%x ", s, op); 416 else 417 printf("%s %s ", s, opcodes[op]); 418 switch (op) { 419 420 case RRQ: 421 case WRQ: 422 n -= 2; 423 file = cp = tp->th_stuff; 424 cp = index(cp, '\0'); 425 printf("<file=%s, mode=%s>\n", file, cp + 1); 426 break; 427 428 case DATA: 429 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); 430 break; 431 432 case ACK: 433 printf("<block=%d>\n", ntohs(tp->th_block)); 434 break; 435 436 case ERROR: 437 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); 438 break; 439 } 440 } 441 442 struct timeval tstart; 443 struct timeval tstop; 444 445 static void 446 startclock() 447 { 448 449 (void)gettimeofday(&tstart, NULL); 450 } 451 452 static void 453 stopclock() 454 { 455 456 (void)gettimeofday(&tstop, NULL); 457 } 458 459 static void 460 printstats(direction, amount) 461 const char *direction; 462 unsigned long amount; 463 { 464 double delta; 465 /* compute delta in 1/10's second units */ 466 delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - 467 ((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); 468 delta = delta/10.; /* back to seconds */ 469 printf("%s %d bytes in %.1f seconds", direction, amount, delta); 470 if (verbose) 471 printf(" [%.0f bits/sec]", (amount*8.)/delta); 472 putchar('\n'); 473 } 474 475 static void 476 timer(sig) 477 int sig; 478 { 479 480 timeout += rexmtval; 481 if (timeout >= maxtimeout) { 482 printf("Transfer timed out.\n"); 483 longjmp(toplevel, -1); 484 } 485 txrx_error = 1; 486 longjmp(timeoutbuf, 1); 487 } 488 489 static int 490 cmpport(sa, sb) 491 struct sockaddr *sa; 492 struct sockaddr *sb; 493 { 494 char a[NI_MAXSERV], b[NI_MAXSERV]; 495 496 if (getnameinfo(sa, sa->sa_len, NULL, 0, a, sizeof(a), NI_NUMERICSERV)) 497 return 0; 498 if (getnameinfo(sb, sb->sa_len, NULL, 0, b, sizeof(b), NI_NUMERICSERV)) 499 return 0; 500 if (strcmp(a, b) != 0) 501 return 0; 502 503 return 1; 504 } 505