1 /*
2 * Copyright (C) 2008 Edwin Groothuis. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32
33 #include <netinet/in.h>
34 #include <arpa/tftp.h>
35 #include <arpa/inet.h>
36
37 #include <errno.h>
38 #include <setjmp.h>
39 #include <signal.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <syslog.h>
44 #include <unistd.h>
45
46 #include "tftp-file.h"
47 #include "tftp-io.h"
48 #include "tftp-utils.h"
49 #include "tftp-options.h"
50
51 struct sockaddr_storage peer_sock;
52 struct sockaddr_storage me_sock;
53
54 static int send_packet(int peer, uint16_t block, char *pkt, int size);
55
56 static struct errmsg {
57 int e_code;
58 const char *e_msg;
59 } errmsgs[] = {
60 { EUNDEF, "Undefined error code" },
61 { ENOTFOUND, "File not found" },
62 { EACCESS, "Access violation" },
63 { ENOSPACE, "Disk full or allocation exceeded" },
64 { EBADOP, "Illegal TFTP operation" },
65 { EBADID, "Unknown transfer ID" },
66 { EEXISTS, "File already exists" },
67 { ENOUSER, "No such user" },
68 { EOPTNEG, "Option negotiation" },
69 { -1, NULL }
70 };
71
72 #define DROPPACKET(s) \
73 if (packetdroppercentage != 0 && \
74 random()%100 < packetdroppercentage) { \
75 tftp_log(LOG_DEBUG, "Artificial packet drop in %s", s); \
76 return; \
77 }
78 #define DROPPACKETn(s,n) \
79 if (packetdroppercentage != 0 && \
80 random()%100 < packetdroppercentage) { \
81 tftp_log(LOG_DEBUG, "Artificial packet drop in %s", s); \
82 return (n); \
83 }
84
85 const char *
errtomsg(int error)86 errtomsg(int error)
87 {
88 static char ebuf[40];
89 struct errmsg *pe;
90
91 if (error == 0)
92 return ("success");
93 for (pe = errmsgs; pe->e_code >= 0; pe++)
94 if (pe->e_code == error)
95 return (pe->e_msg);
96 snprintf(ebuf, sizeof(ebuf), "error %d", error);
97 return (ebuf);
98 }
99
100 static int
send_packet(int peer,uint16_t block,char * pkt,int size)101 send_packet(int peer, uint16_t block, char *pkt, int size)
102 {
103 int i;
104 int t = 1;
105
106 for (i = 0; i < 12 ; i++) {
107 DROPPACKETn("send_packet", 0);
108
109 if (sendto(peer, pkt, size, 0, (struct sockaddr *)&peer_sock,
110 peer_sock.ss_len) == size) {
111 if (i)
112 tftp_log(LOG_ERR,
113 "%s block %d, attempt %d successful",
114 packettype(ntohs(((struct tftphdr *)
115 (pkt))->th_opcode)), block, i);
116 return (0);
117 }
118 tftp_log(LOG_ERR,
119 "%s block %d, attempt %d failed (Error %d: %s)",
120 packettype(ntohs(((struct tftphdr *)(pkt))->th_opcode)),
121 block, i, errno, strerror(errno));
122 sleep(t);
123 if (t < 32)
124 t <<= 1;
125 }
126 tftp_log(LOG_ERR, "send_packet: %s", strerror(errno));
127 return (1);
128 }
129
130 /*
131 * Send an ERROR packet (error message).
132 * Error code passed in is one of the
133 * standard TFTP codes, or a UNIX errno
134 * offset by 100.
135 */
136 void
send_error(int peer,int error)137 send_error(int peer, int error)
138 {
139 struct tftphdr *tp;
140 int length;
141 struct errmsg *pe;
142 char buf[MAXPKTSIZE];
143
144 if (debug&DEBUG_PACKETS)
145 tftp_log(LOG_DEBUG, "Sending ERROR %d", error);
146
147 DROPPACKET("send_error");
148
149 tp = (struct tftphdr *)buf;
150 tp->th_opcode = htons((u_short)ERROR);
151 tp->th_code = htons((u_short)error);
152 for (pe = errmsgs; pe->e_code >= 0; pe++)
153 if (pe->e_code == error)
154 break;
155 if (pe->e_code < 0) {
156 pe->e_msg = strerror(error - 100);
157 tp->th_code = EUNDEF; /* set 'undef' errorcode */
158 }
159 strcpy(tp->th_msg, pe->e_msg);
160 length = strlen(pe->e_msg);
161 tp->th_msg[length] = '\0';
162 length += 5;
163
164 if (debug&DEBUG_PACKETS)
165 tftp_log(LOG_DEBUG, "Sending ERROR %d: %s", error, tp->th_msg);
166
167 if (sendto(peer, buf, length, 0,
168 (struct sockaddr *)&peer_sock, peer_sock.ss_len) != length)
169 tftp_log(LOG_ERR, "send_error: %s", strerror(errno));
170 }
171
172 /*
173 * Send an WRQ packet (write request).
174 */
175 int
send_wrq(int peer,char * filename,char * mode)176 send_wrq(int peer, char *filename, char *mode)
177 {
178 int n;
179 struct tftphdr *tp;
180 char *bp;
181 char buf[MAXPKTSIZE];
182 int size;
183
184 if (debug&DEBUG_PACKETS)
185 tftp_log(LOG_DEBUG, "Sending WRQ: filename: '%s', mode '%s'",
186 filename, mode
187 );
188
189 DROPPACKETn("send_wrq", 1);
190
191 tp = (struct tftphdr *)buf;
192 tp->th_opcode = htons((u_short)WRQ);
193 size = 2;
194
195 bp = tp->th_stuff;
196 strcpy(bp, filename);
197 bp += strlen(filename);
198 *bp = 0;
199 bp++;
200 size += strlen(filename) + 1;
201
202 strcpy(bp, mode);
203 bp += strlen(mode);
204 *bp = 0;
205 bp++;
206 size += strlen(mode) + 1;
207
208 if (options_rfc_enabled)
209 size += make_options(peer, bp, sizeof(buf) - size);
210
211 n = sendto(peer, buf, size, 0,
212 (struct sockaddr *)&peer_sock, peer_sock.ss_len);
213 if (n != size) {
214 tftp_log(LOG_ERR, "send_wrq: %s", strerror(errno));
215 return (1);
216 }
217 return (0);
218 }
219
220 /*
221 * Send an RRQ packet (write request).
222 */
223 int
send_rrq(int peer,char * filename,char * mode)224 send_rrq(int peer, char *filename, char *mode)
225 {
226 int n;
227 struct tftphdr *tp;
228 char *bp;
229 char buf[MAXPKTSIZE];
230 int size;
231
232 if (debug&DEBUG_PACKETS)
233 tftp_log(LOG_DEBUG, "Sending RRQ: filename: '%s', mode '%s'",
234 filename, mode
235 );
236
237 DROPPACKETn("send_rrq", 1);
238
239 tp = (struct tftphdr *)buf;
240 tp->th_opcode = htons((u_short)RRQ);
241 size = 2;
242
243 bp = tp->th_stuff;
244 strcpy(bp, filename);
245 bp += strlen(filename);
246 *bp = 0;
247 bp++;
248 size += strlen(filename) + 1;
249
250 strcpy(bp, mode);
251 bp += strlen(mode);
252 *bp = 0;
253 bp++;
254 size += strlen(mode) + 1;
255
256 if (options_rfc_enabled) {
257 options[OPT_TSIZE].o_request = strdup("0");
258 size += make_options(peer, bp, sizeof(buf) - size);
259 }
260
261 n = sendto(peer, buf, size, 0,
262 (struct sockaddr *)&peer_sock, peer_sock.ss_len);
263 if (n != size) {
264 tftp_log(LOG_ERR, "send_rrq: %d %s", n, strerror(errno));
265 return (1);
266 }
267 return (0);
268 }
269
270 /*
271 * Send an OACK packet (option acknowledgement).
272 */
273 int
send_oack(int peer)274 send_oack(int peer)
275 {
276 struct tftphdr *tp;
277 int size, i, n;
278 char *bp;
279 char buf[MAXPKTSIZE];
280
281 if (debug&DEBUG_PACKETS)
282 tftp_log(LOG_DEBUG, "Sending OACK");
283
284 DROPPACKETn("send_oack", 0);
285
286 /*
287 * Send back an options acknowledgement (only the ones with
288 * a reply for)
289 */
290 tp = (struct tftphdr *)buf;
291 bp = buf + 2;
292 size = sizeof(buf) - 2;
293 tp->th_opcode = htons((u_short)OACK);
294 for (i = 0; options[i].o_type != NULL; i++) {
295 if (options[i].o_reply != NULL) {
296 n = snprintf(bp, size, "%s%c%s", options[i].o_type,
297 0, options[i].o_reply);
298 bp += n+1;
299 size -= n+1;
300 if (size < 0) {
301 tftp_log(LOG_ERR, "oack: buffer overflow");
302 exit(1);
303 }
304 }
305 }
306 size = bp - buf;
307
308 if (sendto(peer, buf, size, 0,
309 (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
310 tftp_log(LOG_INFO, "send_oack: %s", strerror(errno));
311 return (1);
312 }
313
314 return (0);
315 }
316
317 /*
318 * Send an ACK packet (acknowledgement).
319 */
320 int
send_ack(int fp,uint16_t block)321 send_ack(int fp, uint16_t block)
322 {
323 struct tftphdr *tp;
324 int size;
325 char buf[MAXPKTSIZE];
326
327 if (debug&DEBUG_PACKETS)
328 tftp_log(LOG_DEBUG, "Sending ACK for block %d", block);
329
330 DROPPACKETn("send_ack", 0);
331
332 tp = (struct tftphdr *)buf;
333 size = sizeof(buf) - 2;
334 tp->th_opcode = htons((u_short)ACK);
335 tp->th_block = htons((u_short)block);
336 size = 4;
337
338 if (sendto(fp, buf, size, 0,
339 (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
340 tftp_log(LOG_INFO, "send_ack: %s", strerror(errno));
341 return (1);
342 }
343
344 return (0);
345 }
346
347 /*
348 * Send a DATA packet
349 */
350 int
send_data(int peer,uint16_t block,char * data,int size)351 send_data(int peer, uint16_t block, char *data, int size)
352 {
353 char buf[MAXPKTSIZE];
354 struct tftphdr *pkt;
355 int n;
356
357 if (debug&DEBUG_PACKETS)
358 tftp_log(LOG_DEBUG, "Sending DATA packet %d of %d bytes",
359 block, size);
360
361 DROPPACKETn("send_data", 0);
362
363 pkt = (struct tftphdr *)buf;
364
365 pkt->th_opcode = htons((u_short)DATA);
366 pkt->th_block = htons((u_short)block);
367 memcpy(pkt->th_data, data, size);
368
369 n = send_packet(peer, block, (char *)pkt, size + 4);
370 return (n);
371 }
372
373
374 /*
375 * Receive a packet
376 */
377 static jmp_buf timeoutbuf;
378
379 static void
timeout(int sig __unused)380 timeout(int sig __unused)
381 {
382
383 /* tftp_log(LOG_DEBUG, "Timeout\n"); Inside a signal handler... */
384 longjmp(timeoutbuf, 1);
385 }
386
387 int
receive_packet(int peer,char * data,int size,struct sockaddr_storage * from,int thistimeout)388 receive_packet(int peer, char *data, int size, struct sockaddr_storage *from,
389 int thistimeout)
390 {
391 struct tftphdr *pkt;
392 struct sockaddr_storage from_local;
393 struct sockaddr_storage *pfrom;
394 socklen_t fromlen;
395 int n;
396 static int waiting;
397
398 if (debug&DEBUG_PACKETS)
399 tftp_log(LOG_DEBUG,
400 "Waiting %d seconds for packet", timeoutpacket);
401
402 pkt = (struct tftphdr *)data;
403
404 waiting = 0;
405 signal(SIGALRM, timeout);
406 setjmp(timeoutbuf);
407 alarm(thistimeout);
408
409 if (waiting > 0) {
410 alarm(0);
411 return (RP_TIMEOUT);
412 }
413
414 if (waiting > 0) {
415 tftp_log(LOG_ERR, "receive_packet: timeout");
416 alarm(0);
417 return (RP_TIMEOUT);
418 }
419
420 waiting++;
421 pfrom = (from == NULL) ? &from_local : from;
422 fromlen = sizeof(*pfrom);
423 n = recvfrom(peer, data, size, 0, (struct sockaddr *)pfrom, &fromlen);
424
425 alarm(0);
426
427 DROPPACKETn("receive_packet", RP_TIMEOUT);
428
429 if (n < 0) {
430 tftp_log(LOG_ERR, "receive_packet: timeout");
431 return (RP_TIMEOUT);
432 }
433
434 alarm(0);
435
436 if (n < 0) {
437 /* No idea what could have happened if it isn't a timeout */
438 tftp_log(LOG_ERR, "receive_packet: %s", strerror(errno));
439 return (RP_RECVFROM);
440 }
441 if (n < 4) {
442 tftp_log(LOG_ERR,
443 "receive_packet: packet too small (%d bytes)", n);
444 return (RP_TOOSMALL);
445 }
446
447 pkt->th_opcode = ntohs((u_short)pkt->th_opcode);
448 if (pkt->th_opcode == DATA ||
449 pkt->th_opcode == ACK)
450 pkt->th_block = ntohs((u_short)pkt->th_block);
451
452 if (pkt->th_opcode == DATA && n > pktsize) {
453 tftp_log(LOG_ERR, "receive_packet: packet too big");
454 return (RP_TOOBIG);
455 }
456
457 if (((struct sockaddr_in *)(pfrom))->sin_addr.s_addr !=
458 ((struct sockaddr_in *)(&peer_sock))->sin_addr.s_addr) {
459 tftp_log(LOG_ERR,
460 "receive_packet: received packet from wrong source");
461 return (RP_WRONGSOURCE);
462 }
463
464 if (pkt->th_opcode == ERROR) {
465 tftp_log(pkt->th_code == EUNDEF ? LOG_DEBUG : LOG_ERR,
466 "Got ERROR packet: %s", pkt->th_msg);
467 return (RP_ERROR);
468 }
469
470 if (debug&DEBUG_PACKETS)
471 tftp_log(LOG_DEBUG, "Received %d bytes in a %s packet",
472 n, packettype(pkt->th_opcode));
473
474 return n - 4;
475 }
476