tftp.c (1a0fda2b547365c9453523592a445dfe21266d4b) tftp.c (752fa694029c20397f7928fa5f6b80f787677be2)
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

--- 31 unchanged lines hidden (view full) ---

40#include <sys/cdefs.h>
41__FBSDID("$FreeBSD$");
42
43/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
44
45/*
46 * TFTP User Program -- Protocol Machines
47 */
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

--- 31 unchanged lines hidden (view full) ---

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