1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39 /*
40 * TFTP User Program -- Protocol Machines
41 */
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/time.h>
45 #include <sys/stat.h>
46
47 #include <signal.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <stdbool.h>
51 #include <unistd.h>
52 #include <errno.h>
53 #include <string.h>
54 #include <stddef.h>
55 #include <inttypes.h>
56
57 #include "tftpcommon.h"
58 #include "tftpprivate.h"
59
60 static char *blksize_str(void);
61 static char *timeout_str(void);
62 static char *tsize_str(void);
63 static int blksize_handler(char *);
64 static int timeout_handler(char *);
65 static int tsize_handler(char *);
66 static int add_options(char *, char *);
67 static int process_oack(tftpbuf *, int);
68 static void nak(int);
69 static void startclock(void);
70 static void stopclock(void);
71 static void printstats(char *, off_t);
72 static int makerequest(int, char *, struct tftphdr *, char *);
73 static void tpacket(char *, struct tftphdr *, int);
74
75 static struct options {
76 char *opt_name;
77 char *(*opt_str)(void);
78 int (*opt_handler)(char *);
79 } options[] = {
80 { "blksize", blksize_str, blksize_handler },
81 { "timeout", timeout_str, timeout_handler },
82 { "tsize", tsize_str, tsize_handler },
83 { NULL }
84 };
85
86 static char optbuf[MAX_OPTVAL_LEN];
87 static bool tsize_set;
88
89 static tftpbuf ackbuf;
90 static int timeout;
91 static off_t tsize;
92 static jmp_buf timeoutbuf;
93
94 int blocksize = SEGSIZE; /* Number of data bytes in a DATA packet */
95
96 /*ARGSUSED*/
97 static void
timer(int signum)98 timer(int signum)
99 {
100 timeout += rexmtval;
101 if (timeout >= maxtimeout) {
102 (void) fputs("Transfer timed out.\n", stderr);
103 longjmp(toplevel, -1);
104 }
105 (void) signal(SIGALRM, timer);
106 longjmp(timeoutbuf, 1);
107 }
108
109 /*
110 * Send the requested file.
111 */
112 void
tftp_sendfile(int fd,char * name,char * mode)113 tftp_sendfile(int fd, char *name, char *mode)
114 {
115 struct tftphdr *ap; /* data and ack packets */
116 struct tftphdr *dp;
117 int n;
118 volatile int count = 0, size;
119 volatile ushort_t block = 0;
120 volatile off_t amount = 0;
121 struct sockaddr_in6 from;
122 socklen_t fromlen;
123 int convert; /* true if doing nl->crlf conversion */
124 FILE *file;
125 struct stat statb;
126 int errcode;
127
128 startclock(); /* start stat's clock */
129 dp = r_init(); /* reset fillbuf/read-ahead code */
130 ap = &ackbuf.tb_hdr;
131 file = fdopen(fd, "r");
132 convert = (strcmp(mode, "netascii") == 0);
133
134 tsize_set = ((tsize_opt != 0) && !convert && (fstat(fd, &statb) == 0));
135 if (tsize_set)
136 tsize = statb.st_size;
137
138 do {
139 (void) signal(SIGALRM, timer);
140 if (count == 0) {
141 if ((size = makerequest(WRQ, name, dp, mode)) == -1) {
142 (void) fprintf(stderr,
143 "tftp: Error: Write request packet too "
144 "big\n");
145 (void) fclose(file);
146 return;
147 }
148 size -= 4;
149 } else {
150 size = readit(file, &dp, convert);
151 if (size < 0) {
152 nak(errno + 100);
153 break;
154 }
155 dp->th_opcode = htons((ushort_t)DATA);
156 dp->th_block = htons((ushort_t)block);
157 }
158 timeout = 0;
159 (void) setjmp(timeoutbuf);
160 if (trace)
161 tpacket("sent", dp, size + 4);
162 n = sendto(f, dp, size + 4, 0,
163 (struct sockaddr *)&sin6, sizeof (sin6));
164 if (n != size + 4) {
165 perror("tftp: sendto");
166 goto abort;
167 }
168 /* Can't read-ahead first block as OACK may change blocksize */
169 if (count != 0)
170 read_ahead(file, convert);
171 (void) alarm(rexmtval);
172 for (; ; ) {
173 (void) sigrelse(SIGALRM);
174 do {
175 fromlen = (socklen_t)sizeof (from);
176 n = recvfrom(f, ackbuf.tb_data,
177 sizeof (ackbuf.tb_data), 0,
178 (struct sockaddr *)&from, &fromlen);
179 if (n < 0) {
180 perror("tftp: recvfrom");
181 goto abort;
182 }
183 } while (n < offsetof(struct tftphdr, th_data));
184 (void) sighold(SIGALRM);
185 sin6.sin6_port = from.sin6_port; /* added */
186 if (trace)
187 tpacket("received", ap, n);
188 /* should verify packet came from server */
189 ap->th_opcode = ntohs(ap->th_opcode);
190 if (ap->th_opcode == ERROR) {
191 ap->th_code = ntohs(ap->th_code);
192 (void) fprintf(stderr,
193 "Error code %d", ap->th_code);
194 if (n > offsetof(struct tftphdr, th_data))
195 (void) fprintf(stderr, ": %.*s", n -
196 offsetof(struct tftphdr, th_data),
197 ap->th_msg);
198 (void) fputc('\n', stderr);
199 goto abort;
200 }
201 if ((count == 0) && (ap->th_opcode == OACK)) {
202 errcode = process_oack(&ackbuf, n);
203 if (errcode >= 0) {
204 nak(errcode);
205 (void) fputs("Rejected OACK\n",
206 stderr);
207 goto abort;
208 }
209 break;
210 }
211 if (ap->th_opcode == ACK) {
212 ap->th_block = ntohs(ap->th_block);
213 if (ap->th_block == block) {
214 break;
215 }
216 /*
217 * Never resend the current DATA packet on
218 * receipt of a duplicate ACK, doing so would
219 * cause the "Sorcerer's Apprentice Syndrome".
220 */
221 }
222 }
223 cancel_alarm();
224 if (count > 0)
225 amount += size;
226 block++;
227 count++;
228 } while (size == blocksize || count == 1);
229 abort:
230 cancel_alarm();
231 (void) fclose(file);
232 stopclock();
233 if (amount > 0)
234 printstats("Sent", amount);
235 }
236
237 /*
238 * Receive a file.
239 */
240 void
tftp_recvfile(int fd,char * name,char * mode)241 tftp_recvfile(int fd, char *name, char *mode)
242 {
243 struct tftphdr *ap;
244 struct tftphdr *dp;
245 volatile ushort_t block = 1;
246 int n;
247 volatile int size;
248 volatile unsigned long amount = 0;
249 struct sockaddr_in6 from;
250 socklen_t fromlen;
251 volatile bool firsttrip = true;
252 FILE *file;
253 int convert; /* true if converting crlf -> lf */
254 int errcode;
255
256 startclock();
257 dp = w_init();
258 ap = &ackbuf.tb_hdr;
259 file = fdopen(fd, "w");
260 convert = (strcmp(mode, "netascii") == 0);
261
262 tsize_set = (tsize_opt != 0);
263 if (tsize_set)
264 tsize = 0;
265
266 if ((size = makerequest(RRQ, name, ap, mode)) == -1) {
267 (void) fprintf(stderr,
268 "tftp: Error: Read request packet too big\n");
269 (void) fclose(file);
270 return;
271 }
272
273 do {
274 (void) signal(SIGALRM, timer);
275 if (firsttrip) {
276 firsttrip = false;
277 } else {
278 ap->th_opcode = htons((ushort_t)ACK);
279 ap->th_block = htons((ushort_t)(block));
280 size = 4;
281 block++;
282 }
283
284 send_oack_ack:
285 timeout = 0;
286 (void) setjmp(timeoutbuf);
287 send_ack:
288 if (trace)
289 tpacket("sent", ap, size);
290 if (sendto(f, ackbuf.tb_data, size, 0, (struct sockaddr *)&sin6,
291 sizeof (sin6)) != size) {
292 (void) alarm(0);
293 perror("tftp: sendto");
294 goto abort;
295 }
296 if (write_behind(file, convert) < 0) {
297 nak(errno + 100);
298 goto abort;
299 }
300 (void) alarm(rexmtval);
301 for (; ; ) {
302 (void) sigrelse(SIGALRM);
303 do {
304 fromlen = (socklen_t)sizeof (from);
305 n = recvfrom(f, dp, blocksize + 4, 0,
306 (struct sockaddr *)&from, &fromlen);
307 if (n < 0) {
308 perror("tftp: recvfrom");
309 goto abort;
310 }
311 } while (n < offsetof(struct tftphdr, th_data));
312 (void) sighold(SIGALRM);
313 sin6.sin6_port = from.sin6_port; /* added */
314 if (trace)
315 tpacket("received", dp, n);
316 /* should verify client address */
317 dp->th_opcode = ntohs(dp->th_opcode);
318 if (dp->th_opcode == ERROR) {
319 dp->th_code = ntohs(dp->th_code);
320 (void) fprintf(stderr, "Error code %d",
321 dp->th_code);
322 if (n > offsetof(struct tftphdr, th_data))
323 (void) fprintf(stderr, ": %.*s", n -
324 offsetof(struct tftphdr, th_data),
325 dp->th_msg);
326 (void) fputc('\n', stderr);
327 goto abort;
328 }
329 if ((block == 1) && (dp->th_opcode == OACK)) {
330 errcode = process_oack((tftpbuf *)dp, n);
331 if (errcode >= 0) {
332 cancel_alarm();
333 nak(errcode);
334 (void) fputs("Rejected OACK\n",
335 stderr);
336 (void) fclose(file);
337 return;
338 }
339 ap->th_opcode = htons((ushort_t)ACK);
340 ap->th_block = htons(0);
341 size = 4;
342 goto send_oack_ack;
343 }
344 if (dp->th_opcode == DATA) {
345 int j;
346
347 dp->th_block = ntohs(dp->th_block);
348 if (dp->th_block == block) {
349 break; /* have next packet */
350 }
351 /*
352 * On an error, try to synchronize
353 * both sides.
354 */
355 j = synchnet(f);
356 if (j < 0) {
357 perror("tftp: recvfrom");
358 goto abort;
359 }
360 if ((j > 0) && trace) {
361 (void) printf("discarded %d packets\n",
362 j);
363 }
364 if (dp->th_block == (block-1)) {
365 goto send_ack; /* resend ack */
366 }
367 }
368 }
369 cancel_alarm();
370 size = writeit(file, &dp, n - 4, convert);
371 if (size < 0) {
372 nak(errno + 100);
373 goto abort;
374 }
375 amount += size;
376 } while (size == blocksize);
377
378 cancel_alarm();
379 if (write_behind(file, convert) < 0) { /* flush last buffer */
380 nak(errno + 100);
381 goto abort;
382 }
383 n = fclose(file);
384 file = NULL;
385 if (n == EOF) {
386 nak(errno + 100);
387 goto abort;
388 }
389
390 /* ok to ack, since user has seen err msg */
391 ap->th_opcode = htons((ushort_t)ACK);
392 ap->th_block = htons((ushort_t)block);
393 if (trace)
394 tpacket("sent", ap, 4);
395 if (sendto(f, ackbuf.tb_data, 4, 0,
396 (struct sockaddr *)&sin6, sizeof (sin6)) != 4)
397 perror("tftp: sendto");
398
399 abort:
400 cancel_alarm();
401 if (file != NULL)
402 (void) fclose(file);
403 stopclock();
404 if (amount > 0)
405 printstats("Received", amount);
406 }
407
408 static int
makerequest(int request,char * name,struct tftphdr * tp,char * mode)409 makerequest(int request, char *name, struct tftphdr *tp, char *mode)
410 {
411 char *cp, *cpend;
412 int len;
413
414 tp->th_opcode = htons((ushort_t)request);
415 cp = (char *)&tp->th_stuff;
416
417 /* Maximum size of a request packet is 512 bytes (RFC 2347) */
418 cpend = (char *)tp + SEGSIZE;
419
420 len = strlcpy(cp, name, cpend - cp) + 1;
421 cp += len;
422 if (cp > cpend)
423 return (-1);
424
425 len = strlcpy(cp, mode, cpend - cp) + 1;
426 cp += len;
427 if (cp > cpend)
428 return (-1);
429
430 len = add_options(cp, cpend);
431 if (len == -1)
432 return (-1);
433 cp += len;
434
435 return (cp - (char *)tp);
436 }
437
438 /*
439 * Return the blksize option value string to include in the request packet.
440 */
441 static char *
blksize_str(void)442 blksize_str(void)
443 {
444 blocksize = SEGSIZE;
445 if (blksize == 0)
446 return (NULL);
447
448 (void) snprintf(optbuf, sizeof (optbuf), "%d", blksize);
449 return (optbuf);
450 }
451
452 /*
453 * Return the timeout option value string to include in the request packet.
454 */
455 static char *
timeout_str(void)456 timeout_str(void)
457 {
458 if (srexmtval == 0)
459 return (NULL);
460
461 (void) snprintf(optbuf, sizeof (optbuf), "%d", srexmtval);
462 return (optbuf);
463 }
464
465 /*
466 * Return the tsize option value string to include in the request packet.
467 */
468 static char *
tsize_str(void)469 tsize_str(void)
470 {
471 if (tsize_set == false)
472 return (NULL);
473
474 (void) snprintf(optbuf, sizeof (optbuf), OFF_T_FMT, tsize);
475 return (optbuf);
476 }
477
478 /*
479 * Validate and action the blksize option value string from the OACK packet.
480 * Returns -1 on success or an error code on failure.
481 */
482 static int
blksize_handler(char * optstr)483 blksize_handler(char *optstr)
484 {
485 char *endp;
486 int value;
487
488 /* Make sure the option was requested */
489 if (blksize == 0)
490 return (EOPTNEG);
491 errno = 0;
492 value = (int)strtol(optstr, &endp, 10);
493 if (errno != 0 || value < MIN_BLKSIZE || value > blksize ||
494 *endp != '\0')
495 return (EOPTNEG);
496 blocksize = value;
497 return (-1);
498 }
499
500 /*
501 * Validate and action the timeout option value string from the OACK packet.
502 * Returns -1 on success or an error code on failure.
503 */
504 static int
timeout_handler(char * optstr)505 timeout_handler(char *optstr)
506 {
507 char *endp;
508 int value;
509
510 /* Make sure the option was requested */
511 if (srexmtval == 0)
512 return (EOPTNEG);
513 errno = 0;
514 value = (int)strtol(optstr, &endp, 10);
515 if (errno != 0 || value != srexmtval || *endp != '\0')
516 return (EOPTNEG);
517 /*
518 * Nothing to set, client and server retransmission intervals are
519 * set separately in the client.
520 */
521 return (-1);
522 }
523
524 /*
525 * Validate and action the tsize option value string from the OACK packet.
526 * Returns -1 on success or an error code on failure.
527 */
528 static int
tsize_handler(char * optstr)529 tsize_handler(char *optstr)
530 {
531 char *endp;
532 longlong_t value;
533
534 /* Make sure the option was requested */
535 if (tsize_set == false)
536 return (EOPTNEG);
537 errno = 0;
538 value = strtoll(optstr, &endp, 10);
539 if (errno != 0 || value < 0 || *endp != '\0')
540 return (EOPTNEG);
541 #if _FILE_OFFSET_BITS == 32
542 if (value > MAXOFF_T)
543 return (ENOSPACE);
544 #endif
545 /*
546 * Don't bother checking the tsize value we specified in a write
547 * request is echoed back in the OACK.
548 */
549 if (tsize == 0)
550 tsize = value;
551 return (-1);
552 }
553
554 /*
555 * Add TFTP options to a request packet.
556 */
557 static int
add_options(char * obuf,char * obufend)558 add_options(char *obuf, char *obufend)
559 {
560 int i;
561 char *cp, *ostr;
562
563 cp = obuf;
564 for (i = 0; options[i].opt_name != NULL; i++) {
565 ostr = options[i].opt_str();
566 if (ostr != NULL) {
567 cp += strlcpy(cp, options[i].opt_name, obufend - cp)
568 + 1;
569 if (cp > obufend)
570 return (-1);
571
572 cp += strlcpy(cp, ostr, obufend - cp) + 1;
573 if (cp > obufend)
574 return (-1);
575 }
576 }
577 return (cp - obuf);
578 }
579
580 /*
581 * Process OACK packet sent by server in response to options in the request
582 * packet. Returns -1 on success or an error code on failure.
583 */
584 static int
process_oack(tftpbuf * oackbuf,int n)585 process_oack(tftpbuf *oackbuf, int n)
586 {
587 char *cp, *oackend, *optname, *optval;
588 struct tftphdr *oackp;
589 int i, errcode;
590
591 oackp = &oackbuf->tb_hdr;
592 cp = (char *)&oackp->th_stuff;
593 oackend = (char *)oackbuf + n;
594
595 while (cp < oackend) {
596 optname = cp;
597 if ((optval = next_field(optname, oackend)) == NULL)
598 return (EOPTNEG);
599 if ((cp = next_field(optval, oackend)) == NULL)
600 return (EOPTNEG);
601 for (i = 0; options[i].opt_name != NULL; i++) {
602 if (strcasecmp(optname, options[i].opt_name) == 0)
603 break;
604 }
605 if (options[i].opt_name == NULL)
606 return (EOPTNEG);
607 errcode = options[i].opt_handler(optval);
608 if (errcode >= 0)
609 return (errcode);
610 }
611 return (-1);
612 }
613
614 /*
615 * Send a nak packet (error message).
616 * Error code passed in is one of the
617 * standard TFTP codes, or a UNIX errno
618 * offset by 100.
619 */
620 static void
nak(int error)621 nak(int error)
622 {
623 struct tftphdr *tp;
624 int length;
625 struct errmsg *pe;
626
627 tp = &ackbuf.tb_hdr;
628 tp->th_opcode = htons((ushort_t)ERROR);
629 tp->th_code = htons((ushort_t)error);
630 for (pe = errmsgs; pe->e_code >= 0; pe++)
631 if (pe->e_code == error)
632 break;
633 if (pe->e_code < 0) {
634 pe->e_msg = strerror(error - 100);
635 tp->th_code = EUNDEF;
636 }
637 (void) strlcpy(tp->th_msg, pe->e_msg,
638 sizeof (ackbuf) - sizeof (struct tftphdr));
639 length = strlen(pe->e_msg) + 4;
640 if (trace)
641 tpacket("sent", tp, length);
642 if (sendto(f, ackbuf.tb_data, length, 0,
643 (struct sockaddr *)&sin6, sizeof (sin6)) != length)
644 perror("nak");
645 }
646
647 static void
tpacket(char * s,struct tftphdr * tp,int n)648 tpacket(char *s, struct tftphdr *tp, int n)
649 {
650 static char *opcodes[] = {
651 "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK"
652 };
653 char *cp, *file, *mode;
654 ushort_t op = ntohs(tp->th_opcode);
655 char *tpend;
656
657 if (op < RRQ || op > OACK)
658 (void) printf("%s opcode=%x ", s, op);
659 else
660 (void) printf("%s %s ", s, opcodes[op]);
661
662 switch (op) {
663 case RRQ:
664 case WRQ:
665 tpend = (char *)tp + n;
666 n -= sizeof (tp->th_opcode);
667 file = (char *)&tp->th_stuff;
668 if ((mode = next_field(file, tpend)) == NULL) {
669 (void) printf("<file=%.*s>\n", n, file);
670 break;
671 }
672 n -= mode - file;
673 if ((cp = next_field(mode, tpend)) == NULL) {
674 (void) printf("<file=%s, mode=%.*s>\n", file, n, mode);
675 break;
676 }
677 (void) printf("<file=%s, mode=%s", file, mode);
678 n -= cp - mode;
679 if (n > 0) {
680 (void) printf(", options: ");
681 print_options(stdout, cp, n);
682 }
683 (void) puts(">");
684 break;
685
686 case DATA:
687 (void) printf("<block=%d, %d bytes>\n", ntohs(tp->th_block),
688 n - sizeof (tp->th_opcode) - sizeof (tp->th_block));
689 break;
690
691 case ACK:
692 (void) printf("<block=%d>\n", ntohs(tp->th_block));
693 break;
694
695 case OACK:
696 (void) printf("<options: ");
697 print_options(stdout, (char *)&tp->th_stuff,
698 n - sizeof (tp->th_opcode));
699 (void) puts(">");
700 break;
701
702 case ERROR:
703 (void) printf("<code=%d", ntohs(tp->th_code));
704 n = n - sizeof (tp->th_opcode) - sizeof (tp->th_code);
705 if (n > 0)
706 (void) printf(", msg=%.*s", n, tp->th_msg);
707 (void) puts(">");
708 break;
709 }
710 }
711
712 static hrtime_t tstart, tstop;
713
714 static void
startclock(void)715 startclock(void)
716 {
717 tstart = gethrtime();
718 }
719
720 static void
stopclock(void)721 stopclock(void)
722 {
723 tstop = gethrtime();
724 }
725
726 static void
printstats(char * direction,off_t amount)727 printstats(char *direction, off_t amount)
728 {
729 hrtime_t delta, tenths;
730
731 delta = tstop - tstart;
732 tenths = delta / (NANOSEC / 10);
733 (void) printf("%s " OFF_T_FMT " bytes in %" PRId64 ".%" PRId64
734 " seconds", direction, amount, tenths / 10, tenths % 10);
735 if (verbose)
736 (void) printf(" [%" PRId64 " bits/sec]\n",
737 ((hrtime_t)amount * 8 * NANOSEC) / delta);
738 else
739 (void) putchar('\n');
740 }
741