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