VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/proxy_tftpd.c@ 51574

Last change on this file since 51574 was 51574, checked in by vboxsync, 10 years ago

NAT/Net: #define LOG_GROUP LOG_GROUP_NAT_SERVICE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 20.9 KB
Line 
1/* -*- indent-tabs-mode: nil; -*- */
2#define LOG_GROUP LOG_GROUP_NAT_SERVICE
3
4#define _USE_WINSTD_ERRNO
5/* XXX: replace POSIX file operations with IPRT, to avoid hacks with errno renamings */
6#include "winutils.h"
7
8#include "proxy.h"
9#include "tftp.h"
10
11#ifndef RT_OS_WINDOWS
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <stdarg.h>
17#include <stdio.h>
18#include <string.h>
19#include <unistd.h>
20#else
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <errno.h>
24#include <fcntl.h>
25#include <io.h>
26#include <stdarg.h>
27#include <stdio.h>
28#include <string.h>
29
30# define O_RDONLY _O_RDONLY
31# define S_ISREG(x) ((x) & _S_IFREG)
32#endif
33
34#include "lwip/timers.h"
35#include "lwip/udp.h"
36
37#include <iprt/string.h>
38
39struct xfer {
40 struct udp_pcb *pcb;
41 int fd;
42 unsigned int ack;
43 struct pbuf *pbuf;
44
45 struct pbuf *oack;
46
47 int rexmit;
48
49 ipX_addr_t peer_ip;
50 u16_t peer_port;
51
52 char *filename;
53 int octet;
54
55 /* options */
56 unsigned int blksize;
57 int blksize_from_opt;
58
59 unsigned int timeout;
60 int timeout_from_opt;
61
62 off_t tsize;
63 int tsize_from_opt;
64};
65
66struct tftpd {
67 struct udp_pcb *pcb;
68 char *root;
69
70#define TFTP_MAX_XFERS 3
71 struct xfer xfers[TFTP_MAX_XFERS];
72};
73
74struct tftp_option {
75 const char *name;
76 int (*getopt)(struct xfer *, const char *);
77 int (*ackopt)(struct xfer *, char **, size_t *);
78};
79
80
81static void tftpd_recv(void *, struct udp_pcb *, struct pbuf *, ip_addr_t *, u16_t);
82
83static void tftpd_rrq(struct pbuf *, ip_addr_t *, u16_t);
84
85static void tftp_xfer_recv(void *, struct udp_pcb *, struct pbuf *, ip_addr_t *, u16_t);
86
87static void tftp_recv_ack(struct xfer *, u16_t);
88static void tftp_fillbuf(struct xfer *);
89static void tftp_send(struct xfer *);
90static void tftp_timeout(void *);
91
92static struct xfer *tftp_xfer_alloc(ip_addr_t *, u16_t);
93static int tftp_xfer_create_pcb(struct xfer *);
94static void tftp_xfer_free(struct xfer *);
95
96static int tftp_parse_filename(struct xfer *, char **, size_t *);
97static int tftp_parse_mode(struct xfer *, char **, size_t *);
98static int tftp_parse_option(struct xfer *, char **, size_t *);
99
100static int tftp_opt_blksize(struct xfer *, const char *);
101static int tftp_opt_timeout(struct xfer *, const char *);
102static int tftp_opt_tsize(struct xfer *, const char *);
103
104static char *tftp_getstr(struct xfer *, const char *, char **, size_t *);
105
106static int tftp_ack_blksize(struct xfer *, char **, size_t *);
107static int tftp_ack_timeout(struct xfer *, char **, size_t *);
108static int tftp_ack_tsize(struct xfer *, char **, size_t *);
109
110static int tftp_add_oack(char **, size_t *, const char *, const char *, ...) __attribute__((format(printf, 4, 5)));
111
112static ssize_t tftp_strnlen(char *, size_t);
113
114static int tftp_internal_error(struct xfer *);
115static int tftp_error(struct xfer *, u16_t, const char *, ...) __attribute__((format(printf, 3, 4)));
116static void tftpd_error(ip_addr_t *, u16_t, u16_t, const char *, ...) __attribute__((format(printf, 4, 5)));
117static struct pbuf *tftp_verror(u16_t, const char *, va_list);
118
119
120/* const */ int report_transient_errors = 1;
121static struct tftpd tftpd;
122
123static struct tftp_option tftp_options[] = {
124 { "blksize", tftp_opt_blksize, tftp_ack_blksize }, /* RFC 2348 */
125 { "timeout", tftp_opt_timeout, tftp_ack_timeout }, /* RFC 2349 */
126 { "tsize", tftp_opt_tsize, tftp_ack_tsize }, /* RFC 2349 */
127 { NULL, NULL, NULL }
128};
129
130
131err_t
132tftpd_init(struct netif *proxy_netif, const char *tftproot)
133{
134 size_t len;
135 err_t error;
136
137 tftpd.root = strdup(tftproot);
138 if (tftpd.root == NULL) {
139 DPRINTF0(("%s: failed to allocate tftpd.root\n", __func__));
140 return ERR_MEM;
141 }
142
143 len = strlen(tftproot);
144 if (tftpd.root[len - 1] == '/') {
145 tftpd.root[len - 1] = '\0';
146 }
147
148 tftpd.pcb = udp_new();
149 if (tftpd.pcb == NULL) {
150 DPRINTF0(("%s: failed to allocate PCB\n", __func__));
151 return ERR_MEM;
152 }
153
154 udp_recv(tftpd.pcb, tftpd_recv, NULL);
155
156 error = udp_bind(tftpd.pcb, &proxy_netif->ip_addr, TFTP_SERVER_PORT);
157 if (error != ERR_OK) {
158 DPRINTF0(("%s: failed to bind PCB\n", __func__));
159 return error;
160 }
161
162 return ERR_OK;
163}
164
165
166static void
167tftpd_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
168 ip_addr_t *addr, u16_t port)
169{
170 u16_t op;
171
172 LWIP_ASSERT1(pcb == tftpd.pcb);
173
174 LWIP_UNUSED_ARG(pcb); /* only in assert */
175 LWIP_UNUSED_ARG(arg);
176
177 if (pbuf_clen(p) > 1) { /* this code assumes contiguous aligned payload */
178 pbuf_free(p);
179 return;
180 }
181
182 op = ntohs(*(u16_t *)p->payload);
183 switch (op) {
184 case TFTP_RRQ:
185 tftpd_rrq(p, addr, port);
186 break;
187
188 case TFTP_WRQ:
189 tftpd_error(addr, port, TFTP_EACCESS, "Permission denied");
190 break;
191
192 default:
193 tftpd_error(addr, port, TFTP_ENOSYS, "Bad opcode %d", op);
194 break;
195 }
196
197 pbuf_free(p);
198}
199
200
201/**
202 * Parse Read Request packet and start new transfer.
203 */
204static void
205tftpd_rrq(struct pbuf *p, ip_addr_t *addr, u16_t port)
206{
207 struct xfer *xfer;
208 char *s;
209 size_t len;
210 int has_options;
211 int status;
212
213 xfer = tftp_xfer_alloc(addr, port);
214 if (xfer == NULL) {
215 return;
216 }
217
218 /* skip opcode */
219 s = (char *)p->payload + sizeof(u16_t);
220 len = p->len - sizeof(u16_t);
221
222
223 /*
224 * Parse RRQ:
225 * filename, mode, [opt1, value1, [...] ]
226 */
227 status = tftp_parse_filename(xfer, &s, &len);
228 if (status < 0) {
229 goto terminate;
230 }
231
232 status = tftp_parse_mode(xfer, &s, &len);
233 if (status < 0) {
234 goto terminate;
235 }
236
237 has_options = 0;
238 while (len > 0) {
239 status = tftp_parse_option(xfer, &s, &len);
240 if (status < 0) {
241 goto terminate;
242 }
243 has_options += status;
244 }
245
246
247 /*
248 * Create OACK packet if necessary.
249 */
250 if (has_options) {
251 xfer->oack = pbuf_alloc(PBUF_RAW, 128, PBUF_RAM);
252 if (xfer->oack != NULL) {
253 struct tftp_option *o;
254
255 ((u16_t *)xfer->oack->payload)[0] = PP_HTONS(TFTP_OACK);
256
257 s = (char *)xfer->oack->payload + sizeof(u16_t);
258 len = xfer->oack->len - sizeof(u16_t);
259
260 for (o = &tftp_options[0]; o->name != NULL; ++o) {
261 status = (*o->ackopt)(xfer, &s, &len);
262 if (status < 0) {
263 pbuf_free(xfer->oack);
264 xfer->oack = NULL;
265 break;
266 }
267 }
268
269 if (xfer->oack != NULL) {
270 pbuf_realloc(xfer->oack, xfer->oack->len - len);
271 }
272 }
273 }
274
275
276 /*
277 * Create static pbuf that will be used for all data packets.
278 */
279 xfer->pbuf = pbuf_alloc(PBUF_RAW, xfer->blksize + 4, PBUF_RAM);
280 if (xfer->pbuf == NULL) {
281 tftp_internal_error(xfer);
282 goto terminate;
283 }
284 ((u16_t *)xfer->pbuf->payload)[0] = PP_HTONS(TFTP_DATA);
285
286
287 /*
288 * Finally, create PCB. Before this point any error was reported
289 * from the server port (see tftp_error() for the reason).
290 */
291 status = tftp_xfer_create_pcb(xfer);
292 if (status < 0) {
293 goto terminate;
294 }
295
296 if (xfer->oack) {
297 tftp_send(xfer);
298 }
299 else {
300 /* trigger send of the first data packet */
301 tftp_recv_ack(xfer, 0);
302 }
303
304 return;
305
306 terminate:
307 DPRINTF(("%s: terminated", __func__));
308 tftp_xfer_free(xfer);
309}
310
311
312static void
313tftp_xfer_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
314 ip_addr_t *addr, u16_t port)
315{
316 struct xfer *xfer = (struct xfer *)arg;
317 u16_t op;
318
319 LWIP_UNUSED_ARG(pcb); /* assert only */
320 LWIP_UNUSED_ARG(addr);
321 LWIP_UNUSED_ARG(port);
322
323 LWIP_ASSERT1(xfer->pcb == pcb);
324
325 if (p->len < 2) {
326 tftp_error(xfer, TFTP_ENOSYS, "Short packet");
327 tftp_xfer_free(xfer);
328 pbuf_free(p);
329 return;
330 }
331
332 op = ntohs(*(u16_t *)p->payload);
333 if (op == TFTP_ACK) {
334 u16_t ack;
335
336 if (p->len < 4) {
337 tftp_error(xfer, TFTP_ENOSYS, "Short packet");
338 tftp_xfer_free(xfer);
339 pbuf_free(p);
340 return;
341 }
342
343 ack = ntohs(((u16_t *)p->payload)[1]);
344 tftp_recv_ack(xfer, ack);
345 }
346 else if (op == TFTP_ERROR) {
347 tftp_xfer_free(xfer);
348 }
349 else {
350 tftp_error(xfer, TFTP_ENOSYS, "Unexpected opcode %d", op);
351 tftp_xfer_free(xfer);
352 }
353
354 pbuf_free(p);
355}
356
357
358static void
359tftp_recv_ack(struct xfer *xfer, u16_t ack)
360{
361 if (ack != (u16_t)xfer->ack) {
362 DPRINTF2(("%s: expect %u (%u), got %u\n",
363 __func__, (u16_t)xfer->ack, xfer->ack, ack));
364 return;
365 }
366
367 sys_untimeout(tftp_timeout, xfer);
368 xfer->rexmit = 0;
369
370 if (xfer->pbuf->len < xfer->blksize) {
371 DPRINTF(("%s: got final ack %u (%u)\n",
372 __func__, (u16_t)xfer->ack, xfer->ack));
373 tftp_xfer_free(xfer);
374 return;
375 }
376
377 if (xfer->oack != NULL) {
378 pbuf_free(xfer->oack);
379 xfer->oack = NULL;
380 }
381
382 ++xfer->ack;
383 tftp_fillbuf(xfer);
384 tftp_send(xfer);
385}
386
387
388static void
389tftp_send(struct xfer *xfer)
390{
391 struct pbuf *pbuf;
392
393 pbuf = xfer->oack ? xfer->oack : xfer->pbuf;
394 udp_send(xfer->pcb, pbuf);
395 sys_timeout(xfer->timeout * 1000, tftp_timeout, xfer);
396}
397
398
399static void
400tftp_timeout(void *arg)
401{
402 struct xfer *xfer = (struct xfer *)arg;
403 int maxrexmit;
404
405 maxrexmit = xfer->timeout < 60 ? 5 : 3;
406 if (++xfer->rexmit < maxrexmit) {
407 tftp_send(xfer);
408 }
409 else {
410 tftp_xfer_free(xfer);
411 }
412}
413
414
415static void
416tftp_fillbuf(struct xfer *xfer)
417{
418 ssize_t nread;
419
420 DPRINTF2(("%s: reading block %u\n", __func__, xfer->ack));
421
422 ((u16_t *)xfer->pbuf->payload)[1] = htons(xfer->ack);
423 nread = read(xfer->fd, (char *)xfer->pbuf->payload + 4, xfer->blksize);
424
425 if (nread < 0) {
426 tftp_error(xfer, TFTP_EUNDEF, "Read failed");
427 return;
428 }
429
430 pbuf_realloc(xfer->pbuf, nread + 4);
431}
432
433
434/**
435 * Find a free transfer slot (without a pcb). Record peer's IP
436 * address and port, but don't allocate a pcb yet.
437 *
438 * We delay creation of the pcb in response to the original request
439 * until the request is verified and accepted. This makes using
440 * tcpdump(8) easier, since tcpdump does not track TFTP transfers, so
441 * an error reply from a new pcb is not recognized as such and is not
442 * decoded as TFTP (see tftp_error()).
443 *
444 * If the request is rejected, the pcb remains NULL and the transfer
445 * slot remains unallocated. Since all TFTP processing happens on the
446 * lwIP thread, there's no concurrent processing, so we don't need to
447 * "lock" the transfer slot until the pcb is allocated.
448 */
449static struct xfer *
450tftp_xfer_alloc(ip_addr_t *addr, u16_t port)
451{
452 struct xfer *xfer;
453 int i;
454
455 /* Find free xfer slot */
456 xfer = NULL;
457 for (i = 0; i < TFTP_MAX_XFERS; ++i) {
458 if (tftpd.xfers[i].pcb == NULL) {
459 xfer = &tftpd.xfers[i];
460 break;
461 }
462 }
463
464 if (xfer == NULL) {
465 if (report_transient_errors) {
466 tftpd_error(addr, port, TFTP_EUNDEF,
467 "Maximum number of simultaneous connections exceeded");
468 }
469 return NULL;
470 }
471
472 ipX_addr_copy(0, xfer->peer_ip, *ip_2_ipX(addr));
473 xfer->peer_port = port;
474
475 xfer->ack = 0;
476
477 xfer->pbuf = NULL;
478 xfer->oack = NULL;
479 xfer->rexmit = 0;
480
481 xfer->blksize = 512;
482 xfer->blksize_from_opt = 0;
483
484 xfer->timeout = 1;
485 xfer->timeout_from_opt = 0;
486
487 xfer->tsize = -1;
488 xfer->tsize_from_opt = 0;
489
490 return xfer;
491}
492
493
494static int
495tftp_xfer_create_pcb(struct xfer *xfer)
496{
497 struct udp_pcb *pcb;
498 err_t error;
499
500 pcb = udp_new();
501
502 /* Bind */
503 if (pcb != NULL) {
504 error = udp_bind(pcb, ipX_2_ip(&tftpd.pcb->local_ip), 0);
505 if (error != ERR_OK) {
506 udp_remove(pcb);
507 pcb = NULL;
508 }
509 }
510
511 /* Connect */
512 if (pcb != NULL) {
513 error = udp_connect(pcb, ipX_2_ip(&xfer->peer_ip), xfer->peer_port);
514 if (error != ERR_OK) {
515 udp_remove(pcb);
516 pcb = NULL;
517 }
518 }
519
520 if (pcb == NULL) {
521 if (report_transient_errors) {
522 tftp_error(xfer, TFTP_EUNDEF, "Failed to create connection");
523 }
524 return -1;
525 }
526
527 xfer->pcb = pcb;
528 udp_recv(xfer->pcb, tftp_xfer_recv, xfer);
529
530 return 0;
531}
532
533
534static void
535tftp_xfer_free(struct xfer *xfer)
536{
537 sys_untimeout(tftp_timeout, xfer);
538
539 if (xfer->pcb != NULL) {
540 udp_remove(xfer->pcb);
541 xfer->pcb = NULL;
542 }
543
544 if (xfer->fd > 0) {
545 close(xfer->fd);
546 xfer->fd = -1;
547 }
548
549 if (xfer->oack != NULL) {
550 pbuf_free(xfer->oack);
551 xfer->oack = NULL;
552 }
553
554 if (xfer->pbuf != NULL) {
555 pbuf_free(xfer->pbuf);
556 xfer->pbuf = NULL;
557 }
558
559 if (xfer->filename != NULL) {
560 free(xfer->filename);
561 xfer->filename = NULL;
562 }
563}
564
565
566static int
567tftp_parse_filename(struct xfer *xfer, char **ps, size_t *plen)
568{
569 const char *filename;
570 struct stat st;
571 char *pathname;
572 char *s;
573 size_t len;
574 int status;
575
576 filename = tftp_getstr(xfer, "filename", ps, plen);
577 if (filename == NULL) {
578 return -1;
579 }
580
581 DPRINTF(("%s: requested file name: %s\n", __func__, filename));
582 xfer->filename = strdup(filename);
583 if (xfer->filename == NULL) {
584 return tftp_internal_error(xfer);
585 }
586
587 /* replace backslashes with forward slashes */
588 s = xfer->filename;
589 while ((s = strchr(s, '\\')) != NULL) {
590 *s++ = '/';
591 }
592
593 /* deny attempts to break out of tftp dir */
594 if (strncmp(xfer->filename, "../", 3) == 0
595 || strstr(xfer->filename, "/../") != NULL)
596 {
597 return tftp_error(xfer, TFTP_ENOENT, "Permission denied");
598 }
599
600 len = strlen(tftpd.root) + 1 /*slash*/ + strlen(xfer->filename) + 1 /*nul*/;
601 pathname = (char *)malloc(len);
602 if (pathname == NULL) {
603 return tftp_internal_error(xfer);
604 }
605
606 status = RTStrPrintf(pathname, len, "%s/%s", tftpd.root, xfer->filename);
607 if (status < 0) {
608 return tftp_internal_error(xfer);
609 }
610
611 DPRINTF(("%s: full pathname: %s\n", __func__, pathname));
612 xfer->fd = open(pathname, O_RDONLY);
613 if (xfer->fd < 0) {
614 if (errno == EPERM) {
615 return tftp_error(xfer, TFTP_ENOENT, "Permission denied");
616 }
617 else {
618 return tftp_error(xfer, TFTP_ENOENT, "File not found");
619 }
620 }
621
622 status = fstat(xfer->fd, &st);
623 if (status < 0) {
624 return tftp_internal_error(xfer);
625 }
626
627 if (!S_ISREG(st.st_mode)) {
628 return tftp_error(xfer, TFTP_ENOENT, "File not found");
629 }
630
631 xfer->tsize = st.st_size;
632 return 0;
633}
634
635
636static int
637tftp_parse_mode(struct xfer *xfer, char **ps, size_t *plen)
638{
639 const char *modename;
640
641 modename = tftp_getstr(xfer, "mode", ps, plen);
642 if (modename == NULL) {
643 return -1;
644 }
645
646 if (RTStrICmp(modename, "octet") == 0) {
647 xfer->octet = 1;
648 }
649 else if (RTStrICmp(modename, "netascii") == 0) {
650 xfer->octet = 0;
651 /* XXX: not (yet?) */
652 return tftp_error(xfer, TFTP_ENOSYS, "Mode \"netascii\" not supported");
653 }
654 else if (RTStrICmp(modename, "mail") == 0) {
655 return tftp_error(xfer, TFTP_ENOSYS, "Mode \"mail\" not supported");
656 }
657 else {
658 return tftp_error(xfer, TFTP_ENOSYS, "Unknown mode \"%s\"", modename);
659 }
660
661 return 0;
662}
663
664
665static int
666tftp_parse_option(struct xfer *xfer, char **ps, size_t *plen)
667{
668 const char *opt;
669 const char *val;
670 struct tftp_option *o;
671
672 opt = tftp_getstr(xfer, "option name", ps, plen);
673 if (opt == NULL) {
674 return -1;
675 }
676
677 if (*plen == 0) {
678 return tftp_error(xfer, TFTP_EUNDEF, "Missing option value");
679 }
680
681 val = tftp_getstr(xfer, "option value", ps, plen);
682 if (val == NULL) {
683 return -1;
684 }
685
686 /* handle option if known, ignore otherwise */
687 for (o = &tftp_options[0]; o->name != NULL; ++o) {
688 if (RTStrICmp(o->name, opt) == 0) {
689 return (*o->getopt)(xfer, val);
690 }
691 }
692
693 return 0; /* unknown option */
694}
695
696
697static int
698tftp_opt_blksize(struct xfer *xfer, const char *optval)
699{
700 char *end;
701 long blksize;
702
703 errno = 0;
704 blksize = strtol(optval, &end, 10);
705 if (errno != 0 || *end != '\0') {
706 return 0;
707 }
708
709 if (blksize < 8) {
710 return 0;
711 }
712
713 if (blksize > 1428) { /* exceeds ethernet mtu */
714 blksize = 1428;
715 }
716
717 xfer->blksize = blksize;
718 xfer->blksize_from_opt = 1;
719 return 1;
720}
721
722
723static int
724tftp_opt_timeout(struct xfer *xfer, const char *optval)
725{
726 LWIP_UNUSED_ARG(xfer);
727 LWIP_UNUSED_ARG(optval);
728 return 0;
729}
730
731
732static int
733tftp_opt_tsize(struct xfer *xfer, const char *optval)
734{
735 LWIP_UNUSED_ARG(optval); /* must be "0", but we don't check it */
736
737 if (xfer->tsize < 0) {
738 return 0;
739 }
740
741 xfer->tsize_from_opt = 1;
742 return 1;
743}
744
745
746static char *
747tftp_getstr(struct xfer *xfer, const char *msg, char **ps, size_t *plen)
748{
749 char *s;
750 ssize_t slen;
751
752 s = *ps;
753 slen = tftp_strnlen(s, *plen);
754 if (slen < 0) {
755 tftp_error(xfer, TFTP_EUNDEF, "Unterminated %s", msg);
756 return NULL;
757 }
758
759 *ps += slen + 1;
760 *plen -= slen + 1;
761
762 return s;
763}
764
765
766static int
767tftp_ack_blksize(struct xfer *xfer, char **ps, size_t *plen)
768{
769 if (!xfer->blksize_from_opt) {
770 return 0;
771 }
772
773 return tftp_add_oack(ps, plen, "blksize", "%u", xfer->blksize);
774}
775
776
777static int
778tftp_ack_timeout(struct xfer *xfer, char **ps, size_t *plen)
779{
780 if (!xfer->timeout_from_opt) {
781 return 0;
782 }
783
784 return tftp_add_oack(ps, plen, "timeout", "%u", xfer->timeout);
785}
786
787
788static int
789tftp_ack_tsize(struct xfer *xfer, char **ps, size_t *plen)
790{
791 if (!xfer->tsize_from_opt) {
792 return 0;
793 }
794
795 LWIP_ASSERT1(xfer->tsize >= 0);
796 return tftp_add_oack(ps, plen, "tsize",
797 /* XXX: FIXME: want 64 bit */
798 "%lu", (unsigned long)xfer->tsize);
799}
800
801
802static int
803tftp_add_oack(char **ps, size_t *plen,
804 const char *optname, const char *fmt, ...)
805{
806 va_list ap;
807 int sz;
808
809 sz = RTStrPrintf(*ps, *plen, "%s", optname);
810 if (sz < 0 || (size_t)sz >= *plen) {
811 return -1;
812 }
813
814 ++sz; /* for nul byte */
815 *ps += sz;
816 *plen -= sz;
817
818 va_start(ap, fmt);
819 sz = vsnprintf(*ps, *plen, fmt, ap);
820 va_end(ap);
821 if (sz < 0 || (size_t)sz >= *plen) {
822 return -1;
823 }
824
825 ++sz; /* for nul byte */
826 *ps += sz;
827 *plen -= sz;
828
829 return 0;
830}
831
832
833static ssize_t
834tftp_strnlen(char *buf, size_t bufsize)
835{
836 void *end;
837
838 end = memchr(buf, '\0', bufsize);
839 if (end == NULL) {
840 return -1;
841 }
842
843 return (char *)end - buf;
844}
845
846
847static int
848tftp_internal_error(struct xfer *xfer)
849{
850 if (report_transient_errors) {
851 tftp_error(xfer, TFTP_EUNDEF, "Internal error");
852 }
853 return -1;
854}
855
856
857/**
858 * Send an error packet to the peer.
859 *
860 * PCB may not be created yet in which case send the error packet from
861 * the TFTP server port (*).
862 *
863 * (*) We delay creation of the PCB in response to the original
864 * request until the request is verified and accepted. This makes
865 * using tcpdump(8) easier, since tcpdump does not track TFTP
866 * transfers, so an error reply from a new PCB is not recognized as
867 * such and is not decoded as TFTP.
868 *
869 * Always returns -1 for callers to reuse.
870 */
871static int
872tftp_error(struct xfer *xfer, u16_t error, const char *fmt, ...)
873{
874 va_list ap;
875 struct pbuf *q;
876
877 LWIP_ASSERT1(xfer != NULL);
878
879 va_start(ap, fmt);
880 q = tftp_verror(error, fmt, ap);
881 va_end(ap);
882
883 if (q == NULL) {
884 return -1;
885 }
886
887 if (xfer->pcb != NULL) {
888 udp_send(xfer->pcb, q);
889 }
890 else {
891 udp_sendto(tftpd.pcb, q, ipX_2_ip(&xfer->peer_ip), xfer->peer_port);
892 }
893
894 pbuf_free(q);
895 return -1;
896}
897
898
899/**
900 * Send an error packet from TFTP server port to the specified peer.
901 */
902static void
903tftpd_error(ip_addr_t *addr, u16_t port, u16_t error, const char *fmt, ...)
904{
905 va_list ap;
906 struct pbuf *q;
907
908 va_start(ap, fmt);
909 q = tftp_verror(error, fmt, ap);
910 va_end(ap);
911
912 if (q != NULL) {
913 udp_sendto(tftpd.pcb, q, addr, port);
914 pbuf_free(q);
915 }
916}
917
918
919/**
920 * Create ERROR pbuf with formatted error message.
921 */
922static struct pbuf *
923tftp_verror(u16_t error, const char *fmt, va_list ap)
924{
925 struct tftp_error {
926 u16_t opcode; /* TFTP_ERROR */
927 u16_t errcode;
928 char errmsg[512];
929 };
930
931 struct pbuf *p;
932 struct tftp_error *errpkt;
933 int msgsz;
934
935 p = pbuf_alloc(PBUF_TRANSPORT, sizeof(*errpkt), PBUF_RAM);
936 if (p == NULL) {
937 return NULL;
938 }
939
940 errpkt = (struct tftp_error *)p->payload;
941 errpkt->opcode = PP_HTONS(TFTP_ERROR);
942 errpkt->errcode = htons(error);
943
944 msgsz = vsnprintf(errpkt->errmsg, sizeof(errpkt->errmsg), fmt, ap);
945 if (msgsz < 0) {
946 errpkt->errmsg[0] = '\0';
947 msgsz = 1;
948 }
949 else if ((size_t)msgsz < sizeof(errpkt->errmsg)) {
950 ++msgsz; /* for nul byte */
951 }
952 else {
953 msgsz = sizeof(errpkt->errmsg); /* truncated, includes nul byte */
954 }
955
956 pbuf_realloc(p, sizeof(*errpkt) - sizeof(errpkt->errmsg) + msgsz);
957 return p;
958}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette