]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/tftp.c
1 /* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
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, or
6 (at your option) version 3 dated 29 June, 2007.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 static struct tftp_file
*check_tftp_fileperm(ssize_t
*len
);
22 static void free_transfer(struct tftp_transfer
*transfer
);
23 static ssize_t
tftp_err(int err
, char *packet
, char *mess
, char *file
);
24 static ssize_t
tftp_err_oops(char *packet
, char *file
);
25 static ssize_t
get_block(char *packet
, struct tftp_transfer
*transfer
);
26 static char *next(char **p
, char *end
);
41 void tftp_request(struct listener
*listen
, time_t now
)
44 char *packet
= daemon
->packet
;
45 char *filename
, *mode
, *p
, *end
, *opt
;
46 struct sockaddr_in addr
, peer
;
50 int is_err
= 1, if_index
= 0, mtu
= 0;
52 struct tftp_transfer
*transfer
;
53 int port
= daemon
->start_tftp_port
; /* may be zero to use ephemeral port */
54 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
55 int mtuflag
= IP_PMTUDISC_DONT
;
59 struct cmsghdr align
; /* this ensures alignment */
60 #if defined(HAVE_LINUX_NETWORK)
61 char control
[CMSG_SPACE(sizeof(struct in_pktinfo
))];
62 #elif defined(HAVE_SOLARIS_NETWORK)
63 char control
[CMSG_SPACE(sizeof(unsigned int))];
64 #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
65 char control
[CMSG_SPACE(sizeof(struct sockaddr_dl
))];
69 msg
.msg_controllen
= sizeof(control_u
);
70 msg
.msg_control
= control_u
.control
;
73 msg
.msg_namelen
= sizeof(peer
);
77 iov
.iov_base
= packet
;
78 iov
.iov_len
= daemon
->packet_buff_sz
;
80 /* we overwrote the buffer... */
81 daemon
->srv_save
= NULL
;
83 if ((len
= recvmsg(listen
->tftpfd
, &msg
, 0)) < 2)
86 if (daemon
->options
& OPT_NOWILD
)
88 addr
= listen
->iface
->addr
.in
;
89 mtu
= listen
->iface
->mtu
;
93 char name
[IF_NAMESIZE
];
94 struct cmsghdr
*cmptr
;
96 addr
.sin_addr
.s_addr
= 0;
98 #if defined(HAVE_LINUX_NETWORK)
99 for (cmptr
= CMSG_FIRSTHDR(&msg
); cmptr
; cmptr
= CMSG_NXTHDR(&msg
, cmptr
))
100 if (cmptr
->cmsg_level
== SOL_IP
&& cmptr
->cmsg_type
== IP_PKTINFO
)
102 addr
.sin_addr
= ((struct in_pktinfo
*)CMSG_DATA(cmptr
))->ipi_spec_dst
;
103 if_index
= ((struct in_pktinfo
*)CMSG_DATA(cmptr
))->ipi_ifindex
;
106 #elif defined(HAVE_SOLARIS_NETWORK)
107 for (cmptr
= CMSG_FIRSTHDR(&msg
); cmptr
; cmptr
= CMSG_NXTHDR(&msg
, cmptr
))
108 if (cmptr
->cmsg_level
== IPPROTO_IP
&& cmptr
->cmsg_type
== IP_RECVDSTADDR
)
109 addr
.sin_addr
= *((struct in_addr
*)CMSG_DATA(cmptr
));
110 else if (cmptr
->cmsg_level
== IPPROTO_IP
&& cmptr
->cmsg_type
== IP_RECVIF
)
111 if_index
= *((unsigned int *)CMSG_DATA(cmptr
));
114 #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
115 for (cmptr
= CMSG_FIRSTHDR(&msg
); cmptr
; cmptr
= CMSG_NXTHDR(&msg
, cmptr
))
116 if (cmptr
->cmsg_level
== IPPROTO_IP
&& cmptr
->cmsg_type
== IP_RECVDSTADDR
)
117 addr
.sin_addr
= *((struct in_addr
*)CMSG_DATA(cmptr
));
118 else if (cmptr
->cmsg_level
== IPPROTO_IP
&& cmptr
->cmsg_type
== IP_RECVIF
)
119 if_index
= ((struct sockaddr_dl
*)CMSG_DATA(cmptr
))->sdl_index
;
123 if (!indextoname(listen
->tftpfd
, if_index
, name
) ||
124 addr
.sin_addr
.s_addr
== 0 ||
125 !iface_check(AF_INET
, (struct all_addr
*)&addr
.sin_addr
, name
, &if_index
))
128 /* allowed interfaces are the same as for DHCP */
129 for (tmp
= daemon
->dhcp_except
; tmp
; tmp
= tmp
->next
)
130 if (tmp
->name
&& (strcmp(tmp
->name
, name
) == 0))
133 strncpy(name
, ifr
.ifr_name
, IF_NAMESIZE
);
134 if (ioctl(listen
->tftpfd
, SIOCGIFMTU
, &ifr
) != -1)
138 addr
.sin_port
= htons(port
);
139 addr
.sin_family
= AF_INET
;
140 #ifdef HAVE_SOCKADDR_SA_LEN
141 addr
.sin_len
= sizeof(addr
);
144 if (!(transfer
= whine_malloc(sizeof(struct tftp_transfer
))))
147 if ((transfer
->sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
153 transfer
->peer
= peer
;
154 transfer
->timeout
= now
+ 2;
155 transfer
->backoff
= 1;
157 transfer
->blocksize
= 512;
158 transfer
->offset
= 0;
159 transfer
->file
= NULL
;
160 transfer
->opt_blocksize
= transfer
->opt_transize
= 0;
161 transfer
->netascii
= transfer
->carrylf
= 0;
163 /* if we have a nailed-down range, iterate until we find a free one. */
166 if (bind(transfer
->sockfd
, (struct sockaddr
*)&addr
, sizeof(addr
)) == -1 ||
167 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
168 setsockopt(transfer
->sockfd
, SOL_IP
, IP_MTU_DISCOVER
, &mtuflag
, sizeof(mtuflag
)) == -1 ||
170 !fix_fd(transfer
->sockfd
))
172 if (errno
== EADDRINUSE
&& daemon
->start_tftp_port
!= 0)
174 if (++port
<= daemon
->end_tftp_port
)
176 addr
.sin_port
= htons(port
);
179 my_syslog(MS_TFTP
| LOG_ERR
, _("unable to get free port for TFTP"));
181 free_transfer(transfer
);
190 if (ntohs(*((unsigned short *)packet
)) != OP_RRQ
||
191 !(filename
= next(&p
, end
)) ||
192 !(mode
= next(&p
, end
)) ||
193 (strcasecmp(mode
, "octet") != 0 && strcasecmp(mode
, "netascii") != 0))
194 len
= tftp_err(ERR_ILL
, packet
, _("unsupported request from %s"), inet_ntoa(peer
.sin_addr
));
197 if (strcasecmp(mode
, "netascii") == 0)
198 transfer
->netascii
= 1;
200 while ((opt
= next(&p
, end
)))
202 if (strcasecmp(opt
, "blksize") == 0)
204 if ((opt
= next(&p
, end
)) &&
205 !(daemon
->options
& OPT_TFTP_NOBLOCK
))
207 transfer
->blocksize
= atoi(opt
);
208 if (transfer
->blocksize
< 1)
209 transfer
->blocksize
= 1;
210 if (transfer
->blocksize
> (unsigned)daemon
->packet_buff_sz
- 4)
211 transfer
->blocksize
= (unsigned)daemon
->packet_buff_sz
- 4;
212 /* 32 bytes for IP, UDP and TFTP headers */
213 if (mtu
!= 0 && transfer
->blocksize
> (unsigned)mtu
- 32)
214 transfer
->blocksize
= (unsigned)mtu
- 32;
215 transfer
->opt_blocksize
= 1;
219 else if (strcasecmp(opt
, "tsize") == 0 && next(&p
, end
) && !transfer
->netascii
)
221 transfer
->opt_transize
= 1;
226 /* cope with backslashes from windows boxen. */
227 while ((p
= strchr(filename
, '\\')))
230 strcpy(daemon
->namebuff
, "/");
231 if (daemon
->tftp_prefix
)
233 if (daemon
->tftp_prefix
[0] == '/')
234 daemon
->namebuff
[0] = 0;
235 strncat(daemon
->namebuff
, daemon
->tftp_prefix
, (MAXDNAME
-1) - strlen(daemon
->namebuff
));
236 if (daemon
->tftp_prefix
[strlen(daemon
->tftp_prefix
)-1] != '/')
237 strncat(daemon
->namebuff
, "/", (MAXDNAME
-1) - strlen(daemon
->namebuff
));
239 if (daemon
->options
& OPT_TFTP_APREF
)
241 size_t oldlen
= strlen(daemon
->namebuff
);
244 strncat(daemon
->namebuff
, inet_ntoa(peer
.sin_addr
), (MAXDNAME
-1) - strlen(daemon
->namebuff
));
245 strncat(daemon
->namebuff
, "/", (MAXDNAME
-1) - strlen(daemon
->namebuff
));
247 /* remove unique-directory if it doesn't exist */
248 if (stat(daemon
->namebuff
, &statbuf
) == -1 || !S_ISDIR(statbuf
.st_mode
))
249 daemon
->namebuff
[oldlen
] = 0;
252 /* Absolute pathnames OK if they match prefix */
253 if (filename
[0] == '/')
255 if (strstr(filename
, daemon
->namebuff
) == filename
)
256 daemon
->namebuff
[0] = 0;
261 else if (filename
[0] == '/')
262 daemon
->namebuff
[0] = 0;
263 strncat(daemon
->namebuff
, filename
, (MAXDNAME
-1) - strlen(daemon
->namebuff
));
265 /* check permissions and open file */
266 if ((transfer
->file
= check_tftp_fileperm(&len
)))
268 if ((len
= get_block(packet
, transfer
)) == -1)
269 len
= tftp_err_oops(packet
, daemon
->namebuff
);
275 while (sendto(transfer
->sockfd
, packet
, len
, 0,
276 (struct sockaddr
*)&peer
, sizeof(peer
)) == -1 && errno
== EINTR
);
279 free_transfer(transfer
);
282 my_syslog(MS_TFTP
| LOG_INFO
, _("TFTP sent %s to %s"), daemon
->namebuff
, inet_ntoa(peer
.sin_addr
));
283 transfer
->next
= daemon
->tftp_trans
;
284 daemon
->tftp_trans
= transfer
;
288 static struct tftp_file
*check_tftp_fileperm(ssize_t
*len
)
290 char *packet
= daemon
->packet
, *namebuff
= daemon
->namebuff
;
291 struct tftp_file
*file
;
292 struct tftp_transfer
*t
;
293 uid_t uid
= geteuid();
297 /* trick to ban moving out of the subtree */
298 if (daemon
->tftp_prefix
&& strstr(namebuff
, "/../"))
301 if ((fd
= open(namebuff
, O_RDONLY
)) == -1)
305 *len
= tftp_err(ERR_FNF
, packet
, _("file %s not found"), namebuff
);
308 else if (errno
== EACCES
)
314 /* stat the file descriptor to avoid stat->open races */
315 if (fstat(fd
, &statbuf
) == -1)
318 /* running as root, must be world-readable */
321 if (!(statbuf
.st_mode
& S_IROTH
))
324 /* in secure mode, must be owned by user running dnsmasq */
325 else if ((daemon
->options
& OPT_TFTP_SECURE
) && uid
!= statbuf
.st_uid
)
328 /* If we're doing many tranfers from the same file, only
329 open it once this saves lots of file descriptors
330 when mass-booting a big cluster, for instance.
331 Be conservative and only share when inode and name match
332 this keeps error messages sane. */
333 for (t
= daemon
->tftp_trans
; t
; t
= t
->next
)
334 if (t
->file
->dev
== statbuf
.st_dev
&&
335 t
->file
->inode
== statbuf
.st_ino
&&
336 strcmp(t
->file
->filename
, namebuff
) == 0)
343 if (!(file
= whine_malloc(sizeof(struct tftp_file
) + strlen(namebuff
) + 1)))
350 file
->size
= statbuf
.st_size
;
351 file
->dev
= statbuf
.st_dev
;
352 file
->inode
= statbuf
.st_ino
;
354 strcpy(file
->filename
, namebuff
);
359 *len
= tftp_err(ERR_PERM
, packet
, _("cannot access %s: %s"), namebuff
);
365 *len
= tftp_err_oops(packet
, namebuff
);
371 void check_tftp_listeners(fd_set
*rset
, time_t now
)
373 struct tftp_transfer
*transfer
, *tmp
, **up
;
377 unsigned short op
, block
;
378 } *mess
= (struct ack
*)daemon
->packet
;
380 /* Check for activity on any existing transfers */
381 for (transfer
= daemon
->tftp_trans
, up
= &daemon
->tftp_trans
; transfer
; transfer
= tmp
)
383 tmp
= transfer
->next
;
385 if (FD_ISSET(transfer
->sockfd
, rset
))
387 /* we overwrote the buffer... */
388 daemon
->srv_save
= NULL
;
390 if ((len
= recv(transfer
->sockfd
, daemon
->packet
, daemon
->packet_buff_sz
, 0)) >= (ssize_t
)sizeof(struct ack
))
392 if (ntohs(mess
->op
) == OP_ACK
&& ntohs(mess
->block
) == (unsigned short)transfer
->block
)
394 /* Got ack, ensure we take the (re)transmit path */
395 transfer
->timeout
= now
;
396 transfer
->backoff
= 0;
397 if (transfer
->block
++ != 0)
398 transfer
->offset
+= transfer
->blocksize
- transfer
->expansion
;
400 else if (ntohs(mess
->op
) == OP_ERR
)
402 char *p
= daemon
->packet
+ sizeof(struct ack
);
403 char *end
= daemon
->packet
+ len
;
404 char *err
= next(&p
, end
);
405 /* Sanitise error message */
411 for (q
= r
= err
; *r
; r
++)
412 if (isprint((int)*r
))
416 my_syslog(MS_TFTP
| LOG_ERR
, _("TFTP error %d %s received from %s"),
417 (int)ntohs(mess
->block
), err
,
418 inet_ntoa(transfer
->peer
.sin_addr
));
420 /* Got err, ensure we take abort */
421 transfer
->timeout
= now
;
422 transfer
->backoff
= 100;
427 if (difftime(now
, transfer
->timeout
) >= 0.0)
431 /* timeout, retransmit */
432 transfer
->timeout
+= 1 + (1<<transfer
->backoff
);
434 /* we overwrote the buffer... */
435 daemon
->srv_save
= NULL
;
437 if ((len
= get_block(daemon
->packet
, transfer
)) == -1)
439 len
= tftp_err_oops(daemon
->packet
, transfer
->file
->filename
);
442 else if (++transfer
->backoff
> 5)
444 /* don't complain about timeout when we're awaiting the last
445 ACK, some clients never send it */
447 my_syslog(MS_TFTP
| LOG_ERR
, _("TFTP failed sending %s to %s"),
448 transfer
->file
->filename
, inet_ntoa(transfer
->peer
.sin_addr
));
453 while(sendto(transfer
->sockfd
, daemon
->packet
, len
, 0,
454 (struct sockaddr
*)&transfer
->peer
, sizeof(transfer
->peer
)) == -1 && errno
== EINTR
);
456 if (endcon
|| len
== 0)
460 free_transfer(transfer
);
465 up
= &transfer
->next
;
469 static void free_transfer(struct tftp_transfer
*transfer
)
471 close(transfer
->sockfd
);
472 if (transfer
->file
&& (--transfer
->file
->refcount
) == 0)
474 close(transfer
->file
->fd
);
475 free(transfer
->file
);
480 static char *next(char **p
, char *end
)
487 (len
= strlen(ret
)) == 0)
494 static ssize_t
tftp_err(int err
, char *packet
, char *message
, char *file
)
497 unsigned short op
, err
;
499 } *mess
= (struct errmess
*)packet
;
501 char *errstr
= strerror(errno
);
503 mess
->op
= htons(OP_ERR
);
504 mess
->err
= htons(err
);
505 ret
+= (snprintf(mess
->message
, 500, message
, file
, errstr
) + 1);
506 my_syslog(MS_TFTP
| LOG_ERR
, "TFTP %s", mess
->message
);
511 static ssize_t
tftp_err_oops(char *packet
, char *file
)
513 return tftp_err(ERR_NOTDEF
, packet
, _("cannot read %s: %s"), file
);
516 /* return -1 for error, zero for done. */
517 static ssize_t
get_block(char *packet
, struct tftp_transfer
*transfer
)
519 if (transfer
->block
== 0)
526 } *mess
= (struct oackmess
*)packet
;
529 mess
->op
= htons(OP_OACK
);
530 if (transfer
->opt_blocksize
)
532 p
+= (sprintf(p
, "blksize") + 1);
533 p
+= (sprintf(p
, "%d", transfer
->blocksize
) + 1);
535 if (transfer
->opt_transize
)
537 p
+= (sprintf(p
,"tsize") + 1);
538 p
+= (sprintf(p
, "%u", (unsigned int)transfer
->file
->size
) + 1);
545 /* send data packet */
547 unsigned short op
, block
;
548 unsigned char data
[];
549 } *mess
= (struct datamess
*)packet
;
551 size_t size
= transfer
->file
->size
- transfer
->offset
;
553 if (transfer
->offset
> transfer
->file
->size
)
554 return 0; /* finished */
556 if (size
> transfer
->blocksize
)
557 size
= transfer
->blocksize
;
559 mess
->op
= htons(OP_DATA
);
560 mess
->block
= htons((unsigned short)(transfer
->block
));
562 if (lseek(transfer
->file
->fd
, transfer
->offset
, SEEK_SET
) == (off_t
)-1 ||
563 !read_write(transfer
->file
->fd
, mess
->data
, size
, 1))
566 transfer
->expansion
= 0;
568 /* Map '\n' to CR-LF in netascii mode */
569 if (transfer
->netascii
)
574 for (i
= 0, newcarrylf
= 0; i
< size
; i
++)
575 if (mess
->data
[i
] == '\n' && ( i
!= 0 || !transfer
->carrylf
))
577 if (size
== transfer
->blocksize
)
579 transfer
->expansion
++;
581 newcarrylf
= 1; /* don't expand LF again if it moves to the next block */
584 size
++; /* room in this block */
586 /* make space and insert CR */
587 memmove(&mess
->data
[i
+1], &mess
->data
[i
], size
- (i
+ 1));
588 mess
->data
[i
] = '\r';
592 transfer
->carrylf
= newcarrylf
;