]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - libexec/tftpd/tftp-io.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 <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 *
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
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
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
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
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
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
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
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
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
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 }