1 /* $OpenBSD: tftp.c,v 1.25 2017/09/10 07:29:39 tb Exp $ */
2 /* $NetBSD: tftp.c,v 1.5 1995/04/29 05:55:25 cgd Exp $ */
3
4 /*
5 * Copyright (c) 1983, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * TFTP User Program -- Protocol Machines
35 *
36 * This version includes many modifications by Jim Guyton <guyton@rand-unix>
37 */
38
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/time.h>
42 #include <sys/stat.h>
43
44 #include <netinet/in.h>
45 #include <arpa/tftp.h>
46
47 #include <err.h>
48 #include <errno.h>
49 #include <poll.h>
50 #include <signal.h>
51 #include <stdio.h>
52 #include <stddef.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <time.h>
56 #include <unistd.h>
57 #include <netdb.h>
58
59 #include "extern.h"
60 #include "tftpsubs.h"
61
62 static int cmpport(struct sockaddr *, struct sockaddr *);
63 static int makerequest(int, const char *, struct tftphdr *, const char *);
64 static void nak(int, struct sockaddr *);
65 static void tpacket(const char *, struct tftphdr *, int);
66 static void startclock(void);
67 static void stopclock(void);
68 static void printstats(const char *, unsigned long);
69 static void printtimeout(void);
70 static void oack(struct tftphdr *, int, int);
71 static int oack_set(const char *, const char *);
72
73 extern struct sockaddr_storage peeraddr; /* filled in by main */
74 extern int f; /* the opened socket */
75 extern int trace;
76 extern int verbose;
77 extern int rexmtval;
78 extern int maxtimeout;
79 extern FILE *file;
80 extern volatile sig_atomic_t intrflag;
81 extern char *ackbuf;
82 extern int has_options;
83 extern int opt_tsize;
84 extern int opt_tout;
85 extern int opt_blksize;
86
87 struct timespec tstart;
88 struct timespec tstop;
89 unsigned int segment_size = SEGSIZE;
90 unsigned int packet_size = SEGSIZE + 4;
91
92 struct errmsg {
93 int e_code;
94 char *e_msg;
95 } errmsgs[] = {
96 { EUNDEF, "Undefined error code" },
97 { ENOTFOUND, "File not found" },
98 { EACCESS, "Access violation" },
99 { ENOSPACE, "Disk full or allocation exceeded" },
100 { EBADOP, "Illegal TFTP operation" },
101 { EBADID, "Unknown transfer ID" },
102 { EEXISTS, "File already exists" },
103 { ENOUSER, "No such user" },
104 { EOPTNEG, "Option negotiation failed" },
105 { -1, NULL }
106 };
107
108 struct options {
109 const char *o_type;
110 } options[] = {
111 { "tsize" },
112 { "timeout" },
113 { "blksize" },
114 { NULL }
115 };
116
117 enum opt_enum {
118 OPT_TSIZE = 0,
119 OPT_TIMEOUT,
120 OPT_BLKSIZE
121 };
122
123 /*
124 * Send the requested file.
125 */
126 void
sendfile(int fd,char * name,char * mode)127 sendfile(int fd, char *name, char *mode)
128 {
129 struct tftphdr *dp, *ap; /* data and ack packets */
130 struct sockaddr_storage from, peer;
131 struct sockaddr_storage serv; /* valid server port number */
132 struct pollfd pfd[1];
133 unsigned long amount;
134 socklen_t fromlen;
135 int convert; /* true if converting crlf -> lf */
136 int n, nfds, error, timeouts, size;
137 uint16_t block = 0;
138 int firsttrip = 1;
139
140 startclock(); /* start stat's clock */
141 dp = r_init(); /* reset fillbuf/read-ahead code */
142 ap = (struct tftphdr *)ackbuf;
143 file = fdopen(fd, "r");
144 convert = !strcmp(mode, "netascii");
145 amount = 0;
146 memcpy(&peer, &peeraddr, peeraddr.ss_len);
147 memset(&serv, 0, sizeof(serv));
148
149 do {
150 /* read data from file */
151 if (firsttrip)
152 size = makerequest(WRQ, name, dp, mode) - 4;
153 else {
154 size = readit(file, &dp, convert, segment_size);
155 if (size < 0) {
156 nak(errno + 100, (struct sockaddr *)&peer);
157 break;
158 }
159 dp->th_opcode = htons((u_short)DATA);
160 dp->th_block = htons(block);
161 }
162
163 /* send data to server and wait for server ACK */
164 for (timeouts = 0, error = 0; !intrflag;) {
165 if (timeouts >= maxtimeout) {
166 printtimeout();
167 goto abort;
168 }
169
170 if (!error) {
171 if (trace)
172 tpacket("sent", dp, size + 4);
173 if (sendto(f, dp, size + 4, 0,
174 (struct sockaddr *)&peer,
175 peer.ss_len) != size + 4) {
176 warn("sendto");
177 goto abort;
178 }
179 if (!firsttrip)
180 read_ahead(file, convert, segment_size);
181 }
182 error = 0;
183
184 pfd[0].fd = f;
185 pfd[0].events = POLLIN;
186 nfds = poll(pfd, 1, rexmtval * 1000);
187 if (nfds == 0) {
188 timeouts += rexmtval;
189 continue;
190 }
191 if (nfds == -1) {
192 error = 1;
193 if (errno == EINTR)
194 continue;
195 warn("poll");
196 goto abort;
197 }
198 fromlen = sizeof(from);
199 n = recvfrom(f, ackbuf, packet_size, 0,
200 (struct sockaddr *)&from, &fromlen);
201 if (n == 0) {
202 warn("recvfrom");
203 goto abort;
204 }
205 if (n == -1) {
206 error = 1;
207 if (errno == EINTR)
208 continue;
209 warn("recvfrom");
210 goto abort;
211 }
212 if (!serv.ss_family)
213 serv = from;
214 else if (!cmpport((struct sockaddr *)&serv,
215 (struct sockaddr *)&from)) {
216 warn("server port mismatch");
217 goto abort;
218 }
219 peer = from;
220 if (trace)
221 tpacket("received", ap, n);
222
223 ap->th_opcode = ntohs(ap->th_opcode);
224
225 if (ap->th_opcode == OACK) {
226 oack(ap, n, 0);
227 break;
228 }
229
230 ap->th_block = ntohs(ap->th_block);
231
232 if (ap->th_opcode == ERROR) {
233 printf("Error code %d: %s\n",
234 ap->th_code, ap->th_msg);
235 goto abort;
236 }
237 if (ap->th_opcode == ACK) {
238 int j;
239 if (ap->th_block == block)
240 break;
241 /* re-synchronize with other side */
242 j = synchnet(f);
243 if (j && trace)
244 printf("discarded %d packets\n", j);
245 if (ap->th_block == (block - 1))
246 continue;
247 }
248 error = 1; /* received packet does not match */
249 }
250
251 if (firsttrip) {
252 size = segment_size;
253 firsttrip = 0;
254 } else
255 amount += size;
256 block++;
257 } while ((size == segment_size) && !intrflag);
258
259 abort:
260 fclose(file);
261 stopclock();
262 if (amount > 0) {
263 if (intrflag)
264 putchar('\n');
265 printstats("Sent", amount);
266 }
267 }
268
269 /*
270 * Receive a file.
271 */
272 void
recvfile(int fd,char * name,char * mode)273 recvfile(int fd, char *name, char *mode)
274 {
275 struct tftphdr *dp, *ap; /* data and ack packets */
276 struct sockaddr_storage from, peer;
277 struct sockaddr_storage serv; /* valid server port number */
278 struct pollfd pfd[1];
279 unsigned long amount;
280 socklen_t fromlen;
281 int convert; /* true if converting crlf -> lf */
282 int n, nfds, error, timeouts, size;
283 int firsttrip;
284 uint16_t block;
285
286 startclock(); /* start stat's clock */
287 dp = w_init(); /* reset fillbuf/read-ahead code */
288 ap = (struct tftphdr *)ackbuf;
289 file = fdopen(fd, "w");
290 convert = !strcmp(mode, "netascii");
291 n = 0;
292 block = 1;
293 amount = 0;
294 firsttrip = 1;
295 memcpy(&peer, &peeraddr, peeraddr.ss_len);
296 memset(&serv, 0, sizeof(serv));
297
298 options:
299 do {
300 /* create new ACK packet */
301 if (firsttrip) {
302 size = makerequest(RRQ, name, ap, mode);
303 firsttrip = 0;
304 } else {
305 ap->th_opcode = htons((u_short)ACK);
306 ap->th_block = htons(block);
307 size = 4;
308 block++;
309 }
310
311 /* send ACK to server and wait for server data */
312 for (timeouts = 0, error = 0; !intrflag;) {
313 if (timeouts >= maxtimeout) {
314 printtimeout();
315 goto abort;
316 }
317
318 if (!error) {
319 if (trace)
320 tpacket("sent", ap, size);
321 if (sendto(f, ackbuf, size, 0,
322 (struct sockaddr *)&peer,
323 peer.ss_len) != size) {
324 warn("sendto");
325 goto abort;
326 }
327 write_behind(file, convert);
328 }
329 error = 0;
330
331 pfd[0].fd = f;
332 pfd[0].events = POLLIN;
333 nfds = poll(pfd, 1, rexmtval * 1000);
334 if (nfds == 0) {
335 timeouts += rexmtval;
336 continue;
337 }
338 if (nfds == -1) {
339 error = 1;
340 if (errno == EINTR)
341 continue;
342 warn("poll");
343 goto abort;
344 }
345 fromlen = sizeof(from);
346 n = recvfrom(f, dp, packet_size, 0,
347 (struct sockaddr *)&from, &fromlen);
348 if (n == 0) {
349 warn("recvfrom");
350 goto abort;
351 }
352 if (n == -1) {
353 error = 1;
354 if (errno == EINTR)
355 continue;
356 warn("recvfrom");
357 goto abort;
358 }
359 if (!serv.ss_family)
360 serv = from;
361 else if (!cmpport((struct sockaddr *)&serv,
362 (struct sockaddr *)&from)) {
363 warn("server port mismatch");
364 goto abort;
365 }
366 peer = from;
367 if (trace)
368 tpacket("received", dp, n);
369
370 dp->th_opcode = ntohs(dp->th_opcode);
371
372 if (dp->th_opcode == OACK) {
373 oack(dp, n, 0);
374 block = 0;
375 goto options;
376 }
377
378 dp->th_block = ntohs(dp->th_block);
379
380 if (dp->th_opcode == ERROR) {
381 printf("Error code %d: %s\n",
382 dp->th_code, dp->th_msg);
383 goto abort;
384 }
385 if (dp->th_opcode == DATA) {
386 int j;
387 if (dp->th_block == block)
388 break;
389 /* re-synchronize with other side */
390 j = synchnet(f);
391 if (j && trace)
392 printf("discarded %d packets\n", j);
393 if (dp->th_block == (block - 1))
394 continue;
395 }
396 error = 1; /* received packet does not match */
397 }
398
399 /* write data to file */
400 size = writeit(file, &dp, n - 4, convert);
401 if (size < 0) {
402 nak(errno + 100, (struct sockaddr *)&peer);
403 break;
404 }
405 amount += size;
406 } while (size == segment_size && !intrflag);
407
408 abort:
409 /* ok to ack, since user has seen err msg */
410 ap->th_opcode = htons((u_short)ACK);
411 ap->th_block = htons(block);
412 (void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer,
413 peer.ss_len);
414 write_behind(file, convert); /* flush last buffer */
415
416 fclose(file);
417 stopclock();
418 if (amount > 0) {
419 if (intrflag)
420 putchar('\n');
421 printstats("Received", amount);
422 }
423 }
424
425 static int
cmpport(struct sockaddr * sa,struct sockaddr * sb)426 cmpport(struct sockaddr *sa, struct sockaddr *sb)
427 {
428 char a[NI_MAXSERV], b[NI_MAXSERV];
429 if (getnameinfo(sa, sa->sa_len, NULL, 0, a, sizeof(a), NI_NUMERICSERV))
430 return (0);
431 if (getnameinfo(sb, sb->sa_len, NULL, 0, b, sizeof(b), NI_NUMERICSERV))
432 return (0);
433 if (strcmp(a, b) != 0)
434 return (0);
435
436 return (1);
437 }
438
439 static int
makerequest(int request,const char * name,struct tftphdr * tp,const char * mode)440 makerequest(int request, const char *name, struct tftphdr *tp,
441 const char *mode)
442 {
443 char *cp;
444 int len, pktlen;
445 off_t fsize = 0;
446 struct stat st;
447
448 tp->th_opcode = htons((u_short)request);
449 cp = tp->th_stuff;
450 pktlen = packet_size - offsetof(struct tftphdr, th_stuff);
451 len = strlen(name) + 1;
452 strlcpy(cp, name, pktlen);
453 strlcpy(cp + len, mode, pktlen - len);
454 len += strlen(mode) + 1;
455
456 if (opt_tsize) {
457 if (request == WRQ) {
458 stat(name, &st);
459 fsize = st.st_size;
460 }
461 len += snprintf(cp + len, pktlen - len, "%s%c%lld%c",
462 options[OPT_TSIZE].o_type, 0, fsize, 0);
463 }
464 if (opt_tout)
465 len += snprintf(cp + len, pktlen - len, "%s%c%d%c",
466 options[OPT_TIMEOUT].o_type, 0, rexmtval, 0);
467 if (opt_blksize)
468 len += snprintf(cp + len, pktlen - len, "%s%c%d%c",
469 options[OPT_BLKSIZE].o_type, 0, opt_blksize, 0);
470
471 return (cp + len - (char *)tp);
472 }
473
474 /*
475 * Send a nak packet (error message).
476 * Error code passed in is one of the
477 * standard TFTP codes, or a UNIX errno
478 * offset by 100.
479 */
480 static void
nak(int error,struct sockaddr * peer)481 nak(int error, struct sockaddr *peer)
482 {
483 struct errmsg *pe;
484 struct tftphdr *tp;
485 int length;
486
487 tp = (struct tftphdr *)ackbuf;
488 tp->th_opcode = htons((u_short)ERROR);
489 tp->th_code = htons((u_short)error);
490 for (pe = errmsgs; pe->e_code >= 0; pe++)
491 if (pe->e_code == error)
492 break;
493 if (pe->e_code < 0) {
494 pe->e_msg = strerror(error - 100);
495 tp->th_code = EUNDEF;
496 }
497 length = strlcpy(tp->th_msg, pe->e_msg, packet_size) + 5;
498 if (length > packet_size)
499 length = packet_size;
500 if (trace)
501 tpacket("sent", tp, length);
502 if (sendto(f, ackbuf, length, 0, peer,
503 peer->sa_len) != length)
504 warn("nak");
505 }
506
507 static void
tpacket(const char * s,struct tftphdr * tp,int n)508 tpacket(const char *s, struct tftphdr *tp, int n)
509 {
510 char *cp, *file;
511 static char *opcodes[] =
512 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
513
514 u_short op = ntohs(tp->th_opcode);
515
516 if (op < RRQ || op > OACK)
517 printf("%s opcode=%x ", s, op);
518 else
519 printf("%s %s ", s, opcodes[op]);
520
521 switch (op) {
522 case RRQ:
523 case WRQ:
524 n -= 2;
525 file = cp = tp->th_stuff;
526 cp = strchr(cp, '\0');
527 printf("<file=%s, mode=%s", file, cp + 1);
528 if (has_options)
529 oack(tp, n, 1);
530 printf(">\n");
531 break;
532 case DATA:
533 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
534 break;
535 case ACK:
536 printf("<block=%d>\n", ntohs(tp->th_block));
537 break;
538 case ERROR:
539 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
540 break;
541 case OACK:
542 printf("<");
543 oack(tp, n, 1);
544 printf(">\n");
545 break;
546 }
547 }
548
549 static void
startclock(void)550 startclock(void)
551 {
552 clock_gettime(CLOCK_MONOTONIC, &tstart);
553 }
554
555 static void
stopclock(void)556 stopclock(void)
557 {
558 clock_gettime(CLOCK_MONOTONIC, &tstop);
559 }
560
561 static void
printstats(const char * direction,unsigned long amount)562 printstats(const char *direction, unsigned long amount)
563 {
564 double delta;
565
566 /* compute delta in 1/10's second units */
567 delta = ((tstop.tv_sec * 10.) + (tstop.tv_nsec / 100000000)) -
568 ((tstart.tv_sec * 10.) + (tstart.tv_nsec / 100000000));
569 delta = delta / 10.; /* back to seconds */
570 printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
571 if (verbose)
572 printf(" [%.0f bits/sec]", (amount * 8.) / delta);
573 putchar('\n');
574 }
575
576 static void
printtimeout(void)577 printtimeout(void)
578 {
579 printf("Transfer timed out.\n");
580 }
581
582 static void
oack(struct tftphdr * tp,int size,int trace)583 oack(struct tftphdr *tp, int size, int trace)
584 {
585 int i, len, off;
586 char *opt, *val;
587
588 u_short op = ntohs(tp->th_opcode);
589
590 opt = tp->th_u.tu_stuff;
591 val = tp->th_u.tu_stuff;
592
593 if (op == RRQ || op == WRQ) {
594 len = strlen(opt) + 1;
595 opt = strchr(opt, '\0');
596 opt++;
597 len += strlen(opt) + 1;
598 opt = strchr(opt, '\0');
599 opt++;
600 val = opt;
601 off = len;
602 if (trace)
603 printf(", ");
604 } else
605 off = 2;
606
607 for (i = off, len = 0; i < size - 1; i++) {
608 if (*val != '\0') {
609 val++;
610 continue;
611 }
612 /* got option and value */
613 val++;
614 if (trace)
615 printf("%s=%s", opt, val);
616 else
617 if (oack_set(opt, val) == -1)
618 break;
619 len = strlen(val) + 1;
620 val += len;
621 opt = val;
622 i += len;
623 if (trace && i < size - 1)
624 printf(", ");
625 }
626 }
627
628 int
oack_set(const char * option,const char * value)629 oack_set(const char *option, const char *value)
630 {
631 int i, n;
632 const char *errstr;
633 struct sockaddr_storage peer;
634 memcpy(&peer, &peeraddr, peeraddr.ss_len);
635
636 for (i = 0; options[i].o_type != NULL; i++) {
637 if (!strcasecmp(options[i].o_type, option)) {
638 if (i == OPT_TSIZE) {
639 /* XXX verify OACK response */
640 }
641 if (i == OPT_TIMEOUT) {
642 /* verify OACK response */
643 n = strtonum(value, TIMEOUT_MIN, TIMEOUT_MAX,
644 &errstr);
645 if (errstr || rexmtval != n ||
646 opt_tout == 0) {
647 nak(EOPTNEG, (struct sockaddr *)&peer);
648 intrflag = 1;
649 return (-1);
650 }
651 /* OK */
652 }
653 if (i == OPT_BLKSIZE) {
654 /* verify OACK response */
655 n = strtonum(value, SEGSIZE_MIN, SEGSIZE_MAX,
656 &errstr);
657 if (errstr || opt_blksize != n ||
658 opt_blksize == 0) {
659 nak(EOPTNEG, (struct sockaddr *)&peer);
660 intrflag = 1;
661 return (-1);
662 }
663 /* OK, set option */
664 segment_size = n;
665 packet_size = segment_size + 4;
666 }
667 }
668 }
669
670 return (1);
671 }
672