Annotation of embedaddon/dnsmasq/src/tftp.c, revision 1.1.1.4
1.1.1.4 ! misho 1: /* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
1.1 misho 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, or
6: (at your option) version 3 dated 29 June, 2007.
7:
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.
12:
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/>.
15: */
16:
17: #include "dnsmasq.h"
18:
19: #ifdef HAVE_TFTP
20:
1.1.1.4 ! misho 21: static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len);
1.1 misho 22: static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix);
23: static void free_transfer(struct tftp_transfer *transfer);
1.1.1.4 ! misho 24: static ssize_t tftp_err(int err, char *packet, char *message, char *file);
1.1 misho 25: static ssize_t tftp_err_oops(char *packet, char *file);
26: static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
27: static char *next(char **p, char *end);
28: static void sanitise(char *buf);
29:
30: #define OP_RRQ 1
31: #define OP_WRQ 2
32: #define OP_DATA 3
33: #define OP_ACK 4
34: #define OP_ERR 5
35: #define OP_OACK 6
36:
37: #define ERR_NOTDEF 0
38: #define ERR_FNF 1
39: #define ERR_PERM 2
40: #define ERR_FULL 3
41: #define ERR_ILL 4
42:
43: void tftp_request(struct listener *listen, time_t now)
44: {
45: ssize_t len;
46: char *packet = daemon->packet;
47: char *filename, *mode, *p, *end, *opt;
48: union mysockaddr addr, peer;
49: struct msghdr msg;
50: struct iovec iov;
51: struct ifreq ifr;
52: int is_err = 1, if_index = 0, mtu = 0;
53: struct iname *tmp;
1.1.1.4 ! misho 54: struct tftp_transfer *transfer = NULL, **up;
1.1 misho 55: int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */
56: #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
57: int mtuflag = IP_PMTUDISC_DONT;
58: #endif
59: char namebuff[IF_NAMESIZE];
60: char *name = NULL;
61: char *prefix = daemon->tftp_prefix;
62: struct tftp_prefix *pref;
1.1.1.4 ! misho 63: union all_addr addra;
! 64: int family = listen->addr.sa.sa_family;
1.1.1.2 misho 65: /* Can always get recvd interface for IPv6 */
1.1.1.4 ! misho 66: int check_dest = !option_bool(OPT_NOWILD) || family == AF_INET6;
1.1 misho 67: union {
68: struct cmsghdr align; /* this ensures alignment */
69: char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
70: #if defined(HAVE_LINUX_NETWORK)
71: char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
72: #elif defined(HAVE_SOLARIS_NETWORK)
1.1.1.4 ! misho 73: char control[CMSG_SPACE(sizeof(struct in_addr)) +
! 74: CMSG_SPACE(sizeof(unsigned int))];
1.1 misho 75: #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
1.1.1.4 ! misho 76: char control[CMSG_SPACE(sizeof(struct in_addr)) +
! 77: CMSG_SPACE(sizeof(struct sockaddr_dl))];
1.1 misho 78: #endif
79: } control_u;
80:
81: msg.msg_controllen = sizeof(control_u);
82: msg.msg_control = control_u.control;
83: msg.msg_flags = 0;
84: msg.msg_name = &peer;
85: msg.msg_namelen = sizeof(peer);
86: msg.msg_iov = &iov;
87: msg.msg_iovlen = 1;
88:
89: iov.iov_base = packet;
90: iov.iov_len = daemon->packet_buff_sz;
91:
92: /* we overwrote the buffer... */
93: daemon->srv_save = NULL;
94:
95: if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
96: return;
1.1.1.2 misho 97:
98: /* Can always get recvd interface for IPv6 */
99: if (!check_dest)
1.1 misho 100: {
101: if (listen->iface)
102: {
103: addr = listen->iface->addr;
104: name = listen->iface->name;
1.1.1.3 misho 105: mtu = listen->iface->mtu;
106: if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
107: mtu = daemon->tftp_mtu;
1.1 misho 108: }
109: else
110: {
111: /* we're listening on an address that doesn't appear on an interface,
112: ask the kernel what the socket is bound to */
113: socklen_t tcp_len = sizeof(union mysockaddr);
114: if (getsockname(listen->tftpfd, (struct sockaddr *)&addr, &tcp_len) == -1)
115: return;
116: }
117: }
118: else
119: {
120: struct cmsghdr *cmptr;
121:
122: if (msg.msg_controllen < sizeof(struct cmsghdr))
123: return;
124:
1.1.1.4 ! misho 125: addr.sa.sa_family = family;
1.1 misho 126:
127: #if defined(HAVE_LINUX_NETWORK)
1.1.1.4 ! misho 128: if (family == AF_INET)
1.1 misho 129: for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
130: if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
131: {
132: union {
133: unsigned char *c;
134: struct in_pktinfo *p;
135: } p;
136: p.c = CMSG_DATA(cmptr);
137: addr.in.sin_addr = p.p->ipi_spec_dst;
138: if_index = p.p->ipi_ifindex;
139: }
140:
141: #elif defined(HAVE_SOLARIS_NETWORK)
1.1.1.4 ! misho 142: if (family == AF_INET)
1.1 misho 143: for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
144: {
145: union {
146: unsigned char *c;
147: struct in_addr *a;
148: unsigned int *i;
149: } p;
150: p.c = CMSG_DATA(cmptr);
151: if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
152: addr.in.sin_addr = *(p.a);
153: else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
154: if_index = *(p.i);
155: }
156:
157: #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
1.1.1.4 ! misho 158: if (family == AF_INET)
1.1 misho 159: for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
160: {
161: union {
162: unsigned char *c;
163: struct in_addr *a;
164: struct sockaddr_dl *s;
165: } p;
166: p.c = CMSG_DATA(cmptr);
167: if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
168: addr.in.sin_addr = *(p.a);
169: else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
170: if_index = p.s->sdl_index;
171: }
172:
173: #endif
174:
1.1.1.4 ! misho 175: if (family == AF_INET6)
1.1 misho 176: {
177: for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
178: if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
179: {
180: union {
181: unsigned char *c;
182: struct in6_pktinfo *p;
183: } p;
184: p.c = CMSG_DATA(cmptr);
185:
186: addr.in6.sin6_addr = p.p->ipi6_addr;
187: if_index = p.p->ipi6_ifindex;
188: }
189: }
190:
191: if (!indextoname(listen->tftpfd, if_index, namebuff))
192: return;
193:
194: name = namebuff;
195:
1.1.1.4 ! misho 196: addra.addr4 = addr.in.sin_addr;
1.1 misho 197:
1.1.1.4 ! misho 198: if (family == AF_INET6)
! 199: addra.addr6 = addr.in6.sin6_addr;
1.1 misho 200:
1.1.1.2 misho 201: if (daemon->tftp_interfaces)
1.1 misho 202: {
1.1.1.2 misho 203: /* dedicated tftp interface list */
204: for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next)
205: if (tmp->name && wildcard_match(tmp->name, name))
206: break;
207:
208: if (!tmp)
1.1 misho 209: return;
210: }
1.1.1.2 misho 211: else
212: {
213: /* Do the same as DHCP */
1.1.1.4 ! misho 214: if (!iface_check(family, &addra, name, NULL))
1.1.1.2 misho 215: {
216: if (!option_bool(OPT_CLEVERBIND))
217: enumerate_interfaces(0);
1.1.1.4 ! misho 218: if (!loopback_exception(listen->tftpfd, family, &addra, name) &&
! 219: !label_exception(if_index, family, &addra))
1.1.1.2 misho 220: return;
221: }
222:
1.1 misho 223: #ifdef HAVE_DHCP
1.1.1.2 misho 224: /* allowed interfaces are the same as for DHCP */
225: for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
226: if (tmp->name && wildcard_match(tmp->name, name))
227: return;
1.1 misho 228: #endif
1.1.1.2 misho 229: }
230:
1.1.1.4 ! misho 231: safe_strncpy(ifr.ifr_name, name, IF_NAMESIZE);
1.1 misho 232: if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
1.1.1.3 misho 233: {
234: mtu = ifr.ifr_mtu;
235: if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
236: mtu = daemon->tftp_mtu;
237: }
1.1 misho 238: }
1.1.1.3 misho 239:
240: /* Failed to get interface mtu - can use configured value. */
241: if (mtu == 0)
242: mtu = daemon->tftp_mtu;
243:
1.1.1.4 ! misho 244: /* data transfer via server listening socket */
! 245: if (option_bool(OPT_SINGLE_PORT))
! 246: {
! 247: int tftp_cnt;
! 248:
! 249: for (tftp_cnt = 0, transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; up = &transfer->next, transfer = transfer->next)
! 250: {
! 251: tftp_cnt++;
! 252:
! 253: if (sockaddr_isequal(&peer, &transfer->peer))
! 254: {
! 255: if (ntohs(*((unsigned short *)packet)) == OP_RRQ)
! 256: {
! 257: /* Handle repeated RRQ or abandoned transfer from same host and port
! 258: by unlinking and reusing the struct transfer. */
! 259: *up = transfer->next;
! 260: break;
! 261: }
! 262: else
! 263: {
! 264: handle_tftp(now, transfer, len);
! 265: return;
! 266: }
! 267: }
! 268: }
! 269:
! 270: /* Enforce simultaneous transfer limit. In non-single-port mode
! 271: this is doene by not listening on the server socket when
! 272: too many transfers are in progress. */
! 273: if (!transfer && tftp_cnt >= daemon->tftp_max)
! 274: return;
! 275: }
! 276:
1.1 misho 277: if (name)
278: {
279: /* check for per-interface prefix */
280: for (pref = daemon->if_prefix; pref; pref = pref->next)
281: if (strcmp(pref->interface, name) == 0)
282: prefix = pref->prefix;
283: }
284:
1.1.1.4 ! misho 285: if (family == AF_INET)
1.1 misho 286: {
287: addr.in.sin_port = htons(port);
288: #ifdef HAVE_SOCKADDR_SA_LEN
289: addr.in.sin_len = sizeof(addr.in);
290: #endif
291: }
292: else
293: {
294: addr.in6.sin6_port = htons(port);
295: addr.in6.sin6_flowinfo = 0;
296: addr.in6.sin6_scope_id = 0;
297: #ifdef HAVE_SOCKADDR_SA_LEN
298: addr.in6.sin6_len = sizeof(addr.in6);
299: #endif
300: }
301:
1.1.1.4 ! misho 302: /* May reuse struct transfer from abandoned transfer in single port mode. */
! 303: if (!transfer && !(transfer = whine_malloc(sizeof(struct tftp_transfer))))
1.1 misho 304: return;
305:
1.1.1.4 ! misho 306: if (option_bool(OPT_SINGLE_PORT))
! 307: transfer->sockfd = listen->tftpfd;
! 308: else if ((transfer->sockfd = socket(family, SOCK_DGRAM, 0)) == -1)
1.1 misho 309: {
310: free(transfer);
311: return;
312: }
313:
314: transfer->peer = peer;
1.1.1.4 ! misho 315: transfer->source = addra;
! 316: transfer->if_index = if_index;
1.1 misho 317: transfer->timeout = now + 2;
318: transfer->backoff = 1;
319: transfer->block = 1;
320: transfer->blocksize = 512;
321: transfer->offset = 0;
322: transfer->file = NULL;
323: transfer->opt_blocksize = transfer->opt_transize = 0;
324: transfer->netascii = transfer->carrylf = 0;
325:
1.1.1.4 ! misho 326: (void)prettyprint_addr(&peer, daemon->addrbuff);
1.1 misho 327:
328: /* if we have a nailed-down range, iterate until we find a free one. */
1.1.1.4 ! misho 329: while (!option_bool(OPT_SINGLE_PORT))
1.1 misho 330: {
331: if (bind(transfer->sockfd, &addr.sa, sa_len(&addr)) == -1 ||
332: #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
333: setsockopt(transfer->sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
334: #endif
335: !fix_fd(transfer->sockfd))
336: {
337: if (errno == EADDRINUSE && daemon->start_tftp_port != 0)
338: {
339: if (++port <= daemon->end_tftp_port)
340: {
1.1.1.4 ! misho 341: if (family == AF_INET)
1.1 misho 342: addr.in.sin_port = htons(port);
343: else
1.1.1.4 ! misho 344: addr.in6.sin6_port = htons(port);
! 345:
1.1 misho 346: continue;
347: }
348: my_syslog(MS_TFTP | LOG_ERR, _("unable to get free port for TFTP"));
349: }
350: free_transfer(transfer);
351: return;
352: }
353: break;
354: }
355:
356: p = packet + 2;
357: end = packet + len;
1.1.1.4 ! misho 358:
1.1 misho 359: if (ntohs(*((unsigned short *)packet)) != OP_RRQ ||
360: !(filename = next(&p, end)) ||
361: !(mode = next(&p, end)) ||
362: (strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
363: {
364: len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff);
365: is_err = 1;
366: }
367: else
368: {
369: if (strcasecmp(mode, "netascii") == 0)
370: transfer->netascii = 1;
371:
372: while ((opt = next(&p, end)))
373: {
374: if (strcasecmp(opt, "blksize") == 0)
375: {
376: if ((opt = next(&p, end)) && !option_bool(OPT_TFTP_NOBLOCK))
377: {
1.1.1.3 misho 378: /* 32 bytes for IP, UDP and TFTP headers, 52 bytes for IPv6 */
1.1.1.4 ! misho 379: int overhead = (family == AF_INET) ? 32 : 52;
1.1 misho 380: transfer->blocksize = atoi(opt);
381: if (transfer->blocksize < 1)
382: transfer->blocksize = 1;
383: if (transfer->blocksize > (unsigned)daemon->packet_buff_sz - 4)
384: transfer->blocksize = (unsigned)daemon->packet_buff_sz - 4;
1.1.1.3 misho 385: if (mtu != 0 && transfer->blocksize > (unsigned)mtu - overhead)
386: transfer->blocksize = (unsigned)mtu - overhead;
1.1 misho 387: transfer->opt_blocksize = 1;
388: transfer->block = 0;
389: }
390: }
391: else if (strcasecmp(opt, "tsize") == 0 && next(&p, end) && !transfer->netascii)
392: {
393: transfer->opt_transize = 1;
394: transfer->block = 0;
395: }
396: }
397:
398: /* cope with backslashes from windows boxen. */
399: for (p = filename; *p; p++)
400: if (*p == '\\')
401: *p = '/';
402: else if (option_bool(OPT_TFTP_LC))
403: *p = tolower(*p);
404:
405: strcpy(daemon->namebuff, "/");
406: if (prefix)
407: {
408: if (prefix[0] == '/')
409: daemon->namebuff[0] = 0;
410: strncat(daemon->namebuff, prefix, (MAXDNAME-1) - strlen(daemon->namebuff));
411: if (prefix[strlen(prefix)-1] != '/')
412: strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
413:
1.1.1.4 ! misho 414: if (option_bool(OPT_TFTP_APREF_IP))
1.1 misho 415: {
416: size_t oldlen = strlen(daemon->namebuff);
417: struct stat statbuf;
418:
419: strncat(daemon->namebuff, daemon->addrbuff, (MAXDNAME-1) - strlen(daemon->namebuff));
420: strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
421:
422: /* remove unique-directory if it doesn't exist */
423: if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode))
424: daemon->namebuff[oldlen] = 0;
425: }
1.1.1.4 ! misho 426:
! 427: if (option_bool(OPT_TFTP_APREF_MAC))
! 428: {
! 429: unsigned char *macaddr = NULL;
! 430: unsigned char macbuf[DHCP_CHADDR_MAX];
! 431:
! 432: #ifdef HAVE_DHCP
! 433: if (daemon->dhcp && peer.sa.sa_family == AF_INET)
! 434: {
! 435: /* Check if the client IP is in our lease database */
! 436: struct dhcp_lease *lease = lease_find_by_addr(peer.in.sin_addr);
! 437: if (lease && lease->hwaddr_type == ARPHRD_ETHER && lease->hwaddr_len == ETHER_ADDR_LEN)
! 438: macaddr = lease->hwaddr;
! 439: }
! 440: #endif
! 441:
! 442: /* If no luck, try to find in ARP table. This only works if client is in same (V)LAN */
! 443: if (!macaddr && find_mac(&peer, macbuf, 1, now) > 0)
! 444: macaddr = macbuf;
! 445:
! 446: if (macaddr)
! 447: {
! 448: size_t oldlen = strlen(daemon->namebuff);
! 449: struct stat statbuf;
! 450:
! 451: snprintf(daemon->namebuff + oldlen, (MAXDNAME-1) - oldlen, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x/",
! 452: macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
! 453:
! 454: /* remove unique-directory if it doesn't exist */
! 455: if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode))
! 456: daemon->namebuff[oldlen] = 0;
! 457: }
! 458: }
! 459:
1.1 misho 460: /* Absolute pathnames OK if they match prefix */
461: if (filename[0] == '/')
462: {
463: if (strstr(filename, daemon->namebuff) == filename)
464: daemon->namebuff[0] = 0;
465: else
466: filename++;
467: }
468: }
469: else if (filename[0] == '/')
470: daemon->namebuff[0] = 0;
471: strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
1.1.1.4 ! misho 472:
1.1 misho 473: /* check permissions and open file */
474: if ((transfer->file = check_tftp_fileperm(&len, prefix)))
475: {
476: if ((len = get_block(packet, transfer)) == -1)
477: len = tftp_err_oops(packet, daemon->namebuff);
478: else
479: is_err = 0;
480: }
481: }
1.1.1.4 ! misho 482:
! 483: send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), packet, len, &peer, &addra, if_index);
1.1 misho 484:
485: if (is_err)
486: free_transfer(transfer);
487: else
488: {
489: transfer->next = daemon->tftp_trans;
490: daemon->tftp_trans = transfer;
491: }
492: }
493:
494: static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
495: {
496: char *packet = daemon->packet, *namebuff = daemon->namebuff;
497: struct tftp_file *file;
498: struct tftp_transfer *t;
499: uid_t uid = geteuid();
500: struct stat statbuf;
501: int fd = -1;
502:
503: /* trick to ban moving out of the subtree */
504: if (prefix && strstr(namebuff, "/../"))
505: goto perm;
506:
507: if ((fd = open(namebuff, O_RDONLY)) == -1)
508: {
509: if (errno == ENOENT)
510: {
511: *len = tftp_err(ERR_FNF, packet, _("file %s not found"), namebuff);
512: return NULL;
513: }
514: else if (errno == EACCES)
515: goto perm;
516: else
517: goto oops;
518: }
519:
520: /* stat the file descriptor to avoid stat->open races */
521: if (fstat(fd, &statbuf) == -1)
522: goto oops;
523:
524: /* running as root, must be world-readable */
525: if (uid == 0)
526: {
527: if (!(statbuf.st_mode & S_IROTH))
528: goto perm;
529: }
530: /* in secure mode, must be owned by user running dnsmasq */
531: else if (option_bool(OPT_TFTP_SECURE) && uid != statbuf.st_uid)
532: goto perm;
533:
1.1.1.4 ! misho 534: /* If we're doing many transfers from the same file, only
1.1 misho 535: open it once this saves lots of file descriptors
536: when mass-booting a big cluster, for instance.
537: Be conservative and only share when inode and name match
538: this keeps error messages sane. */
539: for (t = daemon->tftp_trans; t; t = t->next)
540: if (t->file->dev == statbuf.st_dev &&
541: t->file->inode == statbuf.st_ino &&
542: strcmp(t->file->filename, namebuff) == 0)
543: {
544: close(fd);
545: t->file->refcount++;
546: return t->file;
547: }
548:
549: if (!(file = whine_malloc(sizeof(struct tftp_file) + strlen(namebuff) + 1)))
550: {
551: errno = ENOMEM;
552: goto oops;
553: }
554:
555: file->fd = fd;
556: file->size = statbuf.st_size;
557: file->dev = statbuf.st_dev;
558: file->inode = statbuf.st_ino;
559: file->refcount = 1;
560: strcpy(file->filename, namebuff);
561: return file;
562:
563: perm:
564: errno = EACCES;
565: *len = tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff);
566: if (fd != -1)
567: close(fd);
568: return NULL;
569:
570: oops:
571: *len = tftp_err_oops(packet, namebuff);
572: if (fd != -1)
573: close(fd);
574: return NULL;
575: }
576:
1.1.1.3 misho 577: void check_tftp_listeners(time_t now)
1.1 misho 578: {
579: struct tftp_transfer *transfer, *tmp, **up;
580:
1.1.1.4 ! misho 581: /* In single port mode, all packets come via port 69 and tftp_request() */
! 582: if (!option_bool(OPT_SINGLE_PORT))
! 583: for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1.1.1.3 misho 584: if (poll_check(transfer->sockfd, POLLIN))
1.1 misho 585: {
586: /* we overwrote the buffer... */
587: daemon->srv_save = NULL;
1.1.1.4 ! misho 588: handle_tftp(now, transfer, recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0));
1.1 misho 589: }
1.1.1.4 ! misho 590:
! 591: for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp)
! 592: {
! 593: tmp = transfer->next;
1.1 misho 594:
595: if (difftime(now, transfer->timeout) >= 0.0)
596: {
597: int endcon = 0;
1.1.1.4 ! misho 598: ssize_t len;
1.1 misho 599:
600: /* timeout, retransmit */
1.1.1.4 ! misho 601: transfer->timeout += 1 + (1<<(transfer->backoff/2));
1.1 misho 602:
603: /* we overwrote the buffer... */
604: daemon->srv_save = NULL;
605:
606: if ((len = get_block(daemon->packet, transfer)) == -1)
607: {
608: len = tftp_err_oops(daemon->packet, transfer->file->filename);
609: endcon = 1;
610: }
1.1.1.4 ! misho 611: else if (++transfer->backoff > 7)
1.1 misho 612: {
1.1.1.4 ! misho 613: /* don't complain about timeout when we're awaiting the last
! 614: ACK, some clients never send it */
! 615: if ((unsigned)len == transfer->blocksize + 4)
! 616: endcon = 1;
1.1 misho 617: len = 0;
618: }
619:
620: if (len != 0)
1.1.1.4 ! misho 621: send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), daemon->packet, len,
! 622: &transfer->peer, &transfer->source, transfer->if_index);
! 623:
1.1 misho 624: if (endcon || len == 0)
625: {
626: strcpy(daemon->namebuff, transfer->file->filename);
627: sanitise(daemon->namebuff);
1.1.1.4 ! misho 628: (void)prettyprint_addr(&transfer->peer, daemon->addrbuff);
1.1 misho 629: my_syslog(MS_TFTP | LOG_INFO, endcon ? _("failed sending %s to %s") : _("sent %s to %s"), daemon->namebuff, daemon->addrbuff);
630: /* unlink */
631: *up = tmp;
632: if (endcon)
633: free_transfer(transfer);
634: else
635: {
636: /* put on queue to be sent to script and deleted */
637: transfer->next = daemon->tftp_done_trans;
638: daemon->tftp_done_trans = transfer;
639: }
640: continue;
641: }
642: }
643:
644: up = &transfer->next;
645: }
646: }
1.1.1.4 ! misho 647:
! 648: /* packet in daemon->packet as this is called. */
! 649: static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len)
! 650: {
! 651: struct ack {
! 652: unsigned short op, block;
! 653: } *mess = (struct ack *)daemon->packet;
! 654:
! 655: if (len >= (ssize_t)sizeof(struct ack))
! 656: {
! 657: if (ntohs(mess->op) == OP_ACK && ntohs(mess->block) == (unsigned short)transfer->block)
! 658: {
! 659: /* Got ack, ensure we take the (re)transmit path */
! 660: transfer->timeout = now;
! 661: transfer->backoff = 0;
! 662: if (transfer->block++ != 0)
! 663: transfer->offset += transfer->blocksize - transfer->expansion;
! 664: }
! 665: else if (ntohs(mess->op) == OP_ERR)
! 666: {
! 667: char *p = daemon->packet + sizeof(struct ack);
! 668: char *end = daemon->packet + len;
! 669: char *err = next(&p, end);
! 670:
! 671: (void)prettyprint_addr(&transfer->peer, daemon->addrbuff);
! 672:
! 673: /* Sanitise error message */
! 674: if (!err)
! 675: err = "";
! 676: else
! 677: sanitise(err);
! 678:
! 679: my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
! 680: (int)ntohs(mess->block), err,
! 681: daemon->addrbuff);
! 682:
! 683: /* Got err, ensure we take abort */
! 684: transfer->timeout = now;
! 685: transfer->backoff = 100;
! 686: }
! 687: }
! 688: }
1.1 misho 689:
690: static void free_transfer(struct tftp_transfer *transfer)
691: {
1.1.1.4 ! misho 692: if (!option_bool(OPT_SINGLE_PORT))
! 693: close(transfer->sockfd);
! 694:
1.1 misho 695: if (transfer->file && (--transfer->file->refcount) == 0)
696: {
697: close(transfer->file->fd);
698: free(transfer->file);
699: }
1.1.1.4 ! misho 700:
1.1 misho 701: free(transfer);
702: }
703:
704: static char *next(char **p, char *end)
705: {
706: char *ret = *p;
707: size_t len;
708:
709: if (*(end-1) != 0 ||
710: *p == end ||
711: (len = strlen(ret)) == 0)
712: return NULL;
713:
714: *p += len + 1;
715: return ret;
716: }
717:
718: static void sanitise(char *buf)
719: {
720: unsigned char *q, *r;
721: for (q = r = (unsigned char *)buf; *r; r++)
722: if (isprint((int)*r))
723: *(q++) = *r;
724: *q = 0;
725:
726: }
727:
1.1.1.4 ! misho 728: #define MAXMESSAGE 500 /* limit to make packet < 512 bytes and definitely smaller than buffer */
1.1 misho 729: static ssize_t tftp_err(int err, char *packet, char *message, char *file)
730: {
731: struct errmess {
732: unsigned short op, err;
733: char message[];
734: } *mess = (struct errmess *)packet;
1.1.1.4 ! misho 735: ssize_t len, ret = 4;
1.1 misho 736: char *errstr = strerror(errno);
737:
1.1.1.4 ! misho 738: memset(packet, 0, daemon->packet_buff_sz);
1.1 misho 739: sanitise(file);
1.1.1.4 ! misho 740:
1.1 misho 741: mess->op = htons(OP_ERR);
742: mess->err = htons(err);
1.1.1.4 ! misho 743: len = snprintf(mess->message, MAXMESSAGE, message, file, errstr);
! 744: ret += (len < MAXMESSAGE) ? len + 1 : MAXMESSAGE; /* include terminating zero */
! 745:
1.1 misho 746: my_syslog(MS_TFTP | LOG_ERR, "%s", mess->message);
747:
748: return ret;
749: }
750:
751: static ssize_t tftp_err_oops(char *packet, char *file)
752: {
753: /* May have >1 refs to file, so potentially mangle a copy of the name */
754: strcpy(daemon->namebuff, file);
755: return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff);
756: }
757:
758: /* return -1 for error, zero for done. */
759: static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
760: {
1.1.1.4 ! misho 761: memset(packet, 0, daemon->packet_buff_sz);
! 762:
1.1 misho 763: if (transfer->block == 0)
764: {
765: /* send OACK */
766: char *p;
767: struct oackmess {
768: unsigned short op;
769: char data[];
770: } *mess = (struct oackmess *)packet;
771:
772: p = mess->data;
773: mess->op = htons(OP_OACK);
774: if (transfer->opt_blocksize)
775: {
776: p += (sprintf(p, "blksize") + 1);
1.1.1.4 ! misho 777: p += (sprintf(p, "%u", transfer->blocksize) + 1);
1.1 misho 778: }
779: if (transfer->opt_transize)
780: {
781: p += (sprintf(p,"tsize") + 1);
782: p += (sprintf(p, "%u", (unsigned int)transfer->file->size) + 1);
783: }
784:
785: return p - packet;
786: }
787: else
788: {
789: /* send data packet */
790: struct datamess {
791: unsigned short op, block;
792: unsigned char data[];
793: } *mess = (struct datamess *)packet;
794:
795: size_t size = transfer->file->size - transfer->offset;
796:
797: if (transfer->offset > transfer->file->size)
798: return 0; /* finished */
799:
800: if (size > transfer->blocksize)
801: size = transfer->blocksize;
802:
803: mess->op = htons(OP_DATA);
804: mess->block = htons((unsigned short)(transfer->block));
805:
806: if (lseek(transfer->file->fd, transfer->offset, SEEK_SET) == (off_t)-1 ||
807: !read_write(transfer->file->fd, mess->data, size, 1))
808: return -1;
809:
810: transfer->expansion = 0;
811:
812: /* Map '\n' to CR-LF in netascii mode */
813: if (transfer->netascii)
814: {
815: size_t i;
816: int newcarrylf;
817:
818: for (i = 0, newcarrylf = 0; i < size; i++)
819: if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
820: {
821: transfer->expansion++;
822:
823: if (size != transfer->blocksize)
824: size++; /* room in this block */
825: else if (i == size - 1)
826: newcarrylf = 1; /* don't expand LF again if it moves to the next block */
827:
828: /* make space and insert CR */
829: memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
830: mess->data[i] = '\r';
831:
832: i++;
833: }
834: transfer->carrylf = newcarrylf;
835:
836: }
837:
838: return size + 4;
839: }
840: }
841:
842:
843: int do_tftp_script_run(void)
844: {
845: struct tftp_transfer *transfer;
846:
847: if ((transfer = daemon->tftp_done_trans))
848: {
849: daemon->tftp_done_trans = transfer->next;
850: #ifdef HAVE_SCRIPT
851: queue_tftp(transfer->file->size, transfer->file->filename, &transfer->peer);
852: #endif
853: free_transfer(transfer);
854: return 1;
855: }
856:
857: return 0;
858: }
859: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>