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