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