blob: aab73dab208ae00bfa1eedb489eb7cc4199c61e3 [file] [log] [blame]
Simon Kelley832af0b2007-01-21 20:01:28 +00001/* dnsmasq is Copyright (c) 2000-2006 Simon Kelley
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11*/
12
13#include "dnsmasq.h"
14
15#ifdef HAVE_TFTP
16
17static void free_transfer(struct tftp_transfer *transfer);
18static ssize_t tftp_err(int err, char *packet, char *mess, char *file);
19static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
20static char *next(char **p, char *end);
21
22#define OP_RRQ 1
23#define OP_WRQ 2
24#define OP_DATA 3
25#define OP_ACK 4
26#define OP_ERR 5
27#define OP_OACK 6
28
29#define ERR_NOTDEF 0
30#define ERR_FNF 1
31#define ERR_PERM 2
32#define ERR_FULL 3
33#define ERR_ILL 4
34
35void tftp_request(struct listener *listen, struct daemon *daemon, time_t now)
36{
37 ssize_t len;
38 char *packet = daemon->packet;
39 char *filename, *mode, *p, *end, *opt;
40 struct stat statbuf;
41 struct sockaddr_in addr, peer;
42 struct msghdr msg;
43 struct cmsghdr *cmptr;
44 struct iovec iov;
45 struct ifreq ifr;
46 int is_err = 1, if_index = 0;
47 struct iname *tmp;
48 struct tftp_transfer *transfer, *t;
49 struct tftp_file *file;
50
51 union {
52 struct cmsghdr align; /* this ensures alignment */
53#ifdef HAVE_LINUX_NETWORK
54 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
55#else
56 char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
57#endif
58 } control_u;
59
60 msg.msg_controllen = sizeof(control_u);
61 msg.msg_control = control_u.control;
62 msg.msg_flags = 0;
63 msg.msg_name = &peer;
64 msg.msg_namelen = sizeof(peer);
65 msg.msg_iov = &iov;
66 msg.msg_iovlen = 1;
67
68 iov.iov_base = packet;
69 iov.iov_len = daemon->packet_buff_sz;
70
71 /* we overwrote the buffer... */
72 daemon->srv_save = NULL;
73
74 if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
75 return;
76
77 if (daemon->options & OPT_NOWILD)
78 addr = listen->iface->addr.in;
79 else
80 {
81 addr.sin_addr.s_addr = 0;
82
83#if defined(HAVE_LINUX_NETWORK)
84 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
85 if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
86 {
87 addr.sin_addr = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
88 if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
89 }
90 if (!(ifr.ifr_ifindex = if_index) ||
91 ioctl(listen->tftpfd, SIOCGIFNAME, &ifr) == -1)
92 return;
93
94#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
95 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
96 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
97 addr.sin_addr = *((struct in_addr *)CMSG_DATA(cmptr));
98 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
99 if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
100
101 if (if_index == 0 || !if_indextoname(if_index, ifr.ifr_name))
102 return;
103
104#endif
105
106 if (addr.sin_addr.s_addr == 0)
107 return;
108
109 if (!iface_check(daemon, AF_INET, (struct all_addr *)&addr, &ifr, &if_index))
110 return;
111
112 /* allowed interfaces are the same as for DHCP */
113 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
114 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
115 return;
116
117 }
118
119 /* tell kernel to use ephemeral port */
120 addr.sin_port = 0;
121 addr.sin_family = AF_INET;
122#ifdef HAVE_SOCKADDR_SA_LEN
123 addr.sin_len = sizeof(addr);
124#endif
125
126 if (!(transfer = malloc(sizeof(struct tftp_transfer))))
127 return;
128
129 if ((transfer->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
130 {
131 free(transfer);
132 return;
133 }
134
135 transfer->peer = peer;
136 transfer->timeout = now + 1;
137 transfer->backoff = 1;
138 transfer->block = 1;
139 transfer->blocksize = 512;
140 transfer->file = NULL;
141 transfer->opt_blocksize = transfer->opt_transize = 0;
142
143 if (bind(transfer->sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 ||
144 !fix_fd(transfer->sockfd))
145 {
146 free_transfer(transfer);
147 return;
148 }
149
150 p = packet + 2;
151 end = packet + len;
152
153 if (ntohs(*((unsigned short *)packet)) != OP_RRQ ||
154 !(filename = next(&p, end)) ||
155 !(mode = next(&p, end)) ||
156 strcasecmp(mode, "octet") != 0)
157 len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), inet_ntoa(peer.sin_addr));
158 else
159 {
160 while ((opt = next(&p, end)))
161 {
162 if (strcasecmp(opt, "blksize") == 0 &&
163 (opt = next(&p, end)))
164 {
165 transfer->blocksize = atoi(opt);
166 if (transfer->blocksize < 1)
167 transfer->blocksize = 1;
168 if (transfer->blocksize > (unsigned)daemon->packet_buff_sz - 4)
169 transfer->blocksize = (unsigned)daemon->packet_buff_sz - 4;
170 transfer->opt_blocksize = 1;
171 transfer->block = 0;
172 }
173
174 if (strcasecmp(opt, "tsize") == 0 && next(&p, end))
175 {
176 transfer->opt_transize = 1;
177 transfer->block = 0;
178 }
179 }
180
181 if (daemon->tftp_prefix)
182 {
183 strncpy(daemon->namebuff, daemon->tftp_prefix, MAXDNAME);
184 if (daemon->tftp_prefix[strlen(daemon->tftp_prefix)-1] != '/' &&
185 filename[0] != '/')
186 strncat(daemon->namebuff, "/", MAXDNAME);
187 }
188 else if (filename[0] != '/')
189 strncpy(daemon->namebuff, "/", MAXDNAME);
190 else
191 daemon->namebuff[0] = 0;
192
193 strncat(daemon->namebuff, filename, MAXDNAME);
194 daemon->namebuff[MAXDNAME-1] = 0;
195
196 /* If we're doing many tranfers from the same file, only
197 open it once this saves lots of file descriptors
198 when mass-booting a big cluster, for instance. */
199 for (t = daemon->tftp_trans; t; t = t->next)
200 if (strcmp(t->file->filename, daemon->namebuff) == 0)
201 break;
202
203 if (t)
204 {
205 /* file already open */
206 transfer->file = t->file;
207 transfer->file->refcount++;
208 if ((len = get_block(packet, transfer)) == -1)
209 goto oops;
210 is_err = 0;
211 }
212 else
213 {
214 /* check permissions and open file */
215
216 /* trick to ban moving out of the subtree */
217 if (daemon->tftp_prefix && strstr(daemon->namebuff, "/../"))
218 {
219 errno = EACCES;
220 goto perm;
221 }
222
223 if (stat(daemon->namebuff, &statbuf) == -1)
224 {
225 if (errno == ENOENT || errno == ENOTDIR)
226 len = tftp_err(ERR_FNF, packet, _("file %s not found"), daemon->namebuff);
227 else if (errno == EACCES)
228 {
229 perm:
230 len = tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), daemon->namebuff);
231 }
232 else
233 {
234 oops:
235 len = tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff);
236 }
237 }
238 else
239 {
240 uid_t uid = geteuid();
241 /* running as root, must be world-readable */
242 if (uid == 0)
243 {
244 if (!(statbuf.st_mode & S_IROTH))
245 {
246 errno = EACCES;
247 goto perm;
248 }
249 }
250 /* in secure mode, must be owned by user running dnsmasq */
251 else if ((daemon->options & OPT_TFTP_SECURE) && uid != statbuf.st_uid)
252 {
253 errno = EACCES;
254 goto perm;
255 }
256
257 if (!(file = malloc(sizeof(struct tftp_file) + strlen(daemon->namebuff) + 1)))
258 {
259 errno = ENOMEM;
260 goto oops;
261 }
262
263 if ((file->fd = open(daemon->namebuff, O_RDONLY)) == -1)
264 {
265 free(file);
266
267 if (errno == EACCES || errno == EISDIR)
268 goto perm;
269 else
270 goto oops;
271 }
272 else
273 {
274 transfer->file = file;
275 file->refcount = 1;
276 file->size = statbuf.st_size;
277 strcpy(file->filename, daemon->namebuff);
278 if ((len = get_block(packet, transfer)) == -1)
279 goto oops;
280 is_err = 0;
281 }
282 }
283 }
284 }
285
286 while (sendto(transfer->sockfd, packet, len, 0,
287 (struct sockaddr *)&peer, sizeof(peer)) == -1 && errno == EINTR);
288
289 if (is_err)
290 free_transfer(transfer);
291 else
292 {
293 syslog(LOG_INFO, _("TFTP sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr));
294 transfer->next = daemon->tftp_trans;
295 daemon->tftp_trans = transfer;
296 }
297}
298
299void check_tftp_listeners(struct daemon *daemon, fd_set *rset, time_t now)
300{
301 struct tftp_transfer *transfer, *tmp, **up;
302 ssize_t len;
303
304 struct ack {
305 unsigned short op, block;
306 } *mess = (struct ack *)daemon->packet;
307
308 /* Check for activity on any existing transfers */
309 for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp)
310 {
311 tmp = transfer->next;
312
313 if (FD_ISSET(transfer->sockfd, rset))
314 {
315 /* we overwrote the buffer... */
316 daemon->srv_save = NULL;
317
318 if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
319 {
320 if (ntohs(mess->op) == OP_ACK && ntohs(mess->block) == (unsigned short)transfer->block)
321 {
322 /* Got ack, ensure we take the (re)transmit path */
323 transfer->timeout = now;
324 transfer->backoff = 0;
325 transfer->block++;
326 }
327 else if (ntohs(mess->op) == OP_ERR)
328 {
329 char *p = daemon->packet + sizeof(struct ack);
330 char *end = daemon->packet + len;
331 char *err = next(&p, end);
332 /* Sanitise error message */
333 if (!err)
334 err = "";
335 else
336 {
337 char *q, *r;
338 for (q = r = err; *r; r++)
339 if (isprint(*r))
340 *(q++) = *r;
341 *q = 0;
342 }
343 syslog(LOG_ERR, _("TFTP error %d %s received from %s"),
344 (int)ntohs(mess->block), err,
345 inet_ntoa(transfer->peer.sin_addr));
346
347 /* Got err, ensure we take abort */
348 transfer->timeout = now;
349 transfer->backoff = 100;
350 }
351 }
352 }
353
354 if (difftime(now, transfer->timeout) >= 0.0)
355 {
356 int endcon = 0;
357
358 /* timeout, retransmit */
359 transfer->timeout += 1<<(transfer->backoff);
360
361 /* we overwrote the buffer... */
362 daemon->srv_save = NULL;
363
364 if ((len = get_block(daemon->packet, transfer)) == -1)
365 {
366 len = tftp_err(ERR_NOTDEF, daemon->packet, _("cannot read %s: %s"), transfer->file->filename);
367 endcon = 1;
368 }
369 else if (++transfer->backoff > 5)
370 {
371 /* don't complain about timeout when we're awaiting the last
372 ACK, some clients never send it */
373 if (len != 0)
374 syslog(LOG_ERR, _("TFTP failed sending %s to %s"),
375 transfer->file->filename, inet_ntoa(transfer->peer.sin_addr));
376 len = 0;
377 }
378
379 if (len != 0)
380 while(sendto(transfer->sockfd, daemon->packet, len, 0,
381 (struct sockaddr *)&transfer->peer, sizeof(transfer->peer)) == -1 && errno == EINTR);
382
383 if (endcon || len == 0)
384 {
385 /* unlink */
386 *up = tmp;
387 free_transfer(transfer);
388 continue;
389 }
390 }
391
392 up = &transfer->next;
393 }
394}
395
396static void free_transfer(struct tftp_transfer *transfer)
397{
398 close(transfer->sockfd);
399 if (transfer->file && (--transfer->file->refcount) == 0)
400 {
401 close(transfer->file->fd);
402 free(transfer->file);
403 }
404 free(transfer);
405}
406
407static char *next(char **p, char *end)
408{
409 char *ret = *p;
410 size_t len;
411
412 if (*(end-1) != 0 ||
413 *p == end ||
414 (len = strlen(ret)) == 0)
415 return NULL;
416
417 *p += len + 1;
418 return ret;
419}
420
421static ssize_t tftp_err(int err, char *packet, char *message, char *file)
422{
423 struct errmess {
424 unsigned short op, err;
425 char message[];
426 } *mess = (struct errmess *)packet;
427 ssize_t ret = 4;
428 char *errstr = strerror(errno);
429
430 mess->op = htons(OP_ERR);
431 mess->err = htons(err);
432 ret += (snprintf(mess->message, 500, message, file, errstr) + 1);
433 if (err != ERR_FNF)
434 syslog(LOG_ERR, "TFTP %s", mess->message);
435
436 return ret;
437}
438
439/* return -1 for error, zero for done. */
440static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
441{
442 if (transfer->block == 0)
443 {
444 /* send OACK */
445 char *p;
446 struct oackmess {
447 unsigned short op;
448 char data[];
449 } *mess = (struct oackmess *)packet;
450
451 p = mess->data;
452 mess->op = htons(OP_OACK);
453 if (transfer->opt_blocksize)
454 {
455 p += (sprintf(p, "blksize") + 1);
456 p += (sprintf(p, "%d", transfer->blocksize) + 1);
457 }
458 if (transfer->opt_transize)
459 {
460 p += (sprintf(p,"tsize") + 1);
461 p += (sprintf(p, "%u", (unsigned int)transfer->file->size) + 1);
462 }
463
464 return p - packet;
465 }
466 else
467 {
468 /* send data packet */
469 struct datamess {
470 unsigned short op, block;
471 unsigned char data[];
472 } *mess = (struct datamess *)packet;
473
474 off_t offset = transfer->blocksize * (transfer->block - 1);
475 size_t size = transfer->file->size - offset;
476
477 if (offset > transfer->file->size)
478 return 0; /* finished */
479
480 if (size > transfer->blocksize)
481 size = transfer->blocksize;
482
483 lseek(transfer->file->fd, offset, SEEK_SET);
484
485 mess->op = htons(OP_DATA);
486 mess->block = htons((unsigned short)(transfer->block));
487
488 if (!read_write(transfer->file->fd, mess->data, size, 1))
489 return -1;
490 else
491 return size + 4;
492 }
493}
494
495#endif