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