Bug Summary

File:src/usr.sbin/tftpd/tftpd.c
Warning:line 474, column 26
Access to field 's' results in a dereference of a null pointer (loaded from variable 'rwmap')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name tftpd.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/tftpd/obj -resource-dir /usr/local/llvm16/lib/clang/16 -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/tftpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/tftpd/tftpd.c
1/* $OpenBSD: tftpd.c,v 1.50 2022/10/09 23:04:57 kn Exp $ */
2
3/*
4 * Copyright (c) 2012 David Gwynne <dlg@uq.edu.au>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/*
20 * Copyright (c) 1983 Regents of the University of California.
21 * All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 3. Neither the name of the University nor the names of its contributors
32 * may be used to endorse or promote products derived from this software
33 * without specific prior written permission.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 * SUCH DAMAGE.
46 */
47
48/*
49 * Trivial file transfer protocol server.
50 *
51 * This version is based on src/libexec/tftpd which includes many
52 * modifications by Jim Guyton <guyton@rand-unix>.
53 *
54 * It was restructured to be a persistent event driven daemon
55 * supporting concurrent connections by dlg for use at the University
56 * of Queensland in the Faculty of Engineering Architecture and
57 * Information Technology.
58 */
59
60#include <sys/types.h>
61#include <sys/queue.h>
62#include <sys/socket.h>
63#include <sys/stat.h>
64#include <sys/uio.h>
65#include <sys/un.h>
66
67#include <netinet/in.h>
68#include <arpa/inet.h>
69#include <arpa/tftp.h>
70#include <netdb.h>
71
72#include <err.h>
73#include <ctype.h>
74#include <errno(*__errno()).h>
75#include <event.h>
76#include <fcntl.h>
77#include <paths.h>
78#include <poll.h>
79#include <pwd.h>
80#include <stdio.h>
81#include <stdlib.h>
82#include <string.h>
83#include <stdarg.h>
84#include <syslog.h>
85#include <unistd.h>
86#include <limits.h>
87#include <vis.h>
88
89#define TIMEOUT5 5 /* packet rexmt timeout */
90#define TIMEOUT_MIN1 1 /* minimal packet rexmt timeout */
91#define TIMEOUT_MAX255 255 /* maximal packet rexmt timeout */
92
93#define RETRIES5 5
94
95#define SEEDPATH"/etc/random.seed" "/etc/random.seed"
96
97struct formats;
98
99enum opt_enum {
100 OPT_TSIZE = 0,
101 OPT_TIMEOUT,
102 OPT_BLKSIZE,
103 NOPT
104};
105
106static char *opt_names[] = {
107 "tsize",
108 "timeout",
109 "blksize"
110};
111
112struct opt_client {
113 char *o_request;
114 long long o_reply;
115};
116
117
118struct tftp_server {
119 struct event ev;
120 TAILQ_ENTRY(tftp_server)struct { struct tftp_server *tqe_next; struct tftp_server **tqe_prev
; }
entry;
121 int s;
122};
123
124TAILQ_HEAD(, tftp_server)struct { struct tftp_server *tqh_first; struct tftp_server **
tqh_last; }
tftp_servers;
125
126struct tftp_client {
127 char buf[SEGSIZE_MAX65464 + 4];
128 struct event sev;
129 struct sockaddr_storage ss;
130
131 struct timeval tv;
132
133 TAILQ_ENTRY(tftp_client)struct { struct tftp_client *tqe_next; struct tftp_client **tqe_prev
; }
entry;
134
135 struct opt_client *options;
136
137 size_t segment_size;
138 size_t packet_size;
139 size_t buflen;
140
141 FILE *file;
142 int (*fgetc)(struct tftp_client *);
143 int (*fputc)(struct tftp_client *, int);
144
145 u_int retries;
146 u_int16_t block;
147
148 int opcode;
149 int newline;
150
151 int sock;
152};
153
154__dead__attribute__((__noreturn__)) void usage(void);
155const char *getip(void *);
156int rdaemon(int);
157
158void rewrite_connect(const char *);
159void rewrite_events(void);
160void rewrite_map(struct tftp_client *, const char *);
161void rewrite_req(int, short, void *);
162void rewrite_res(int, short, void *);
163
164int tftpd_listen(const char *, const char *, int);
165void tftpd_events(void);
166void tftpd_recv(int, short, void *);
167int retry(struct tftp_client *);
168int tftp_flush(struct tftp_client *);
169void tftp_end(struct tftp_client *);
170
171void tftp(struct tftp_client *, struct tftphdr *, size_t);
172void tftp_open(struct tftp_client *, const char *);
173void nak(struct tftp_client *, int);
174int oack(struct tftp_client *);
175void oack_done(int, short, void *);
176
177void sendfile(struct tftp_client *);
178void recvfile(struct tftp_client *);
179int fget_octet(struct tftp_client *);
180int fput_octet(struct tftp_client *, int);
181int fget_netascii(struct tftp_client *);
182int fput_netascii(struct tftp_client *, int);
183void file_read(struct tftp_client *);
184void tftp_send(struct tftp_client *);
185int tftp_wrq_ack_packet(struct tftp_client *);
186void tftp_rrq_ack(int, short, void *);
187void tftp_wrq_ack(struct tftp_client *client);
188void tftp_wrq(int, short, void *);
189void tftp_wrq_end(int, short, void *);
190
191int parse_options(struct tftp_client *, char *, size_t,
192 struct opt_client *);
193int validate_access(struct tftp_client *, const char *);
194
195struct tftp_client *
196 client_alloc(void);
197void client_free(struct tftp_client *client);
198
199struct formats {
200 const char *f_mode;
201 int (*f_getc)(struct tftp_client *);
202 int (*f_putc)(struct tftp_client *, int);
203} formats[] = {
204 { "octet", fget_octet, fput_octet },
205 { "netascii", fget_netascii, fput_netascii },
206 { NULL((void *)0), NULL((void *)0) }
207};
208
209struct errmsg {
210 int e_code;
211 const char *e_msg;
212} errmsgs[] = {
213 { EUNDEF0, "Undefined error code" },
214 { ENOTFOUND1, "File not found" },
215 { EACCESS2, "Access violation" },
216 { ENOSPACE3, "Disk full or allocation exceeded" },
217 { EBADOP4, "Illegal TFTP operation" },
218 { EBADID5, "Unknown transfer ID" },
219 { EEXISTS6, "File already exists" },
220 { ENOUSER7, "No such user" },
221 { EOPTNEG8, "Option negotiation failed" },
222 { -1, NULL((void *)0) }
223};
224
225struct loggers {
226 __dead__attribute__((__noreturn__)) void (*err)(int, const char *, ...)
227 __attribute__((__format__ (printf, 2, 3)));
228 __dead__attribute__((__noreturn__)) void (*errx)(int, const char *, ...)
229 __attribute__((__format__ (printf, 2, 3)));
230 void (*warn)(const char *, ...)
231 __attribute__((__format__ (printf, 1, 2)));
232 void (*warnx)(const char *, ...)
233 __attribute__((__format__ (printf, 1, 2)));
234 void (*info)(const char *, ...)
235 __attribute__((__format__ (printf, 1, 2)));
236 void (*debug)(const char *, ...)
237 __attribute__((__format__ (printf, 1, 2)));
238};
239
240const struct loggers conslogger = {
241 err,
242 errx,
243 warn,
244 warnx,
245 warnx, /* info */
246 warnx /* debug */
247};
248
249__dead__attribute__((__noreturn__)) void syslog_err(int, const char *, ...)
250 __attribute__((__format__ (printf, 2, 3)));
251__dead__attribute__((__noreturn__)) void syslog_errx(int, const char *, ...)
252 __attribute__((__format__ (printf, 2, 3)));
253void syslog_warn(const char *, ...)
254 __attribute__((__format__ (printf, 1, 2)));
255void syslog_warnx(const char *, ...)
256 __attribute__((__format__ (printf, 1, 2)));
257void syslog_info(const char *, ...)
258 __attribute__((__format__ (printf, 1, 2)));
259void syslog_debug(const char *, ...)
260 __attribute__((__format__ (printf, 1, 2)));
261void syslog_vstrerror(int, int, const char *, va_list)
262 __attribute__((__format__ (printf, 3, 0)));
263
264const struct loggers syslogger = {
265 syslog_err,
266 syslog_errx,
267 syslog_warn,
268 syslog_warnx,
269 syslog_info,
270 syslog_debug
271};
272
273const struct loggers *logger = &conslogger;
274
275#define lerr(_e, _f...)logger->err((_e), _f...) logger->err((_e), _f)
276#define lerrx(_e, _f...)logger->errx((_e), _f...) logger->errx((_e), _f)
277#define lwarn(_f...)logger->warn(_f...) logger->warn(_f)
278#define lwarnx(_f...)logger->warnx(_f...) logger->warnx(_f)
279#define linfo(_f...)logger->info(_f...) logger->info(_f)
280#define ldebug(_f...)logger->debug(_f...) logger->debug(_f)
281
282__dead__attribute__((__noreturn__)) void
283usage(void)
284{
285 extern char *__progname;
286 fprintf(stderr(&__sF[2]), "usage: %s [-46cdivw] [-l address] [-p port] [-r socket]"
287 " directory\n", __progname);
288 exit(1);
289}
290
291int cancreate = 0;
292int canwrite = 0;
293int verbose = 0;
294int debug = 0;
295int iflag = 0;
296
297int
298main(int argc, char *argv[])
299{
300 extern char *__progname;
301
302 int c;
303 struct passwd *pw;
304
305 char *dir = NULL((void *)0);
306 char *rewrite = NULL((void *)0);
307
308 char *addr = NULL((void *)0);
309 char *port = "tftp";
310 int family = AF_UNSPEC0;
311 int devnull = -1;
312
313 while ((c = getopt(argc, argv, "46cdil:p:r:vw")) != -1) {
1
Assuming the condition is true
2
Loop condition is true. Entering loop body
4
Execution continues on line 313
5
Assuming the condition is true
6
Loop condition is true. Entering loop body
9
Execution continues on line 313
10
Assuming the condition is true
11
Loop condition is true. Entering loop body
13
Execution continues on line 313
14
Assuming the condition is false
15
Loop condition is false. Execution continues on line 355
314 switch (c) {
3
Control jumps to 'case 112:' at line 335
7
Control jumps to 'case 114:' at line 338
12
Control jumps to 'case 100:' at line 324
315 case '4':
316 family = AF_INET2;
317 break;
318 case '6':
319 family = AF_INET624;
320 break;
321 case 'c':
322 canwrite = cancreate = 1;
323 break;
324 case 'd':
325 verbose = debug = 1;
326 break;
327 case 'i':
328 if (rewrite != NULL((void *)0))
329 errx(1, "options -i and -r are incompatible");
330 iflag = 1;
331 break;
332 case 'l':
333 addr = optarg;
334 break;
335 case 'p':
336 port = optarg;
337 break;
338 case 'r':
339 if (iflag
7.1
'iflag' is not equal to 1
== 1)
8
Taking false branch
340 errx(1, "options -i and -r are incompatible");
341 rewrite = optarg;
342 break;
343 case 'v':
344 verbose = 1;
345 break;
346 case 'w':
347 canwrite = 1;
348 break;
349 default:
350 usage();
351 /* NOTREACHED */
352 }
353 }
354
355 argc -= optind;
356 argv += optind;
357
358 if (argc != 1)
16
Assuming 'argc' is equal to 1
17
Taking false branch
359 usage();
360
361 dir = argv[0];
362
363 if (geteuid() != 0)
18
Assuming the condition is false
19
Taking false branch
364 errx(1, "need root privileges");
365
366 pw = getpwnam("_tftpd");
367 if (pw == NULL((void *)0))
20
Assuming 'pw' is not equal to NULL
21
Taking false branch
368 errx(1, "no _tftpd user");
369
370 if (!debug
21.1
'debug' is 1
) {
22
Taking false branch
371 openlog(__progname, LOG_PID0x01|LOG_NDELAY0x08, LOG_DAEMON(3<<3));
372 tzset();
373 logger = &syslogger;
374 devnull = open(_PATH_DEVNULL"/dev/null", O_RDWR0x0002);
375 if (devnull == -1)
376 err(1, "open %s", _PATH_DEVNULL"/dev/null");
377 }
378
379 if (rewrite != NULL((void *)0))
23
Assuming 'rewrite' is not equal to NULL
24
Taking true branch
380 rewrite_connect(rewrite);
381
382 tftpd_listen(addr, port, family);
383
384 if (chroot(dir))
25
Assuming the condition is false
26
Taking false branch
385 err(1, "chroot %s", dir);
386 if (chdir("/"))
27
Assuming the condition is false
387 err(1, "chdir %s", dir);
388
389 /* drop privs */
390 if (setgroups(1, &pw->pw_gid) ||
28
Assuming the condition is false
391 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
29
Assuming the condition is false
392 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
30
Assuming the condition is false
393 errx(1, "can't drop privileges");
394
395 if (!debug
30.1
'debug' is 0
&& rdaemon(devnull) == -1)
31
Assuming the condition is false
32
Taking false branch
396 err(1, "unable to daemonize");
397
398 if (cancreate
32.1
'cancreate' is 0
) {
33
Taking false branch
399 if (pledge("stdio rpath wpath cpath fattr dns inet", NULL((void *)0)) == -1)
400 lerr(1, "pledge")logger->err((1), "pledge");
401 } else if (canwrite
33.1
'canwrite' is 0
) {
34
Taking false branch
402 if (pledge("stdio rpath wpath dns inet", NULL((void *)0)) == -1)
403 lerr(1, "pledge")logger->err((1), "pledge");
404 } else {
405 if (pledge("stdio rpath dns inet", NULL((void *)0)) == -1)
35
Assuming the condition is false
36
Taking false branch
406 lerr(1, "pledge")logger->err((1), "pledge");
407 }
408
409 event_init();
410
411 if (rewrite
36.1
'rewrite' is not equal to NULL
!= NULL((void *)0))
37
Taking true branch
412 rewrite_events();
38
Calling 'rewrite_events'
413
414 tftpd_events();
415
416 event_dispatch();
417
418 exit(0);
419}
420
421struct rewritemap {
422 struct event wrev;
423 struct event rdev;
424 struct evbuffer *wrbuf;
425 struct evbuffer *rdbuf;
426
427 TAILQ_HEAD(, tftp_client)struct { struct tftp_client *tqh_first; struct tftp_client **
tqh_last; }
clients;
428
429 int s;
430};
431
432struct rewritemap *rwmap = NULL((void *)0);
433
434void
435rewrite_connect(const char *path)
436{
437 int s;
438 struct sockaddr_un remote;
439 size_t len;
440
441 rwmap = malloc(sizeof(*rwmap));
442 if (rwmap == NULL((void *)0))
443 err(1, "rewrite event malloc");
444
445 rwmap->wrbuf = evbuffer_new();
446 if (rwmap->wrbuf == NULL((void *)0))
447 err(1, "rewrite wrbuf");
448
449 rwmap->rdbuf = evbuffer_new();
450 if (rwmap->rdbuf == NULL((void *)0))
451 err(1, "rewrite rdbuf");
452
453 TAILQ_INIT(&rwmap->clients)do { (&rwmap->clients)->tqh_first = ((void *)0); (&
rwmap->clients)->tqh_last = &(&rwmap->clients
)->tqh_first; } while (0)
;
454
455 s = socket(AF_UNIX1, SOCK_STREAM1 | SOCK_NONBLOCK0x4000, 0);
456 if (s == -1)
457 err(1, "rewrite socket");
458
459 remote.sun_family = AF_UNIX1;
460 len = strlcpy(remote.sun_path, path, sizeof(remote.sun_path));
461 if (len >= sizeof(remote.sun_path))
462 errx(1, "rewrite socket path is too long");
463
464 len += sizeof(remote.sun_family) + 1;
465 if (connect(s, (struct sockaddr *)&remote, len) == -1)
466 err(1, "%s", path);
467
468 rwmap->s = s;
469}
470
471void
472rewrite_events(void)
473{
474 event_set(&rwmap->wrev, rwmap->s, EV_WRITE0x04, rewrite_req, NULL((void *)0));
39
Access to field 's' results in a dereference of a null pointer (loaded from variable 'rwmap')
475 event_set(&rwmap->rdev, rwmap->s, EV_READ0x02 | EV_PERSIST0x10, rewrite_res, NULL((void *)0));
476 event_add(&rwmap->rdev, NULL((void *)0));
477}
478
479void
480rewrite_map(struct tftp_client *client, const char *filename)
481{
482 char *nicebuf;
483
484 if (stravis(&nicebuf, filename, VIS_SAFE0x20|VIS_OCTAL0x01) == -1)
485 lerr(1, "rwmap stravis")logger->err((1), "rwmap stravis");
486
487 if (evbuffer_add_printf(rwmap->wrbuf, "%s %s %s\n", getip(&client->ss),
488 client->opcode == WRQ02 ? "write" : "read", nicebuf) == -1)
489 lerr(1, "rwmap printf")logger->err((1), "rwmap printf");
490
491 free(nicebuf);
492
493 TAILQ_INSERT_TAIL(&rwmap->clients, client, entry)do { (client)->entry.tqe_next = ((void *)0); (client)->
entry.tqe_prev = (&rwmap->clients)->tqh_last; *(&
rwmap->clients)->tqh_last = (client); (&rwmap->clients
)->tqh_last = &(client)->entry.tqe_next; } while (0
)
;
494
495 event_add(&rwmap->wrev, NULL((void *)0));
496}
497
498void
499rewrite_req(int fd, short events, void *arg)
500{
501 if (evbuffer_write(rwmap->wrbuf, fd) == -1) {
502 switch (errno(*__errno())) {
503 case EINTR4:
504 case EAGAIN35:
505 event_add(&rwmap->wrev, NULL((void *)0));
506 return;
507 }
508
509 lerr(1, "rewrite socket write")logger->err((1), "rewrite socket write");
510 }
511
512 if (EVBUFFER_LENGTH(rwmap->wrbuf)(rwmap->wrbuf)->off)
513 event_add(&rwmap->wrev, NULL((void *)0));
514}
515
516void
517rewrite_res(int fd, short events, void *arg)
518{
519 struct tftp_client *client;
520 char *filename;
521 size_t len;
522
523 switch (evbuffer_read(rwmap->rdbuf, fd, PATH_MAX1024)) {
524 case -1:
525 switch (errno(*__errno())) {
526 case EINTR4:
527 case EAGAIN35:
528 return;
529 }
530 lerr(1, "rewrite socket read")logger->err((1), "rewrite socket read");
531 case 0:
532 lerrx(1, "rewrite socket closed")logger->errx((1), "rewrite socket closed");
533 default:
534 break;
535 }
536
537 while ((filename = evbuffer_readln(rwmap->rdbuf, &len,
538 EVBUFFER_EOL_LF)) != NULL((void *)0)) {
539 client = TAILQ_FIRST(&rwmap->clients)((&rwmap->clients)->tqh_first);
540 if (client == NULL((void *)0))
541 lerrx(1, "unexpected rwmap reply")logger->errx((1), "unexpected rwmap reply");
542
543 TAILQ_REMOVE(&rwmap->clients, client, entry)do { if (((client)->entry.tqe_next) != ((void *)0)) (client
)->entry.tqe_next->entry.tqe_prev = (client)->entry.
tqe_prev; else (&rwmap->clients)->tqh_last = (client
)->entry.tqe_prev; *(client)->entry.tqe_prev = (client)
->entry.tqe_next; ; ; } while (0)
;
544
545 tftp_open(client, filename);
546
547 free(filename);
548 };
549}
550
551int
552tftpd_listen(const char *addr, const char *port, int family)
553{
554 struct tftp_server *server;
555
556 struct addrinfo hints, *res, *res0;
557 int error;
558 int s;
559
560 int cerrno = EADDRNOTAVAIL49;
561 const char *cause = "getaddrinfo";
562
563 int on = 1;
564
565 memset(&hints, 0, sizeof(hints));
566 hints.ai_family = family;
567 hints.ai_socktype = SOCK_DGRAM2;
568 hints.ai_flags = AI_PASSIVE1;
569
570 TAILQ_INIT(&tftp_servers)do { (&tftp_servers)->tqh_first = ((void *)0); (&tftp_servers
)->tqh_last = &(&tftp_servers)->tqh_first; } while
(0)
;
571
572 error = getaddrinfo(addr, port, &hints, &res0);
573 if (error) {
574 errx(1, "%s:%s: %s", addr ? addr : "*", port,
575 gai_strerror(error));
576 }
577
578 for (res = res0; res != NULL((void *)0); res = res->ai_next) {
579 s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK0x4000,
580 res->ai_protocol);
581 if (s == -1) {
582 cause = "socket";
583 cerrno = errno(*__errno());
584 continue;
585 }
586
587 if (bind(s, res->ai_addr, res->ai_addrlen) == -1) {
588 cause = "bind";
589 cerrno = errno(*__errno());
590 close(s);
591 continue;
592 }
593
594 switch (res->ai_family) {
595 case AF_INET2:
596 if (setsockopt(s, IPPROTO_IP0, IP_RECVDSTADDR7,
597 &on, sizeof(on)) == -1)
598 err(1, "setsockopt(IP_RECVDSTADDR)");
599 break;
600 case AF_INET624:
601 if (setsockopt(s, IPPROTO_IPV641, IPV6_RECVPKTINFO36,
602 &on, sizeof(on)) == -1)
603 err(1, "setsockopt(IPV6_RECVPKTINFO)");
604 break;
605 }
606
607 server = malloc(sizeof(*server));
608 if (server == NULL((void *)0))
609 err(1, "malloc");
610
611 server->s = s;
612 TAILQ_INSERT_TAIL(&tftp_servers, server, entry)do { (server)->entry.tqe_next = ((void *)0); (server)->
entry.tqe_prev = (&tftp_servers)->tqh_last; *(&tftp_servers
)->tqh_last = (server); (&tftp_servers)->tqh_last =
&(server)->entry.tqe_next; } while (0)
;
613 }
614
615 if (TAILQ_EMPTY(&tftp_servers)(((&tftp_servers)->tqh_first) == ((void *)0)))
616 errc(1, cerrno, "%s", cause);
617
618 freeaddrinfo(res0);
619 return (0);
620}
621
622void
623tftpd_events(void)
624{
625 struct tftp_server *server;
626 TAILQ_FOREACH(server, &tftp_servers, entry)for((server) = ((&tftp_servers)->tqh_first); (server) !=
((void *)0); (server) = ((server)->entry.tqe_next))
{
627 event_set(&server->ev, server->s, EV_READ0x02 | EV_PERSIST0x10,
628 tftpd_recv, server);
629 event_add(&server->ev, NULL((void *)0));
630 }
631}
632
633struct tftp_client *
634client_alloc(void)
635{
636 struct tftp_client *client;
637
638 client = calloc(1, sizeof(*client));
639 if (client == NULL((void *)0))
640 return (NULL((void *)0));
641
642 client->segment_size = SEGSIZE512;
643 client->packet_size = SEGSIZE512 + 4;
644
645 client->tv.tv_sec = TIMEOUT5;
646 client->tv.tv_usec = 0;
647
648 client->sock = -1;
649 client->file = NULL((void *)0);
650 client->newline = 0;
651
652 return (client);
653}
654
655void
656client_free(struct tftp_client *client)
657{
658 free(client->options);
659
660 if (client->file != NULL((void *)0))
661 fclose(client->file);
662
663 close(client->sock);
664
665 free(client);
666}
667
668void
669tftpd_recv(int fd, short events, void *arg)
670{
671 union {
672 struct cmsghdr hdr;
673 char buf[CMSG_SPACE(sizeof(struct sockaddr_storage))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(struct
sockaddr_storage)) + (sizeof(long) - 1)) &~(sizeof(long)
- 1)))
];
674 } cmsgbuf;
675 struct cmsghdr *cmsg;
676 struct msghdr msg;
677 struct iovec iov;
678
679 ssize_t n;
680 struct sockaddr_storage s_in;
681 int dobind = 1;
682 int on = 1;
683
684 struct tftphdr *tp;
685
686 struct tftp_client *client;
687
688 client = client_alloc();
689 if (client == NULL((void *)0)) {
690 char buf[SEGSIZE_MAX65464 + 4];
691 /* no memory! flush this request... */
692 recv(fd, buf, SEGSIZE_MAX65464 + 4, 0);
693 /* dont care if it fails */
694 return;
695 }
696
697 bzero(&msg, sizeof(msg));
698 iov.iov_base = client->buf;
699 iov.iov_len = client->packet_size;
700 msg.msg_name = &client->ss;
701 msg.msg_namelen = sizeof(client->ss);
702 msg.msg_iov = &iov;
703 msg.msg_iovlen = 1;
704 msg.msg_control = &cmsgbuf.buf;
705 msg.msg_controllen = sizeof(cmsgbuf.buf);
706
707 n = recvmsg(fd, &msg, 0);
708 if (n == -1) {
709 lwarn("recvmsg")logger->warn("recvmsg");
710 goto err;
711 }
712 if (n < 4)
713 goto err;
714
715 client->sock = socket(client->ss.ss_family,
716 SOCK_DGRAM2 | SOCK_NONBLOCK0x4000, 0);
717 if (client->sock == -1) {
718 lwarn("socket")logger->warn("socket");
719 goto err;
720 }
721 memset(&s_in, 0, sizeof(s_in));
722 s_in.ss_family = client->ss.ss_family;
723 s_in.ss_len = client->ss.ss_len;
724
725 /* get local address if possible */
726 for (cmsg = CMSG_FIRSTHDR(&msg)((&msg)->msg_controllen >= sizeof(struct cmsghdr) ?
(struct cmsghdr *)(&msg)->msg_control : (struct cmsghdr
*)((void *)0))
; cmsg != NULL((void *)0);
727 cmsg = CMSG_NXTHDR(&msg, cmsg)(((char *)(cmsg) + (((unsigned long)((cmsg)->cmsg_len) + (
sizeof(long) - 1)) &~(sizeof(long) - 1)) + (((unsigned long
)(sizeof(struct cmsghdr)) + (sizeof(long) - 1)) &~(sizeof
(long) - 1)) > ((char *)(&msg)->msg_control) + (&
msg)->msg_controllen) ? (struct cmsghdr *)((void *)0) : (struct
cmsghdr *)((char *)(cmsg) + (((unsigned long)((cmsg)->cmsg_len
) + (sizeof(long) - 1)) &~(sizeof(long) - 1))))
) {
728 if (cmsg->cmsg_level == IPPROTO_IP0 &&
729 cmsg->cmsg_type == IP_RECVDSTADDR7) {
730 memcpy(&((struct sockaddr_in *)&s_in)->sin_addr,
731 CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
, sizeof(struct in_addr));
732 if (((struct sockaddr_in *)&s_in)->sin_addr.s_addr ==
733 INADDR_BROADCAST((u_int32_t)(0xffffffff)))
734 dobind = 0;
735 break;
736 }
737 if (cmsg->cmsg_level == IPPROTO_IPV641 &&
738 cmsg->cmsg_type == IPV6_PKTINFO46) {
739 struct in6_pktinfo *ipi;
740
741 ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
;
742 memcpy(&((struct sockaddr_in6 *)&s_in)->sin6_addr,
743 &ipi->ipi6_addr, sizeof(struct in6_addr));
744 if (IN6_IS_ADDR_LINKLOCAL(&ipi->ipi6_addr)(((&ipi->ipi6_addr)->__u6_addr.__u6_addr8[0] == 0xfe
) && (((&ipi->ipi6_addr)->__u6_addr.__u6_addr8
[1] & 0xc0) == 0x80))
)
745 ((struct sockaddr_in6 *)&s_in)->sin6_scope_id =
746 ipi->ipi6_ifindex;
747 break;
748 }
749 }
750
751 if (dobind) {
752 setsockopt(client->sock, SOL_SOCKET0xffff, SO_REUSEADDR0x0004,
753 &on, sizeof(on));
754 setsockopt(client->sock, SOL_SOCKET0xffff, SO_REUSEPORT0x0200,
755 &on, sizeof(on));
756
757 if (bind(client->sock, (struct sockaddr *)&s_in,
758 s_in.ss_len) == -1) {
759 lwarn("bind to %s", getip(&s_in))logger->warn("bind to %s", getip(&s_in));
760 goto err;
761 }
762 }
763 if (connect(client->sock, (struct sockaddr *)&client->ss,
764 client->ss.ss_len) == -1) {
765 lwarn("connect to %s", getip(&client->ss))logger->warn("connect to %s", getip(&client->ss));
766 goto err;
767 }
768
769 tp = (struct tftphdr *)client->buf;
770 client->opcode = ntohs(tp->th_opcode)(__uint16_t)(__builtin_constant_p(tp->th_opcode) ? (__uint16_t
)(((__uint16_t)(tp->th_opcode) & 0xffU) << 8 | (
(__uint16_t)(tp->th_opcode) & 0xff00U) >> 8) : __swap16md
(tp->th_opcode))
;
771 if (client->opcode != RRQ01 && client->opcode != WRQ02) {
772 /* bad request */
773 goto err;
774 }
775
776 tftp(client, tp, n);
777
778 return;
779
780err:
781 client_free(client);
782}
783
784int
785parse_options(struct tftp_client *client, char *cp, size_t size,
786 struct opt_client *options)
787{
788 char *option;
789 char *ccp;
790 int has_options = 0;
791 int i;
792
793 while (++cp < client->buf + size) {
794 for (i = 2, ccp = cp; i > 0; ccp++) {
795 if (ccp >= client->buf + size) {
796 /*
797 * Don't reject the request, just stop trying
798 * to parse the option and get on with it.
799 * Some Apple OpenFirmware versions have
800 * trailing garbage on the end of otherwise
801 * valid requests.
802 */
803 return (has_options);
804 } else if (*ccp == '\0')
805 i--;
806 }
807
808 for (option = cp; *cp; cp++)
809 *cp = tolower((unsigned char)*cp);
810
811 for (i = 0; i < NOPT; i++) {
812 if (strcmp(option, opt_names[i]) == 0) {
813 options[i].o_request = ++cp;
814 has_options = 1;
815 }
816 }
817 cp = ccp - 1;
818 }
819
820 return (has_options);
821}
822
823/*
824 * Handle initial connection protocol.
825 */
826void
827tftp(struct tftp_client *client, struct tftphdr *tp, size_t size)
828{
829 struct opt_client *options;
830
831 char *cp;
832 int i, first = 1, ecode, to;
833 struct formats *pf;
834 char *mode = NULL((void *)0);
835 char filename[PATH_MAX1024];
836 const char *errstr;
837
838 if (size < 5) {
839 ecode = EBADOP4;
840 goto error;
841 }
842
843 cp = tp->th_stuffth_u.tu_stuff;
844again:
845 while (cp < client->buf + size) {
846 if (*cp == '\0')
847 break;
848 cp++;
849 }
850 if (*cp != '\0') {
851 ecode = EBADOP4;
852 goto error;
853 }
854 i = cp - tp->th_stuffth_u.tu_stuff;
855 if (i >= sizeof(filename)) {
856 ecode = EBADOP4;
857 goto error;
858 }
859 memcpy(filename, tp->th_stuffth_u.tu_stuff, i);
860 filename[i] = '\0';
861 if (first) {
862 mode = ++cp;
863 first = 0;
864 goto again;
865 }
866 for (cp = mode; *cp; cp++)
867 *cp = tolower((unsigned char)*cp);
868
869 for (pf = formats; pf->f_mode; pf++) {
870 if (strcmp(pf->f_mode, mode) == 0)
871 break;
872 }
873 if (pf->f_mode == 0) {
874 ecode = EBADOP4;
875 goto error;
876 }
877 client->fgetc = pf->f_getc;
878 client->fputc = pf->f_putc;
879
880 client->options = options = calloc(NOPT, sizeof(*client->options));
881 if (options == NULL((void *)0)) {
882 ecode = 100 + ENOMEM12;
883 goto error;
884 }
885
886 if (parse_options(client, cp, size, options)) {
887 if (options[OPT_TIMEOUT].o_request != NULL((void *)0)) {
888 to = strtonum(options[OPT_TIMEOUT].o_request,
889 TIMEOUT_MIN1, TIMEOUT_MAX255, &errstr);
890 if (errstr) {
891 ecode = EBADOP4;
892 goto error;
893 }
894 options[OPT_TIMEOUT].o_reply = client->tv.tv_sec = to;
895 }
896
897 if (options[OPT_BLKSIZE].o_request) {
898 client->segment_size = strtonum(
899 options[OPT_BLKSIZE].o_request,
900 SEGSIZE_MIN8, SEGSIZE_MAX65464, &errstr);
901 if (errstr) {
902 ecode = EBADOP4;
903 goto error;
904 }
905 client->packet_size = client->segment_size + 4;
906 options[OPT_BLKSIZE].o_reply = client->segment_size;
907 }
908 } else {
909 free(options);
910 client->options = NULL((void *)0);
911 }
912
913 if (verbose) {
914 char nicebuf[PATH_MAX1024];
915
916 (void)strnvis(nicebuf, filename, PATH_MAX1024,
917 VIS_SAFE0x20|VIS_OCTAL0x01);
918
919 linfo("%s: %s request for '%s'", getip(&client->ss),logger->info("%s: %s request for '%s'", getip(&client->
ss), client->opcode == 02 ? "write" : "read", nicebuf)
920 client->opcode == WRQ ? "write" : "read", nicebuf)logger->info("%s: %s request for '%s'", getip(&client->
ss), client->opcode == 02 ? "write" : "read", nicebuf)
;
921 }
922
923 if (rwmap != NULL((void *)0))
924 rewrite_map(client, filename);
925 else
926 tftp_open(client, filename);
927
928 return;
929
930error:
931 nak(client, ecode);
932}
933
934void
935tftp_open(struct tftp_client *client, const char *filename)
936{
937 int ecode;
938
939 ecode = validate_access(client, filename);
940 if (ecode)
941 goto error;
942
943 if (client->options) {
944 if (oack(client) == -1)
945 goto error;
946
947 free(client->options);
948 client->options = NULL((void *)0);
949 } else if (client->opcode == WRQ02) {
950 recvfile(client);
951 } else
952 sendfile(client);
953
954 return;
955error:
956 nak(client, ecode);
957}
958
959/*
960 * Validate file access. Since we
961 * have no uid or gid, for now require
962 * file to exist and be publicly
963 * readable/writable.
964 * If we were invoked with arguments
965 * from inetd then the file must also be
966 * in one of the given directory prefixes.
967 * Note also, full path name must be
968 * given as we have no login directory.
969 */
970int
971validate_access(struct tftp_client *client, const char *requested)
972{
973 int mode = client->opcode;
974 struct opt_client *options = client->options;
975 struct stat stbuf;
976 int fd, wmode;
977 const char *errstr, *filename;
978 char rewritten[PATH_MAX1024];
979
980 if (!canwrite && mode != RRQ01)
981 return (EACCESS2);
982
983 if (strcmp(requested, SEEDPATH"/etc/random.seed") == 0) {
984 char *buf;
985 if (mode != RRQ01)
986 return (EACCESS2);
987
988 buf = client->buf + sizeof(client->buf) - 512;
989 arc4random_buf(buf, 512);
990 if (options != NULL((void *)0) && options[OPT_TSIZE].o_request)
991 options[OPT_TSIZE].o_reply = 512;
992 client->file = fmemopen(buf, 512, "r");
993 if (client->file == NULL((void *)0))
994 return (errno(*__errno()) + 100);
995
996 return (0);
997 }
998
999 if (iflag) {
1000 int ret;
1001
1002 /*
1003 * In -i mode, look in the directory named after the
1004 * client address.
1005 */
1006 ret = snprintf(rewritten, sizeof(rewritten), "%s/%s",
1007 getip(&client->ss), requested);
1008 if (ret < 0 || ret >= sizeof(rewritten))
1009 return (ENAMETOOLONG63 + 100);
1010 filename = rewritten;
1011 } else {
1012retryread:
1013 filename = requested;
1014 }
1015
1016 /*
1017 * We use a different permissions scheme if `cancreate' is
1018 * set.
1019 */
1020 wmode = O_TRUNC0x0400;
1021 if (stat(filename, &stbuf) == -1) {
1022 if (!cancreate) {
1023 /*
1024 * In -i mode, retry failed read requests from
1025 * the root directory.
1026 */
1027 if (mode == RRQ01 && errno(*__errno()) == ENOENT2 &&
1028 filename == rewritten)
1029 goto retryread;
1030 return (errno(*__errno()) == ENOENT2 ? ENOTFOUND1 : EACCESS2);
1031 } else {
1032 if ((errno(*__errno()) == ENOENT2) && (mode != RRQ01))
1033 wmode |= O_CREAT0x0200;
1034 else
1035 return (EACCESS2);
1036 }
1037 } else {
1038 if (mode == RRQ01) {
1039 if ((stbuf.st_mode & (S_IRUSR0000400 >> 6)) == 0)
1040 return (EACCESS2);
1041 } else {
1042 if ((stbuf.st_mode & (S_IWUSR0000200 >> 6)) == 0)
1043 return (EACCESS2);
1044 }
1045 }
1046
1047 if (options != NULL((void *)0) && options[OPT_TSIZE].o_request) {
1048 if (mode == RRQ01)
1049 options[OPT_TSIZE].o_reply = stbuf.st_size;
1050 else {
1051 /* allows writes of 65535 blocks * SEGSIZE_MAX bytes */
1052 options[OPT_TSIZE].o_reply =
1053 strtonum(options[OPT_TSIZE].o_request,
1054 1, 65535LL * SEGSIZE_MAX65464, &errstr);
1055 if (errstr)
1056 return (EOPTNEG8);
1057 }
1058 }
1059 fd = open(filename, mode == RRQ01 ? O_RDONLY0x0000 : (O_WRONLY0x0001|wmode), 0666);
1060 if (fd == -1)
1061 return (errno(*__errno()) + 100);
1062 /*
1063 * If the file was created, set default permissions.
1064 */
1065 if ((wmode & O_CREAT0x0200) && fchmod(fd, 0666) == -1) {
1066 int serrno = errno(*__errno());
1067
1068 close(fd);
1069 unlink(filename);
1070
1071 return (serrno + 100);
1072 }
1073 client->file = fdopen(fd, mode == RRQ01 ? "r" : "w");
1074 if (client->file == NULL((void *)0)) {
1075 close(fd);
1076 return (errno(*__errno()) + 100);
1077 }
1078
1079 return (0);
1080}
1081
1082int
1083fget_octet(struct tftp_client *client)
1084{
1085 return (getc(client->file)(!__isthreaded ? (--(client->file)->_r < 0 ? __srget
(client->file) : (int)(*(client->file)->_p++)) : (getc
)(client->file))
);
1086}
1087
1088int
1089fput_octet(struct tftp_client *client, int c)
1090{
1091 return (putc(c, client->file)(!__isthreaded ? __sputc(c, client->file) : (putc)(c, client
->file))
);
1092}
1093
1094int
1095fget_netascii(struct tftp_client *client)
1096{
1097 int c = -1;
1098
1099 switch (client->newline) {
1100 case 0:
1101 c = getc(client->file)(!__isthreaded ? (--(client->file)->_r < 0 ? __srget
(client->file) : (int)(*(client->file)->_p++)) : (getc
)(client->file))
;
1102 if (c == EOF(-1))
1103 break;
1104
1105 if (c == '\n' || c == '\r') {
1106 client->newline = c;
1107 c = '\r';
1108 }
1109 break;
1110 case '\n':
1111 client->newline = 0;
1112 c = '\n';
1113 break;
1114 case '\r':
1115 client->newline = 0;
1116 c = '\0';
1117 break;
1118 }
1119
1120 return (c);
1121}
1122
1123int
1124fput_netascii(struct tftp_client *client, int c)
1125{
1126 if (client->newline == '\r') {
1127 client->newline = 0;
1128
1129 if (c == '\0')
1130 c = '\r';
1131
1132 } else if (c == '\r') {
1133 client->newline = c;
1134 return (c);
1135 }
1136
1137 return (putc(c, client->file)(!__isthreaded ? __sputc(c, client->file) : (putc)(c, client
->file))
);
1138}
1139
1140void
1141sendfile(struct tftp_client *client)
1142{
1143 event_set(&client->sev, client->sock, EV_READ0x02, tftp_rrq_ack, client);
1144 client->block = 1;
1145
1146 file_read(client);
1147}
1148
1149void
1150file_read(struct tftp_client *client)
1151{
1152 u_int8_t *buf;
1153 struct tftphdr *dp;
1154 int i;
1155 int c;
1156
1157 dp = (struct tftphdr *)client->buf;
1158 dp->th_opcode = htons((u_short)DATA)(__uint16_t)(__builtin_constant_p((u_short)03) ? (__uint16_t)
(((__uint16_t)((u_short)03) & 0xffU) << 8 | ((__uint16_t
)((u_short)03) & 0xff00U) >> 8) : __swap16md((u_short
)03))
;
1159 dp->th_blockth_u.tu_block = htons(client->block)(__uint16_t)(__builtin_constant_p(client->block) ? (__uint16_t
)(((__uint16_t)(client->block) & 0xffU) << 8 | (
(__uint16_t)(client->block) & 0xff00U) >> 8) : __swap16md
(client->block))
;
1160 buf = (u_int8_t *)dp->th_data;
1161
1162 for (i = 0; i < client->segment_size; i++) {
1163 c = client->fgetc(client);
1164 if (c == EOF(-1)) {
1165 if (ferror(client->file)(!__isthreaded ? (((client->file)->_flags & 0x0040)
!= 0) : (ferror)(client->file))
) {
1166 nak(client, 100 + EIO5);
1167 return;
1168 }
1169
1170 break;
1171 }
1172 buf[i] = c;
1173 }
1174
1175 client->buflen = i + 4;
1176 client->retries = RETRIES5;
1177
1178 tftp_send(client);
1179}
1180
1181void
1182tftp_send(struct tftp_client *client)
1183{
1184 if (send(client->sock, client->buf, client->buflen, 0) == -1) {
1185 lwarn("send(block)")logger->warn("send(block)");
1186 client_free(client);
1187 return;
1188 }
1189
1190 event_add(&client->sev, &client->tv);
1191}
1192
1193void
1194tftp_rrq_ack(int fd, short events, void *arg)
1195{
1196 struct tftp_client *client = arg;
1197 struct tftphdr *ap; /* ack packet */
1198 char rbuf[SEGSIZE_MIN8];
1199 ssize_t n;
1200
1201 if (events & EV_TIMEOUT0x01) {
1202 if (retry(client) == -1) {
1203 lwarn("%s: retry", getip(&client->ss))logger->warn("%s: retry", getip(&client->ss));
1204 goto done;
1205 }
1206
1207 return;
1208 }
1209
1210 n = recv(fd, rbuf, sizeof(rbuf), 0);
1211 if (n == -1) {
1212 switch (errno(*__errno())) {
1213 case EINTR4:
1214 case EAGAIN35:
1215 event_add(&client->sev, &client->tv);
1216 return;
1217
1218 default:
1219 lwarn("%s: recv", getip(&client->ss))logger->warn("%s: recv", getip(&client->ss));
1220 goto done;
1221 }
1222 }
1223
1224 ap = (struct tftphdr *)rbuf;
1225 ap->th_opcode = ntohs((u_short)ap->th_opcode)(__uint16_t)(__builtin_constant_p((u_short)ap->th_opcode) ?
(__uint16_t)(((__uint16_t)((u_short)ap->th_opcode) & 0xffU
) << 8 | ((__uint16_t)((u_short)ap->th_opcode) &
0xff00U) >> 8) : __swap16md((u_short)ap->th_opcode)
)
;
1226 ap->th_blockth_u.tu_block = ntohs((u_short)ap->th_block)(__uint16_t)(__builtin_constant_p((u_short)ap->th_u.tu_block
) ? (__uint16_t)(((__uint16_t)((u_short)ap->th_u.tu_block)
& 0xffU) << 8 | ((__uint16_t)((u_short)ap->th_u
.tu_block) & 0xff00U) >> 8) : __swap16md((u_short)ap
->th_u.tu_block))
;
1227
1228 switch (ap->th_opcode) {
1229 case ACK04:
1230 break;
1231 case ERROR05:
1232 default: /* assume the worst */
1233 goto done;
1234 }
1235
1236 if (ap->th_blockth_u.tu_block != client->block) {
1237 if (tftp_flush(client) == -1) {
1238 lwarnx("%s: flush", getip(&client->ss))logger->warnx("%s: flush", getip(&client->ss));
1239 goto done;
1240 }
1241
1242 if (ap->th_blockth_u.tu_block != (client->block - 1))
1243 goto done;
1244
1245 tftp_send(client);
1246 return;
1247 }
1248
1249 if (client->buflen != client->packet_size) {
1250 /* this was the last packet in the stream */
1251 goto done;
1252 }
1253
1254 client->block++;
1255 file_read(client);
1256 return;
1257
1258done:
1259 client_free(client);
1260}
1261
1262int
1263tftp_flush(struct tftp_client *client)
1264{
1265 char rbuf[SEGSIZE_MIN8];
1266 ssize_t n;
1267
1268 for (;;) {
1269 n = recv(client->sock, rbuf, sizeof(rbuf), 0);
1270 if (n == -1) {
1271 switch (errno(*__errno())) {
1272 case EAGAIN35:
1273 return (0);
1274
1275 case EINTR4:
1276 break;
1277
1278 default:
1279 return (-1);
1280 }
1281 }
1282 }
1283}
1284
1285void
1286recvfile(struct tftp_client *client)
1287{
1288 event_set(&client->sev, client->sock, EV_READ0x02, tftp_wrq, client);
1289 tftp_wrq_ack(client);
1290}
1291
1292int
1293tftp_wrq_ack_packet(struct tftp_client *client)
1294{
1295 struct tftphdr *ap; /* ack packet */
1296
1297 ap = (struct tftphdr *)client->buf;
1298 ap->th_opcode = htons((u_short)ACK)(__uint16_t)(__builtin_constant_p((u_short)04) ? (__uint16_t)
(((__uint16_t)((u_short)04) & 0xffU) << 8 | ((__uint16_t
)((u_short)04) & 0xff00U) >> 8) : __swap16md((u_short
)04))
;
1299 ap->th_blockth_u.tu_block = htons(client->block)(__uint16_t)(__builtin_constant_p(client->block) ? (__uint16_t
)(((__uint16_t)(client->block) & 0xffU) << 8 | (
(__uint16_t)(client->block) & 0xff00U) >> 8) : __swap16md
(client->block))
;
1300
1301 client->buflen = 4;
1302 client->retries = RETRIES5;
1303
1304 return (send(client->sock, client->buf, client->buflen, 0) != 4);
1305}
1306
1307void
1308tftp_wrq_ack(struct tftp_client *client)
1309{
1310 if (tftp_wrq_ack_packet(client) != 0) {
1311 lwarn("tftp wrq ack")logger->warn("tftp wrq ack");
1312 client_free(client);
1313 return;
1314 }
1315
1316 client->block++;
1317 event_add(&client->sev, &client->tv);
1318}
1319
1320void
1321tftp_wrq(int fd, short events, void *arg)
1322{
1323 char wbuf[SEGSIZE_MAX65464 + 4];
1324 struct tftp_client *client = arg;
1325 struct tftphdr *dp;
1326 ssize_t n;
1327 int i;
1328
1329 if (events & EV_TIMEOUT0x01) {
1330 if (retry(client) == -1) {
1331 lwarn("%s", getip(&client->ss))logger->warn("%s", getip(&client->ss));
1332 goto done;
1333 }
1334
1335 return;
1336 }
1337
1338 n = recv(fd, wbuf, client->packet_size, 0);
1339 if (n == -1) {
1340 switch (errno(*__errno())) {
1341 case EINTR4:
1342 case EAGAIN35:
1343 goto retry;
1344
1345 default:
1346 lwarn("tftp_wrq recv")logger->warn("tftp_wrq recv");
1347 goto done;
1348 }
1349 }
1350
1351 if (n < 4)
1352 goto done;
1353
1354 dp = (struct tftphdr *)wbuf;
1355 dp->th_opcode = ntohs((u_short)dp->th_opcode)(__uint16_t)(__builtin_constant_p((u_short)dp->th_opcode) ?
(__uint16_t)(((__uint16_t)((u_short)dp->th_opcode) & 0xffU
) << 8 | ((__uint16_t)((u_short)dp->th_opcode) &
0xff00U) >> 8) : __swap16md((u_short)dp->th_opcode)
)
;
1356 dp->th_blockth_u.tu_block = ntohs((u_short)dp->th_block)(__uint16_t)(__builtin_constant_p((u_short)dp->th_u.tu_block
) ? (__uint16_t)(((__uint16_t)((u_short)dp->th_u.tu_block)
& 0xffU) << 8 | ((__uint16_t)((u_short)dp->th_u
.tu_block) & 0xff00U) >> 8) : __swap16md((u_short)dp
->th_u.tu_block))
;
1357
1358 switch (dp->th_opcode) {
1359 case ERROR05:
1360 goto done;
1361 case DATA03:
1362 break;
1363 default:
1364 goto retry;
1365 }
1366
1367 if (dp->th_blockth_u.tu_block != client->block) {
1368 if (tftp_flush(client) == -1) {
1369 lwarnx("%s: flush", getip(&client->ss))logger->warnx("%s: flush", getip(&client->ss));
1370 goto done;
1371 }
1372
1373 if (dp->th_blockth_u.tu_block != (client->block - 1))
1374 goto done;
1375
1376 goto retry;
1377 }
1378
1379 for (i = 4; i < n; i++) {
1380 if (client->fputc(client, wbuf[i]) == EOF(-1)) {
1381 lwarn("tftp wrq")logger->warn("tftp wrq");
1382 goto done;
1383 }
1384 }
1385
1386 if (n < client->packet_size) {
1387 tftp_wrq_ack_packet(client);
1388 fclose(client->file);
1389 client->file = NULL((void *)0);
1390 event_set(&client->sev, client->sock, EV_READ0x02,
1391 tftp_wrq_end, client);
1392 event_add(&client->sev, &client->tv);
1393 return;
1394 }
1395
1396 tftp_wrq_ack(client);
1397 return;
1398
1399retry:
1400 event_add(&client->sev, &client->tv);
1401 return;
1402done:
1403 client_free(client);
1404}
1405
1406void
1407tftp_wrq_end(int fd, short events, void *arg)
1408{
1409 char wbuf[SEGSIZE_MAX65464 + 4];
1410 struct tftp_client *client = arg;
1411 struct tftphdr *dp;
1412 ssize_t n;
1413
1414 if (events & EV_TIMEOUT0x01) {
1415 /* this was the last packet, we can clean up */
1416 goto done;
1417 }
1418
1419 n = recv(fd, wbuf, client->packet_size, 0);
1420 if (n == -1) {
1421 switch (errno(*__errno())) {
1422 case EINTR4:
1423 case EAGAIN35:
1424 goto retry;
1425
1426 default:
1427 lwarn("tftp_wrq_end recv")logger->warn("tftp_wrq_end recv");
1428 goto done;
1429 }
1430 }
1431
1432 if (n < 4)
1433 goto done;
1434
1435 dp = (struct tftphdr *)wbuf;
1436 dp->th_opcode = ntohs((u_short)dp->th_opcode)(__uint16_t)(__builtin_constant_p((u_short)dp->th_opcode) ?
(__uint16_t)(((__uint16_t)((u_short)dp->th_opcode) & 0xffU
) << 8 | ((__uint16_t)((u_short)dp->th_opcode) &
0xff00U) >> 8) : __swap16md((u_short)dp->th_opcode)
)
;
1437 dp->th_blockth_u.tu_block = ntohs((u_short)dp->th_block)(__uint16_t)(__builtin_constant_p((u_short)dp->th_u.tu_block
) ? (__uint16_t)(((__uint16_t)((u_short)dp->th_u.tu_block)
& 0xffU) << 8 | ((__uint16_t)((u_short)dp->th_u
.tu_block) & 0xff00U) >> 8) : __swap16md((u_short)dp
->th_u.tu_block))
;
1438
1439 switch (dp->th_opcode) {
1440 case ERROR05:
1441 goto done;
1442 case DATA03:
1443 break;
1444 default:
1445 goto retry;
1446 }
1447
1448 if (dp->th_blockth_u.tu_block != client->block)
1449 goto done;
1450
1451retry:
1452 if (retry(client) == -1) {
1453 lwarn("%s", getip(&client->ss))logger->warn("%s", getip(&client->ss));
1454 goto done;
1455 }
1456 return;
1457done:
1458 client_free(client);
1459 return;
1460}
1461
1462
1463/*
1464 * Send a nak packet (error message).
1465 * Error code passed in is one of the
1466 * standard TFTP codes, or a UNIX errno
1467 * offset by 100.
1468 */
1469void
1470nak(struct tftp_client *client, int error)
1471{
1472 struct tftphdr *tp;
1473 struct errmsg *pe;
1474 size_t length;
1475 ssize_t rslt;
1476
1477 tp = (struct tftphdr *)client->buf;
1478 tp->th_opcode = htons((u_short)ERROR)(__uint16_t)(__builtin_constant_p((u_short)05) ? (__uint16_t)
(((__uint16_t)((u_short)05) & 0xffU) << 8 | ((__uint16_t
)((u_short)05) & 0xff00U) >> 8) : __swap16md((u_short
)05))
;
1479 tp->th_codeth_u.tu_code = htons((u_short)error)(__uint16_t)(__builtin_constant_p((u_short)error) ? (__uint16_t
)(((__uint16_t)((u_short)error) & 0xffU) << 8 | ((__uint16_t
)((u_short)error) & 0xff00U) >> 8) : __swap16md((u_short
)error))
;
1480
1481 for (pe = errmsgs; pe->e_code >= 0; pe++) {
1482 if (pe->e_code == error)
1483 break;
1484 }
1485 if (pe->e_code < 0) {
1486 pe->e_msg = strerror(error - 100);
1487 tp->th_codeth_u.tu_code = htons(EUNDEF)(__uint16_t)(__builtin_constant_p(0) ? (__uint16_t)(((__uint16_t
)(0) & 0xffU) << 8 | ((__uint16_t)(0) & 0xff00U
) >> 8) : __swap16md(0))
; /* set 'undef' errorcode */
1488 }
1489
1490 length = strlcpy(tp->th_msgth_data, pe->e_msg, client->packet_size - 5) + 5;
1491 if (length > client->packet_size)
1492 length = client->packet_size;
1493
1494 linfo("%s: nak: %s", getip(&client->ss), tp->th_msg)logger->info("%s: nak: %s", getip(&client->ss), tp->
th_data)
;
1495
1496 rslt = send(client->sock, client->buf, length, 0);
1497 if (rslt == -1)
1498 lwarn("%s: nak", getip(&client->ss))logger->warn("%s: nak", getip(&client->ss));
1499 else if ((size_t)rslt != length)
1500 lwarnx("%s: nak: sent %zd of %zu bytes", getip(&client->ss),logger->warnx("%s: nak: sent %zd of %zu bytes", getip(&
client->ss), rslt, length)
1501 rslt, length)logger->warnx("%s: nak: sent %zd of %zu bytes", getip(&
client->ss), rslt, length)
;
1502
1503 client_free(client);
1504}
1505
1506/*
1507 * Send an oack packet (option acknowledgement).
1508 */
1509int
1510oack(struct tftp_client *client)
1511{
1512 struct opt_client *options = client->options;
1513 struct tftphdr *tp;
1514 char *bp;
1515 int i, n, size;
1516
1517 tp = (struct tftphdr *)client->buf;
1518 bp = (char *)tp->th_stuffth_u.tu_stuff;
1519 size = sizeof(client->buf) - 2;
1520
1521 tp->th_opcode = htons((u_short)OACK)(__uint16_t)(__builtin_constant_p((u_short)06) ? (__uint16_t)
(((__uint16_t)((u_short)06) & 0xffU) << 8 | ((__uint16_t
)((u_short)06) & 0xff00U) >> 8) : __swap16md((u_short
)06))
;
1522 for (i = 0; i < NOPT; i++) {
1523 if (options[i].o_request == NULL((void *)0))
1524 continue;
1525
1526 n = snprintf(bp, size, "%s%c%lld", opt_names[i], '\0',
1527 options[i].o_reply);
1528 if (n < 0 || n >= size) {
1529 lwarnx("oack: no buffer space")logger->warnx("oack: no buffer space");
1530 goto error;
1531 }
1532
1533 bp += n + 1;
1534 size -= n + 1;
1535 if (size < 0) {
1536 lwarnx("oack: no buffer space")logger->warnx("oack: no buffer space");
1537 goto error;
1538 }
1539 }
1540
1541 client->buflen = bp - client->buf;
1542 client->retries = RETRIES5;
1543
1544 if (send(client->sock, client->buf, client->buflen, 0) == -1) {
1545 lwarn("oack")logger->warn("oack");
1546 goto error;
1547 }
1548
1549 /* no client ACK for write requests with options */
1550 if (client->opcode == WRQ02) {
1551 client->block = 1;
1552 event_set(&client->sev, client->sock, EV_READ0x02,
1553 tftp_wrq, client);
1554 } else
1555 event_set(&client->sev, client->sock, EV_READ0x02,
1556 oack_done, client);
1557
1558 event_add(&client->sev, &client->tv);
1559 return (0);
1560
1561error:
1562 return (-1);
1563}
1564
1565int
1566retry(struct tftp_client *client)
1567{
1568 if (--client->retries == 0) {
1569 errno(*__errno()) = ETIMEDOUT60;
1570 return (-1);
1571 }
1572
1573 tftp_send(client);
1574
1575 return (0);
1576}
1577
1578void
1579oack_done(int fd, short events, void *arg)
1580{
1581 struct tftp_client *client = arg;
1582 struct tftphdr *ap;
1583 ssize_t n;
1584
1585 if (events & EV_TIMEOUT0x01) {
1586 if (retry(client) == -1) {
1587 lwarn("%s", getip(&client->ss))logger->warn("%s", getip(&client->ss));
1588 goto done;
1589 }
1590
1591 return;
1592 }
1593
1594 n = recv(client->sock, client->buf, client->packet_size, 0);
1595 if (n == -1) {
1596 switch (errno(*__errno())) {
1597 case EINTR4:
1598 case EAGAIN35:
1599 event_add(&client->sev, &client->tv);
1600 return;
1601
1602 default:
1603 lwarn("%s: recv", getip(&client->ss))logger->warn("%s: recv", getip(&client->ss));
1604 goto done;
1605 }
1606 }
1607
1608 if (n < 4)
1609 goto done;
1610
1611 ap = (struct tftphdr *)client->buf;
1612 ap->th_opcode = ntohs((u_short)ap->th_opcode)(__uint16_t)(__builtin_constant_p((u_short)ap->th_opcode) ?
(__uint16_t)(((__uint16_t)((u_short)ap->th_opcode) & 0xffU
) << 8 | ((__uint16_t)((u_short)ap->th_opcode) &
0xff00U) >> 8) : __swap16md((u_short)ap->th_opcode)
)
;
1613 ap->th_blockth_u.tu_block = ntohs((u_short)ap->th_block)(__uint16_t)(__builtin_constant_p((u_short)ap->th_u.tu_block
) ? (__uint16_t)(((__uint16_t)((u_short)ap->th_u.tu_block)
& 0xffU) << 8 | ((__uint16_t)((u_short)ap->th_u
.tu_block) & 0xff00U) >> 8) : __swap16md((u_short)ap
->th_u.tu_block))
;
1614
1615 if (ap->th_opcode != ACK04 || ap->th_blockth_u.tu_block != 0)
1616 goto done;
1617
1618 sendfile(client);
1619 return;
1620
1621done:
1622 client_free(client);
1623}
1624
1625const char *
1626getip(void *s)
1627{
1628 struct sockaddr *sa = s;
1629 static char hbuf[NI_MAXHOST256];
1630
1631 if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf),
1632 NULL((void *)0), 0, NI_NUMERICHOST1))
1633 strlcpy(hbuf, "0.0.0.0", sizeof(hbuf));
1634
1635 return(hbuf);
1636}
1637
1638/* daemon(3) clone, intended to be used in a "r"estricted environment */
1639int
1640rdaemon(int devnull)
1641{
1642 if (devnull == -1) {
1643 errno(*__errno()) = EBADF9;
1644 return (-1);
1645 }
1646 if (fcntl(devnull, F_GETFL3) == -1)
1647 return (-1);
1648
1649 switch (fork()) {
1650 case -1:
1651 return (-1);
1652 case 0:
1653 break;
1654 default:
1655 _exit(0);
1656 }
1657
1658 if (setsid() == -1)
1659 return (-1);
1660
1661 (void)dup2(devnull, STDIN_FILENO0);
1662 (void)dup2(devnull, STDOUT_FILENO1);
1663 (void)dup2(devnull, STDERR_FILENO2);
1664 if (devnull > 2)
1665 (void)close(devnull);
1666
1667 return (0);
1668}
1669
1670void
1671syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
1672{
1673 char *s;
1674
1675 if (vasprintf(&s, fmt, ap) == -1) {
1676 syslog(LOG_EMERG0, "unable to alloc in syslog_vstrerror");
1677 exit(1);
1678 }
1679
1680 syslog(priority, "%s: %s", s, strerror(e));
1681
1682 free(s);
1683}
1684
1685void
1686syslog_err(int ecode, const char *fmt, ...)
1687{
1688 va_list ap;
1689
1690 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1691 syslog_vstrerror(errno(*__errno()), LOG_CRIT2, fmt, ap);
1692 va_end(ap)__builtin_va_end((ap));
1693
1694 exit(ecode);
1695}
1696
1697void
1698syslog_errx(int ecode, const char *fmt, ...)
1699{
1700 va_list ap;
1701
1702 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1703 vsyslog(LOG_CRIT2, fmt, ap);
1704 va_end(ap)__builtin_va_end((ap));
1705
1706 exit(ecode);
1707}
1708
1709void
1710syslog_warn(const char *fmt, ...)
1711{
1712 va_list ap;
1713
1714 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1715 syslog_vstrerror(errno(*__errno()), LOG_ERR3, fmt, ap);
1716 va_end(ap)__builtin_va_end((ap));
1717}
1718
1719void
1720syslog_warnx(const char *fmt, ...)
1721{
1722 va_list ap;
1723
1724 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1725 vsyslog(LOG_ERR3, fmt, ap);
1726 va_end(ap)__builtin_va_end((ap));
1727}
1728
1729void
1730syslog_info(const char *fmt, ...)
1731{
1732 va_list ap;
1733
1734 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1735 vsyslog(LOG_INFO6, fmt, ap);
1736 va_end(ap)__builtin_va_end((ap));
1737}
1738
1739void
1740syslog_debug(const char *fmt, ...)
1741{
1742 va_list ap;
1743
1744 if (!debug)
1745 return;
1746
1747 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1748 vsyslog(LOG_DEBUG7, fmt, ap);
1749 va_end(ap)__builtin_va_end((ap));
1750}