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