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