]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libexec/tftpd/tftp-io.c
ident(1): Normalizing date format
[FreeBSD/FreeBSD.git] / libexec / tftpd / tftp-io.c
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$");
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 *
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
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
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
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
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
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
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
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
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
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 }