1ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley 2ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 3ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat This program is free software; you can redistribute it and/or modify 4ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat it under the terms of the GNU General Public License as published by 5ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat the Free Software Foundation; version 2 dated June, 1991, or 6ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (at your option) version 3 dated 29 June, 2007. 7ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 8ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat This program is distributed in the hope that it will be useful, 9ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat but WITHOUT ANY WARRANTY; without even the implied warranty of 10ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat GNU General Public License for more details. 12ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 13ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat You should have received a copy of the GNU General Public License 14ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat along with this program. If not, see <http://www.gnu.org/licenses/>. 15ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat*/ 16ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 17ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include "dnsmasq.h" 18ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 19ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_TFTP 20ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 21ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct tftp_file *check_tftp_fileperm(ssize_t *len); 22ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic void free_transfer(struct tftp_transfer *transfer); 23ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic ssize_t tftp_err(int err, char *packet, char *mess, char *file); 24ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic ssize_t tftp_err_oops(char *packet, char *file); 25ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic ssize_t get_block(char *packet, struct tftp_transfer *transfer); 26ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic char *next(char **p, char *end); 27ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 28ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OP_RRQ 1 29ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OP_WRQ 2 30ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OP_DATA 3 31ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OP_ACK 4 32ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OP_ERR 5 33ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OP_OACK 6 34ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 35ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define ERR_NOTDEF 0 36ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define ERR_FNF 1 37ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define ERR_PERM 2 38ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define ERR_FULL 3 39ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define ERR_ILL 4 40ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 41ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid tftp_request(struct listener *listen, time_t now) 42ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 43ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ssize_t len; 44ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *packet = daemon->packet; 45ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *filename, *mode, *p, *end, *opt; 46ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct sockaddr_in addr, peer; 47ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct msghdr msg; 48ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct iovec iov; 49ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct ifreq ifr; 50ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int is_err = 1, if_index = 0, mtu = 0; 51ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct iname *tmp; 52ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct tftp_transfer *transfer; 53ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */ 54ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) 55ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int mtuflag = IP_PMTUDISC_DONT; 56ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 57ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 58ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat union { 59ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct cmsghdr align; /* this ensures alignment */ 60ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_LINUX_NETWORK) 61ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char control[CMSG_SPACE(sizeof(struct in_pktinfo))]; 62ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(HAVE_SOLARIS_NETWORK) 63ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char control[CMSG_SPACE(sizeof(unsigned int))]; 64ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF) 65ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char control[CMSG_SPACE(sizeof(struct sockaddr_dl))]; 66ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 67ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } control_u; 68ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 69ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_controllen = sizeof(control_u); 70ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_control = control_u.control; 71ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_flags = 0; 72ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_name = &peer; 73ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_namelen = sizeof(peer); 74ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_iov = &iov; 75ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_iovlen = 1; 76ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 77ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iov.iov_base = packet; 78ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iov.iov_len = daemon->packet_buff_sz; 79ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 80ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* we overwrote the buffer... */ 81ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->srv_save = NULL; 82ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 83ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2) 84ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 85ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 86ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->options & OPT_NOWILD) 87ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 88ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr = listen->iface->addr.in; 89ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat mtu = listen->iface->mtu; 90ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 91ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 92ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 93ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char name[IF_NAMESIZE]; 94ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct cmsghdr *cmptr; 95ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 96ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.sin_addr.s_addr = 0; 97ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 98ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_LINUX_NETWORK) 99ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 100ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO) 101ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 102ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.sin_addr = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst; 103ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex; 104ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 105ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 106ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(HAVE_SOLARIS_NETWORK) 107ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 108ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR) 109ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.sin_addr = *((struct in_addr *)CMSG_DATA(cmptr)); 110ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) 111ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if_index = *((unsigned int *)CMSG_DATA(cmptr)); 112ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 113ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 114ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF) 115ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 116ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR) 117ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.sin_addr = *((struct in_addr *)CMSG_DATA(cmptr)); 118ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) 119ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index; 120ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 121ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 122ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 123ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!indextoname(listen->tftpfd, if_index, name) || 124ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.sin_addr.s_addr == 0 || 125ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !iface_check(AF_INET, (struct all_addr *)&addr.sin_addr, name, &if_index)) 126ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 127ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 128ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* allowed interfaces are the same as for DHCP */ 129ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) 130ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (tmp->name && (strcmp(tmp->name, name) == 0)) 131ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 132ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 133ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strncpy(name, ifr.ifr_name, IF_NAMESIZE); 134ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1) 135ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat mtu = ifr.ifr_mtu; 136ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 137ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 138ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.sin_port = htons(port); 139ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.sin_family = AF_INET; 140ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SOCKADDR_SA_LEN 141ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.sin_len = sizeof(addr); 142ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 143ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 144ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(transfer = whine_malloc(sizeof(struct tftp_transfer)))) 145ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 146ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 147ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((transfer->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 148ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 149ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free(transfer); 150ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 151ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 152ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 153ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->peer = peer; 154ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->timeout = now + 2; 155ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->backoff = 1; 156ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->block = 1; 157ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->blocksize = 512; 158ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->offset = 0; 159ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->file = NULL; 160ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->opt_blocksize = transfer->opt_transize = 0; 161ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->netascii = transfer->carrylf = 0; 162ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 163ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* if we have a nailed-down range, iterate until we find a free one. */ 164ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while (1) 165ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 166ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (bind(transfer->sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 || 167ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) 168ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 || 169ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 170ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !fix_fd(transfer->sockfd)) 171ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 172ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (errno == EADDRINUSE && daemon->start_tftp_port != 0) 173ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 174ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (++port <= daemon->end_tftp_port) 175ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 176ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.sin_port = htons(port); 177ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 178ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 179ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_TFTP | LOG_ERR, _("unable to get free port for TFTP")); 180ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 181ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free_transfer(transfer); 182ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 183ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 184ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 185ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 186ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 187ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p = packet + 2; 188ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat end = packet + len; 189ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 190ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (ntohs(*((unsigned short *)packet)) != OP_RRQ || 191ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !(filename = next(&p, end)) || 192ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !(mode = next(&p, end)) || 193ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0)) 194ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), inet_ntoa(peer.sin_addr)); 195ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 196ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 197ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (strcasecmp(mode, "netascii") == 0) 198ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->netascii = 1; 199ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 200ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while ((opt = next(&p, end))) 201ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 202ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (strcasecmp(opt, "blksize") == 0) 203ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 204ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((opt = next(&p, end)) && 205ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !(daemon->options & OPT_TFTP_NOBLOCK)) 206ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 207ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->blocksize = atoi(opt); 208ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (transfer->blocksize < 1) 209ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->blocksize = 1; 210ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (transfer->blocksize > (unsigned)daemon->packet_buff_sz - 4) 211ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->blocksize = (unsigned)daemon->packet_buff_sz - 4; 212ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* 32 bytes for IP, UDP and TFTP headers */ 213ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (mtu != 0 && transfer->blocksize > (unsigned)mtu - 32) 214ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->blocksize = (unsigned)mtu - 32; 215ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->opt_blocksize = 1; 216ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->block = 0; 217ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 218ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 219ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (strcasecmp(opt, "tsize") == 0 && next(&p, end) && !transfer->netascii) 220ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 221ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->opt_transize = 1; 222ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->block = 0; 223ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 224ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 225ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 226ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* cope with backslashes from windows boxen. */ 227ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while ((p = strchr(filename, '\\'))) 228ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *p = '/'; 229ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 230ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strcpy(daemon->namebuff, "/"); 231ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->tftp_prefix) 232ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 233ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->tftp_prefix[0] == '/') 234ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->namebuff[0] = 0; 235ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strncat(daemon->namebuff, daemon->tftp_prefix, (MAXDNAME-1) - strlen(daemon->namebuff)); 236ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->tftp_prefix[strlen(daemon->tftp_prefix)-1] != '/') 237ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff)); 238ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 239ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->options & OPT_TFTP_APREF) 240ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 241ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size_t oldlen = strlen(daemon->namebuff); 242ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct stat statbuf; 243ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 244ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strncat(daemon->namebuff, inet_ntoa(peer.sin_addr), (MAXDNAME-1) - strlen(daemon->namebuff)); 245ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff)); 246ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 247ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* remove unique-directory if it doesn't exist */ 248ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode)) 249ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->namebuff[oldlen] = 0; 250ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 251ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 252ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Absolute pathnames OK if they match prefix */ 253ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (filename[0] == '/') 254ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 255ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (strstr(filename, daemon->namebuff) == filename) 256ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->namebuff[0] = 0; 257ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 258ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat filename++; 259ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 260ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 261ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (filename[0] == '/') 262ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->namebuff[0] = 0; 263ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff)); 264ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 265ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* check permissions and open file */ 266ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((transfer->file = check_tftp_fileperm(&len))) 267ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 268ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((len = get_block(packet, transfer)) == -1) 269ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat len = tftp_err_oops(packet, daemon->namebuff); 270ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 271ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat is_err = 0; 272ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 273ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 274ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 275ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while (sendto(transfer->sockfd, packet, len, 0, 276ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (struct sockaddr *)&peer, sizeof(peer)) == -1 && errno == EINTR); 277ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 278ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (is_err) 279ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free_transfer(transfer); 280ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 281ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 282ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_TFTP | LOG_INFO, _("TFTP sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr)); 283ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->next = daemon->tftp_trans; 284ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->tftp_trans = transfer; 285ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 286ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 287ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 288ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct tftp_file *check_tftp_fileperm(ssize_t *len) 289ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 290ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *packet = daemon->packet, *namebuff = daemon->namebuff; 291ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct tftp_file *file; 292ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct tftp_transfer *t; 293ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat uid_t uid = geteuid(); 294ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct stat statbuf; 295ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int fd = -1; 296ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 297ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* trick to ban moving out of the subtree */ 298ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->tftp_prefix && strstr(namebuff, "/../")) 299ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat goto perm; 300ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 301ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((fd = open(namebuff, O_RDONLY)) == -1) 302ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 303ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (errno == ENOENT) 304ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 305ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *len = tftp_err(ERR_FNF, packet, _("file %s not found"), namebuff); 306ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; 307ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 308ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (errno == EACCES) 309ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat goto perm; 310ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 311ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat goto oops; 312ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 313ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 314ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* stat the file descriptor to avoid stat->open races */ 315ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (fstat(fd, &statbuf) == -1) 316ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat goto oops; 317ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 318ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* running as root, must be world-readable */ 319ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (uid == 0) 320ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 321ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(statbuf.st_mode & S_IROTH)) 322ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat goto perm; 323ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 324ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* in secure mode, must be owned by user running dnsmasq */ 325ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if ((daemon->options & OPT_TFTP_SECURE) && uid != statbuf.st_uid) 326ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat goto perm; 327ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 328ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* If we're doing many tranfers from the same file, only 329ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat open it once this saves lots of file descriptors 330ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat when mass-booting a big cluster, for instance. 331ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat Be conservative and only share when inode and name match 332ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat this keeps error messages sane. */ 333ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (t = daemon->tftp_trans; t; t = t->next) 334ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (t->file->dev == statbuf.st_dev && 335ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat t->file->inode == statbuf.st_ino && 336ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strcmp(t->file->filename, namebuff) == 0) 337ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 338ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat close(fd); 339ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat t->file->refcount++; 340ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return t->file; 341ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 342ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 343ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(file = whine_malloc(sizeof(struct tftp_file) + strlen(namebuff) + 1))) 344ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 345ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat errno = ENOMEM; 346ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat goto oops; 347ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 348ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 349ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat file->fd = fd; 350ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat file->size = statbuf.st_size; 351ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat file->dev = statbuf.st_dev; 352ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat file->inode = statbuf.st_ino; 353ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat file->refcount = 1; 354ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strcpy(file->filename, namebuff); 355ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return file; 356ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 357ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat perm: 358ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat errno = EACCES; 359ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *len = tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff); 360ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (fd != -1) 361ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat close(fd); 362ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; 363ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 364ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat oops: 365ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *len = tftp_err_oops(packet, namebuff); 366ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (fd != -1) 367ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat close(fd); 368ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; 369ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 370ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 371ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid check_tftp_listeners(fd_set *rset, time_t now) 372ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 373ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct tftp_transfer *transfer, *tmp, **up; 374ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ssize_t len; 375ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 376ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct ack { 377ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned short op, block; 378ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } *mess = (struct ack *)daemon->packet; 379ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 380ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Check for activity on any existing transfers */ 381ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp) 382ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 383ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat tmp = transfer->next; 384ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 385ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (FD_ISSET(transfer->sockfd, rset)) 386ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 387ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* we overwrote the buffer... */ 388ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->srv_save = NULL; 389ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 390ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack)) 391ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 392ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (ntohs(mess->op) == OP_ACK && ntohs(mess->block) == (unsigned short)transfer->block) 393ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 394ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Got ack, ensure we take the (re)transmit path */ 395ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->timeout = now; 396ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->backoff = 0; 397ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (transfer->block++ != 0) 398ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->offset += transfer->blocksize - transfer->expansion; 399ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 400ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (ntohs(mess->op) == OP_ERR) 401ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 402ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *p = daemon->packet + sizeof(struct ack); 403ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *end = daemon->packet + len; 404ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *err = next(&p, end); 405ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Sanitise error message */ 406ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!err) 407ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat err = ""; 408ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 409ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 410ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *q, *r; 411ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (q = r = err; *r; r++) 412ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (isprint((int)*r)) 413ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *(q++) = *r; 414ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *q = 0; 415ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 416ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_TFTP | LOG_ERR, _("TFTP error %d %s received from %s"), 417ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (int)ntohs(mess->block), err, 418ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat inet_ntoa(transfer->peer.sin_addr)); 419ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 420ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Got err, ensure we take abort */ 421ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->timeout = now; 422ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->backoff = 100; 423ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 424ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 425ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 426ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 427ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (difftime(now, transfer->timeout) >= 0.0) 428ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 429ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int endcon = 0; 430ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 431ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* timeout, retransmit */ 432ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->timeout += 1 + (1<<transfer->backoff); 433ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 434ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* we overwrote the buffer... */ 435ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->srv_save = NULL; 436ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 437ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((len = get_block(daemon->packet, transfer)) == -1) 438ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 439ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat len = tftp_err_oops(daemon->packet, transfer->file->filename); 440ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat endcon = 1; 441ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 442ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (++transfer->backoff > 5) 443ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 444ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* don't complain about timeout when we're awaiting the last 445ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ACK, some clients never send it */ 446ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (len != 0) 447ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_TFTP | LOG_ERR, _("TFTP failed sending %s to %s"), 448ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->file->filename, inet_ntoa(transfer->peer.sin_addr)); 449ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat len = 0; 450ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 451ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 452ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (len != 0) 453ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while(sendto(transfer->sockfd, daemon->packet, len, 0, 454ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (struct sockaddr *)&transfer->peer, sizeof(transfer->peer)) == -1 && errno == EINTR); 455ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 456ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (endcon || len == 0) 457ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 458ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* unlink */ 459ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *up = tmp; 460ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free_transfer(transfer); 461ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 462ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 463ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 464ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 465ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat up = &transfer->next; 466ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 467ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 468ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 469ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic void free_transfer(struct tftp_transfer *transfer) 470ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 471ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat close(transfer->sockfd); 472ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (transfer->file && (--transfer->file->refcount) == 0) 473ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 474ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat close(transfer->file->fd); 475ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free(transfer->file); 476ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 477ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free(transfer); 478ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 479ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 480ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic char *next(char **p, char *end) 481ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 482ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *ret = *p; 483ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size_t len; 484ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 485ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (*(end-1) != 0 || 486ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *p == end || 487ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (len = strlen(ret)) == 0) 488ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; 489ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 490ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *p += len + 1; 491ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return ret; 492ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 493ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 494ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic ssize_t tftp_err(int err, char *packet, char *message, char *file) 495ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 496ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct errmess { 497ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned short op, err; 498ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char message[]; 499ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } *mess = (struct errmess *)packet; 500ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ssize_t ret = 4; 501ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *errstr = strerror(errno); 502ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 503ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat mess->op = htons(OP_ERR); 504ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat mess->err = htons(err); 505ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ret += (snprintf(mess->message, 500, message, file, errstr) + 1); 506ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_TFTP | LOG_ERR, "TFTP %s", mess->message); 507ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 508ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return ret; 509ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 510ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 511ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic ssize_t tftp_err_oops(char *packet, char *file) 512ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 513ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), file); 514ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 515ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 516ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* return -1 for error, zero for done. */ 517ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic ssize_t get_block(char *packet, struct tftp_transfer *transfer) 518ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 519ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (transfer->block == 0) 520ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 521ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* send OACK */ 522ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *p; 523ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct oackmess { 524ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned short op; 525ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char data[]; 526ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } *mess = (struct oackmess *)packet; 527ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 528ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p = mess->data; 529ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat mess->op = htons(OP_OACK); 530ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (transfer->opt_blocksize) 531ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 532ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += (sprintf(p, "blksize") + 1); 533ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += (sprintf(p, "%d", transfer->blocksize) + 1); 534ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 535ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (transfer->opt_transize) 536ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 537ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += (sprintf(p,"tsize") + 1); 538ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += (sprintf(p, "%u", (unsigned int)transfer->file->size) + 1); 539ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 540ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 541ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return p - packet; 542ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 543ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 544ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 545ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* send data packet */ 546ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct datamess { 547ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned short op, block; 548ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char data[]; 549ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } *mess = (struct datamess *)packet; 550ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 551ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size_t size = transfer->file->size - transfer->offset; 552ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 553ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (transfer->offset > transfer->file->size) 554ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 0; /* finished */ 555ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 556ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (size > transfer->blocksize) 557ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size = transfer->blocksize; 558ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 559ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat mess->op = htons(OP_DATA); 560ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat mess->block = htons((unsigned short)(transfer->block)); 561ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 562ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (lseek(transfer->file->fd, transfer->offset, SEEK_SET) == (off_t)-1 || 563ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !read_write(transfer->file->fd, mess->data, size, 1)) 564ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return -1; 565ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 566ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->expansion = 0; 567ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 568ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Map '\n' to CR-LF in netascii mode */ 569ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (transfer->netascii) 570ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 571ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size_t i; 572ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int newcarrylf; 573ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 574ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (i = 0, newcarrylf = 0; i < size; i++) 575ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf)) 576ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 577ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (size == transfer->blocksize) 578ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 579ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->expansion++; 580ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (i == size - 1) 581ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat newcarrylf = 1; /* don't expand LF again if it moves to the next block */ 582ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 583ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 584ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size++; /* room in this block */ 585ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 586ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* make space and insert CR */ 587ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memmove(&mess->data[i+1], &mess->data[i], size - (i + 1)); 588ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat mess->data[i] = '\r'; 589ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 590ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat i++; 591ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 592ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat transfer->carrylf = newcarrylf; 593ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 594ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 595ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 596ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return size + 4; 597ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 598ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 599ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 600ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 601