Bug Summary

File:src/usr.sbin/tftp-proxy/tftp-proxy.c
Warning:line 507, column 29
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name tftp-proxy.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -fno-rounding-math -mconstructor-aliases -munwind-tables -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/tftp-proxy/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/tftp-proxy/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -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/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/tftp-proxy/tftp-proxy.c
1/* $OpenBSD: tftp-proxy.c,v 1.22 2021/01/17 13:38:52 claudio Exp $
2 *
3 * Copyright (c) 2005 DLS Internet Services
4 * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/types.h>
31#include <sys/ioctl.h>
32#include <sys/socket.h>
33#include <sys/uio.h>
34
35#include <netinet/in.h>
36#include <arpa/inet.h>
37#include <arpa/tftp.h>
38#include <net/if.h>
39#include <net/pfvar.h>
40#include <netdb.h>
41
42#include <unistd.h>
43#include <errno(*__errno()).h>
44#include <err.h>
45#include <pwd.h>
46#include <stdio.h>
47#include <syslog.h>
48#include <string.h>
49#include <stdarg.h>
50#include <stdlib.h>
51#include <event.h>
52
53#include "filter.h"
54
55#define CHROOT_DIR"/var/empty" "/var/empty"
56#define NOPRIV_USER"_tftp_proxy" "_tftp_proxy"
57
58#define DEFTRANSWAIT2 2
59#define NTOP_BUFS4 4
60#define PKTSIZE512 +4 SEGSIZE512+4
61
62const char *opcode(int);
63const char *sock_ntop(struct sockaddr *);
64static void usage(void);
65
66struct proxy_listener {
67 struct event ev;
68 TAILQ_ENTRY(proxy_listener)struct { struct proxy_listener *tqe_next; struct proxy_listener
**tqe_prev; }
entry;
69 int (*cmsg2dst)(struct cmsghdr *, struct sockaddr_storage *);
70 int s;
71};
72
73void proxy_listen(const char *, const char *, int);
74void proxy_listener_events(void);
75int proxy_dst4(struct cmsghdr *, struct sockaddr_storage *);
76int proxy_dst6(struct cmsghdr *, struct sockaddr_storage *);
77void proxy_recv(int, short, void *);
78
79struct fd_reply {
80 TAILQ_ENTRY(fd_reply)struct { struct fd_reply *tqe_next; struct fd_reply **tqe_prev
; }
entry;
81 int fd;
82};
83
84struct privproc {
85 struct event pop_ev;
86 struct event push_ev;
87 TAILQ_HEAD(, fd_reply)struct { struct fd_reply *tqh_first; struct fd_reply **tqh_last
; }
replies;
88 struct evbuffer *buf;
89};
90
91void proxy_privproc(int, struct passwd *);
92void privproc_push(int, short, void *);
93void privproc_pop(int, short, void *);
94
95void unprivproc_push(int, short, void *);
96void unprivproc_pop(int, short, void *);
97void unprivproc_timeout(int, short, void *);
98
99char ntop_buf[NTOP_BUFS4][INET6_ADDRSTRLEN46];
100
101struct loggers {
102 __dead__attribute__((__noreturn__)) void (*err)(int, const char *, ...)
103 __attribute__((__format__ (printf, 2, 3)));
104 __dead__attribute__((__noreturn__)) void (*errx)(int, const char *, ...)
105 __attribute__((__format__ (printf, 2, 3)));
106 void (*warn)(const char *, ...)
107 __attribute__((__format__ (printf, 1, 2)));
108 void (*warnx)(const char *, ...)
109 __attribute__((__format__ (printf, 1, 2)));
110 void (*info)(const char *, ...)
111 __attribute__((__format__ (printf, 1, 2)));
112 void (*debug)(const char *, ...)
113 __attribute__((__format__ (printf, 1, 2)));
114};
115
116const struct loggers conslogger = {
117 err,
118 errx,
119 warn,
120 warnx,
121 warnx, /* info */
122 warnx /* debug */
123};
124
125__dead__attribute__((__noreturn__)) void syslog_err(int, const char *, ...)
126 __attribute__((__format__ (printf, 2, 3)));
127__dead__attribute__((__noreturn__)) void syslog_errx(int, const char *, ...)
128 __attribute__((__format__ (printf, 2, 3)));
129void syslog_warn(const char *, ...)
130 __attribute__((__format__ (printf, 1, 2)));
131void syslog_warnx(const char *, ...)
132 __attribute__((__format__ (printf, 1, 2)));
133void syslog_info(const char *, ...)
134 __attribute__((__format__ (printf, 1, 2)));
135void syslog_debug(const char *, ...)
136 __attribute__((__format__ (printf, 1, 2)));
137void syslog_vstrerror(int, int, const char *, va_list)
138 __attribute__((__format__ (printf, 3, 0)));
139
140const struct loggers syslogger = {
141 syslog_err,
142 syslog_errx,
143 syslog_warn,
144 syslog_warnx,
145 syslog_info,
146 syslog_debug
147};
148
149const struct loggers *logger = &conslogger;
150
151#define lerr(_e, _f...)logger->err((_e), _f...) logger->err((_e), _f)
152#define lerrx(_e, _f...)logger->errx((_e), _f...) logger->errx((_e), _f)
153#define lwarn(_f...)logger->warn(_f...) logger->warn(_f)
154#define lwarnx(_f...)logger->warnx(_f...) logger->warnx(_f)
155#define linfo(_f...)logger->info(_f...) logger->info(_f)
156#define ldebug(_f...)logger->debug(_f...) logger->debug(_f)
157
158__dead__attribute__((__noreturn__)) void
159usage(void)
160{
161 extern char *__progname;
162 fprintf(stderr(&__sF[2]), "usage: %s [-46dv] [-a address] [-l address] [-p port]"
163 " [-w transwait]\n", __progname);
164 exit(1);
165}
166
167int debug = 0;
168int verbose = 0;
169struct timeval transwait = { DEFTRANSWAIT2, 0 };
170
171int on = 1;
172
173struct addr_pair {
174 struct sockaddr_storage src;
175 struct sockaddr_storage dst;
176};
177
178struct proxy_request {
179 char buf[SEGSIZE_MAX65464 + 4];
180 size_t buflen;
181
182 struct addr_pair addrs;
183
184 struct event ev;
185 TAILQ_ENTRY(proxy_request)struct { struct proxy_request *tqe_next; struct proxy_request
**tqe_prev; }
entry;
186 u_int32_t id;
187};
188
189struct proxy_child {
190 TAILQ_HEAD(, proxy_request)struct { struct proxy_request *tqh_first; struct proxy_request
**tqh_last; }
fdrequests;
191 TAILQ_HEAD(, proxy_request)struct { struct proxy_request *tqh_first; struct proxy_request
**tqh_last; }
tmrequests;
192 struct event push_ev;
193 struct event pop_ev;
194 struct evbuffer *buf;
195};
196
197struct proxy_child *child = NULL((void *)0);
198TAILQ_HEAD(, proxy_listener)struct { struct proxy_listener *tqh_first; struct proxy_listener
**tqh_last; }
proxy_listeners;
199
200struct src_addr {
201 TAILQ_ENTRY(src_addr)struct { struct src_addr *tqe_next; struct src_addr **tqe_prev
; }
entry;
202 struct sockaddr_storage addr;
203 socklen_t addrlen;
204};
205TAILQ_HEAD(, src_addr)struct { struct src_addr *tqh_first; struct src_addr **tqh_last
; }
src_addrs;
206
207void source_addresses(const char*, int);
208
209int
210main(int argc, char *argv[])
211{
212 extern char *__progname;
213
214 int c;
215 const char *errstr;
216
217 struct src_addr *saddr, *saddr2;
218 struct passwd *pw;
219
220 char *addr = "localhost";
221 char *port = "6969";
222 int family = AF_UNSPEC0;
223
224 int pair[2];
225
226 TAILQ_INIT(&src_addrs)do { (&src_addrs)->tqh_first = ((void *)0); (&src_addrs
)->tqh_last = &(&src_addrs)->tqh_first; } while
(0)
;
227
228 while ((c = getopt(argc, argv, "46a:dvl:p:w:")) != -1) {
229 switch (c) {
230 case '4':
231 family = AF_INET2;
232 break;
233 case '6':
234 family = AF_INET624;
235 break;
236 case 'a':
237 source_addresses(optarg, family);
238 break;
239 case 'd':
240 verbose = debug = 1;
241 break;
242 case 'l':
243 addr = optarg;
244 break;
245 case 'p':
246 port = optarg;
247 break;
248 case 'v':
249 verbose = 1;
250 break;
251 case 'w':
252 transwait.tv_sec = strtonum(optarg, 1, 30, &errstr);
253 if (errstr)
254 errx(1, "wait is %s", errstr);
255 break;
256 default:
257 usage();
258 /* NOTREACHED */
259 }
260 }
261
262 if (geteuid() != 0)
263 lerrx(1, "need root privileges")logger->errx((1), "need root privileges");
264
265 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_NONBLOCK0x4000, PF_UNSPEC0, pair)
266 == -1)
267 lerr(1, "socketpair")logger->err((1), "socketpair");
268
269 pw = getpwnam(NOPRIV_USER"_tftp_proxy");
270 if (pw == NULL((void *)0))
271 lerrx(1, "no %s user", NOPRIV_USER)logger->errx((1), "no %s user", "_tftp_proxy");
272
273 /* Family option may have been specified late. */
274 if (family != AF_UNSPEC0)
275 TAILQ_FOREACH_SAFE(saddr, &src_addrs, entry, saddr2)for ((saddr) = ((&src_addrs)->tqh_first); (saddr) != (
(void *)0) && ((saddr2) = ((saddr)->entry.tqe_next
), 1); (saddr) = (saddr2))
276 if (saddr->addr.ss_family != family) {
277 TAILQ_REMOVE(&src_addrs, saddr, entry)do { if (((saddr)->entry.tqe_next) != ((void *)0)) (saddr)
->entry.tqe_next->entry.tqe_prev = (saddr)->entry.tqe_prev
; else (&src_addrs)->tqh_last = (saddr)->entry.tqe_prev
; *(saddr)->entry.tqe_prev = (saddr)->entry.tqe_next; ;
; } while (0)
;
278 free(saddr);
279 }
280
281 if (!debug) {
282 if (daemon(1, 0) == -1)
283 lerr(1, "daemon")logger->err((1), "daemon");
284
285 openlog(__progname, LOG_PID0x01|LOG_NDELAY0x08, LOG_DAEMON(3<<3));
286 tzset();
287 logger = &syslogger;
288 }
289
290 switch (fork()) {
291 case -1:
292 lerr(1, "fork")logger->err((1), "fork");
293
294 case 0:
295 setproctitle("privproc");
296 close(pair[1]);
297 proxy_privproc(pair[0], pw);
298 /* this never returns */
299
300 default:
301 setproctitle("unprivproc");
302 close(pair[0]);
303 break;
304 }
305
306 child = calloc(1, sizeof(*child));
307 if (child == NULL((void *)0))
308 lerr(1, "alloc(child)")logger->err((1), "alloc(child)");
309
310 child->buf = evbuffer_new();
311 if (child->buf == NULL((void *)0))
312 lerr(1, "child evbuffer")logger->err((1), "child evbuffer");
313
314 TAILQ_INIT(&child->fdrequests)do { (&child->fdrequests)->tqh_first = ((void *)0);
(&child->fdrequests)->tqh_last = &(&child->
fdrequests)->tqh_first; } while (0)
;
315 TAILQ_INIT(&child->tmrequests)do { (&child->tmrequests)->tqh_first = ((void *)0);
(&child->tmrequests)->tqh_last = &(&child->
tmrequests)->tqh_first; } while (0)
;
316
317 proxy_listen(addr, port, family);
318
319 /* open /dev/pf */
320 init_filter(NULL((void *)0), verbose);
321
322 /* revoke privs */
323 if (chroot(CHROOT_DIR"/var/empty") == -1)
324 lerr(1, "chroot %s", CHROOT_DIR)logger->err((1), "chroot %s", "/var/empty");
325
326 if (chdir("/") == -1)
327 lerr(1, "chdir %s", CHROOT_DIR)logger->err((1), "chdir %s", "/var/empty");
328
329 if (setgroups(1, &pw->pw_gid) ||
330 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
331 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
332 err(1, "unable to revoke privs");
333
334 event_init();
335
336 proxy_listener_events();
337
338 event_set(&child->pop_ev, pair[1], EV_READ0x02 | EV_PERSIST0x10,
339 unprivproc_pop, NULL((void *)0));
340 event_set(&child->push_ev, pair[1], EV_WRITE0x04,
341 unprivproc_push, NULL((void *)0));
342
343 event_add(&child->pop_ev, NULL((void *)0));
344
345 event_dispatch();
346
347 return(0);
348}
349
350void
351source_addresses(const char* name, int family)
352{
353 struct addrinfo hints, *res, *res0;
354 struct src_addr *saddr;
355 int error;
356
357 memset(&hints, 0, sizeof(hints));
358 hints.ai_family = family;
359 hints.ai_socktype = SOCK_DGRAM2;
360 hints.ai_flags = AI_PASSIVE1;
361 error = getaddrinfo(name, NULL((void *)0), &hints, &res0);
362 if (error)
363 lerrx(1, "%s: %s", name, gai_strerror(error))logger->errx((1), "%s: %s", name, gai_strerror(error));
364 for (res = res0; res != NULL((void *)0); res = res->ai_next) {
365 if ((saddr = calloc(1, sizeof(struct src_addr))) == NULL((void *)0))
366 lerrx(1, "calloc")logger->errx((1), "calloc");
367 memcpy(&(saddr->addr), res->ai_addr, res->ai_addrlen);
368 saddr->addrlen = res->ai_addrlen;
369 TAILQ_INSERT_TAIL(&src_addrs, saddr, entry)do { (saddr)->entry.tqe_next = ((void *)0); (saddr)->entry
.tqe_prev = (&src_addrs)->tqh_last; *(&src_addrs)->
tqh_last = (saddr); (&src_addrs)->tqh_last = &(saddr
)->entry.tqe_next; } while (0)
;
370 }
371 freeaddrinfo(res0);
372}
373
374void
375proxy_privproc(int s, struct passwd *pw)
376{
377 struct privproc p;
378
379 if (chroot(CHROOT_DIR"/var/empty") == -1)
380 lerr(1, "chroot to %s", CHROOT_DIR)logger->err((1), "chroot to %s", "/var/empty");
381
382 if (chdir("/") == -1)
383 lerr(1, "chdir to %s", CHROOT_DIR)logger->err((1), "chdir to %s", "/var/empty");
384
385 if (setgroups(1, &pw->pw_gid) ||
386 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid))
387 lerr(1, "unable to set group ids")logger->err((1), "unable to set group ids");
388
389 if (pledge("stdio inet sendfd", NULL((void *)0)) == -1)
390 err(1, "pledge");
391
392 TAILQ_INIT(&p.replies)do { (&p.replies)->tqh_first = ((void *)0); (&p.replies
)->tqh_last = &(&p.replies)->tqh_first; } while
(0)
;
393
394 p.buf = evbuffer_new();
395 if (p.buf == NULL((void *)0))
396 err(1, "pop evbuffer_new");
397
398 event_init();
399
400 event_set(&p.pop_ev, s, EV_READ0x02 | EV_PERSIST0x10, privproc_pop, &p);
401 event_set(&p.push_ev, s, EV_WRITE0x04, privproc_push, &p);
402
403 event_add(&p.pop_ev, NULL((void *)0));
404
405 event_dispatch();
406}
407
408void
409privproc_pop(int fd, short events, void *arg)
410{
411 struct addr_pair req;
412 struct privproc *p = arg;
413 struct fd_reply *rep;
414 struct src_addr *saddr;
415 int add = 0;
416
417 switch (evbuffer_read(p->buf, fd, sizeof(req))) {
418 case 0:
419 lerrx(1, "unprivproc has gone")logger->errx((1), "unprivproc has gone");
420 case -1:
421 switch (errno(*__errno())) {
422 case EAGAIN35:
423 case EINTR4:
424 return;
425 default:
426 lerr(1, "privproc_pop read")logger->err((1), "privproc_pop read");
427 }
428 default:
429 break;
430 }
431
432 while (EVBUFFER_LENGTH(p->buf)(p->buf)->off >= sizeof(req)) {
433 evbuffer_remove(p->buf, &req, sizeof(req));
434
435 /* do i really need to check this? */
436 if (req.src.ss_family != req.dst.ss_family)
437 lerrx(1, "family mismatch")logger->errx((1), "family mismatch");
438
439 rep = calloc(1, sizeof(*rep));
440 if (rep == NULL((void *)0))
441 lerr(1, "reply calloc")logger->err((1), "reply calloc");
442
443 rep->fd = socket(req.src.ss_family, SOCK_DGRAM2 | SOCK_NONBLOCK0x4000,
444 IPPROTO_UDP17);
445 if (rep->fd == -1)
446 lerr(1, "privproc socket")logger->err((1), "privproc socket");
447
448 if (setsockopt(rep->fd, SOL_SOCKET0xffff, SO_BINDANY0x1000,
449 &on, sizeof(on)) == -1)
450 lerr(1, "privproc setsockopt(BINDANY)")logger->err((1), "privproc setsockopt(BINDANY)");
451
452 if (setsockopt(rep->fd, SOL_SOCKET0xffff, SO_REUSEADDR0x0004,
453 &on, sizeof(on)) == -1)
454 lerr(1, "privproc setsockopt(REUSEADDR)")logger->err((1), "privproc setsockopt(REUSEADDR)");
455
456 if (setsockopt(rep->fd, SOL_SOCKET0xffff, SO_REUSEPORT0x0200,
457 &on, sizeof(on)) == -1)
458 lerr(1, "privproc setsockopt(REUSEPORT)")logger->err((1), "privproc setsockopt(REUSEPORT)");
459
460 TAILQ_FOREACH(saddr, &src_addrs, entry)for((saddr) = ((&src_addrs)->tqh_first); (saddr) != ((
void *)0); (saddr) = ((saddr)->entry.tqe_next))
461 if (saddr->addr.ss_family == req.src.ss_family)
462 break;
463 if (saddr == NULL((void *)0)) {
464 if (bind(rep->fd, (struct sockaddr *)&req.src,
465 req.src.ss_len) == -1)
466 lerr(1, "privproc bind")logger->err((1), "privproc bind");
467 } else {
468 if (bind(rep->fd, (struct sockaddr*)&saddr->addr,
469 saddr->addrlen) == -1)
470 lerr(1, "privproc bind")logger->err((1), "privproc bind");
471 }
472
473 if (TAILQ_EMPTY(&p->replies)(((&p->replies)->tqh_first) == ((void *)0)))
474 add = 1;
475
476 TAILQ_INSERT_TAIL(&p->replies, rep, entry)do { (rep)->entry.tqe_next = ((void *)0); (rep)->entry.
tqe_prev = (&p->replies)->tqh_last; *(&p->replies
)->tqh_last = (rep); (&p->replies)->tqh_last = &
(rep)->entry.tqe_next; } while (0)
;
477 }
478
479 if (add)
480 event_add(&p->push_ev, NULL((void *)0));
481}
482
483void
484privproc_push(int fd, short events, void *arg)
485{
486 struct privproc *p = arg;
487 struct fd_reply *rep;
488
489 struct msghdr msg;
490 union {
491 struct cmsghdr hdr;
492 char buf[CMSG_SPACE(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(int))
+ (sizeof(long) - 1)) &~(sizeof(long) - 1)))
];
493 } cmsgbuf;
494 struct cmsghdr *cmsg;
495 struct iovec iov;
496 int result = 0;
497
498 while ((rep = TAILQ_FIRST(&p->replies)((&p->replies)->tqh_first)) != NULL((void *)0)) {
1
Assuming the condition is true
2
Loop condition is true. Entering loop body
10
Loop condition is true. Entering loop body
499 memset(&msg, 0, sizeof(msg));
500
501 msg.msg_control = (caddr_t)&cmsgbuf.buf;
502 msg.msg_controllen = sizeof(cmsgbuf.buf);
503 cmsg = CMSG_FIRSTHDR(&msg)((&msg)->msg_controllen >= sizeof(struct cmsghdr) ?
(struct cmsghdr *)(&msg)->msg_control : (struct cmsghdr
*)((void *)0))
;
3
'?' condition is true
11
'?' condition is true
504 cmsg->cmsg_len = CMSG_LEN(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (sizeof(int)))
;
505 cmsg->cmsg_level = SOL_SOCKET0xffff;
506 cmsg->cmsg_type = SCM_RIGHTS0x01;
507 *(int *)CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
= rep->fd;
12
Use of memory after it is freed
508
509 iov.iov_base = &result;
510 iov.iov_len = sizeof(int);
511 msg.msg_iov = &iov;
512 msg.msg_iovlen = 1;
513
514 switch (sendmsg(fd, &msg, 0)) {
4
Control jumps to 'case 4:' at line 515
515 case sizeof(int):
516 break;
5
Execution continues on line 529
517
518 case -1:
519 if (errno(*__errno()) == EAGAIN35)
520 goto again;
521
522 lerr(1, "privproc sendmsg")logger->err((1), "privproc sendmsg");
523 /* NOTREACHED */
524
525 default:
526 lerrx(1, "privproc sendmsg weird len")logger->errx((1), "privproc sendmsg weird len");
527 }
528
529 TAILQ_REMOVE(&p->replies, rep, entry)do { if (((rep)->entry.tqe_next) != ((void *)0)) (rep)->
entry.tqe_next->entry.tqe_prev = (rep)->entry.tqe_prev;
else (&p->replies)->tqh_last = (rep)->entry.tqe_prev
; *(rep)->entry.tqe_prev = (rep)->entry.tqe_next; ; ; }
while (0)
;
6
Assuming field 'tqe_next' is equal to null
7
Taking false branch
8
Loop condition is false. Exiting loop
530 close(rep->fd);
531 free(rep);
9
Memory is released
532 }
533
534 if (TAILQ_EMPTY(&p->replies)(((&p->replies)->tqh_first) == ((void *)0)))
535 return;
536
537again:
538 event_add(&p->push_ev, NULL((void *)0));
539}
540
541void
542proxy_listen(const char *addr, const char *port, int family)
543{
544 struct proxy_listener *l;
545
546 struct addrinfo hints, *res, *res0;
547 int error;
548 int s, on = 1;
549 int serrno;
550 const char *cause = NULL((void *)0);
551
552 memset(&hints, 0, sizeof(hints));
553 hints.ai_family = family;
554 hints.ai_socktype = SOCK_DGRAM2;
555 hints.ai_flags = AI_PASSIVE1;
556
557 TAILQ_INIT(&proxy_listeners)do { (&proxy_listeners)->tqh_first = ((void *)0); (&
proxy_listeners)->tqh_last = &(&proxy_listeners)->
tqh_first; } while (0)
;
558
559 error = getaddrinfo(addr, port, &hints, &res0);
560 if (error)
561 errx(1, "%s:%s: %s", addr, port, gai_strerror(error));
562
563 for (res = res0; res != NULL((void *)0); res = res->ai_next) {
564 s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK0x4000,
565 res->ai_protocol);
566 if (s == -1) {
567 cause = "socket";
568 continue;
569 }
570
571 if (bind(s, res->ai_addr, res->ai_addrlen) == -1) {
572 cause = "bind";
573 serrno = errno(*__errno());
574 close(s);
575 errno(*__errno()) = serrno;
576 continue;
577 }
578
579 l = calloc(1, sizeof(*l));
580 if (l == NULL((void *)0))
581 err(1, "listener alloc");
582
583 switch (res->ai_family) {
584 case AF_INET2:
585 l->cmsg2dst = proxy_dst4;
586
587 if (setsockopt(s, IPPROTO_IP0, IP_RECVDSTADDR7,
588 &on, sizeof(on)) == -1)
589 errx(1, "setsockopt(IP_RECVDSTADDR)");
590 if (setsockopt(s, IPPROTO_IP0, IP_RECVDSTPORT33,
591 &on, sizeof(on)) == -1)
592 errx(1, "setsockopt(IP_RECVDSTPORT)");
593 break;
594 case AF_INET624:
595 l->cmsg2dst = proxy_dst6;
596
597 if (setsockopt(s, IPPROTO_IPV641, IPV6_RECVPKTINFO36,
598 &on, sizeof(on)) == -1)
599 errx(1, "setsockopt(IPV6_RECVPKTINFO)");
600 if (setsockopt(s, IPPROTO_IPV641, IPV6_RECVDSTPORT64,
601 &on, sizeof(on)) == -1)
602 errx(1, "setsockopt(IPV6_RECVDSTPORT)");
603 break;
604 }
605 l->s = s;
606
607 TAILQ_INSERT_TAIL(&proxy_listeners, l, entry)do { (l)->entry.tqe_next = ((void *)0); (l)->entry.tqe_prev
= (&proxy_listeners)->tqh_last; *(&proxy_listeners
)->tqh_last = (l); (&proxy_listeners)->tqh_last = &
(l)->entry.tqe_next; } while (0)
;
608 }
609 freeaddrinfo(res0);
610
611 if (TAILQ_EMPTY(&proxy_listeners)(((&proxy_listeners)->tqh_first) == ((void *)0)))
612 err(1, "%s", cause);
613}
614
615void
616proxy_listener_events(void)
617{
618 struct proxy_listener *l;
619
620 TAILQ_FOREACH(l, &proxy_listeners, entry)for((l) = ((&proxy_listeners)->tqh_first); (l) != ((void
*)0); (l) = ((l)->entry.tqe_next))
{
621 event_set(&l->ev, l->s, EV_READ0x02 | EV_PERSIST0x10, proxy_recv, l);
622 event_add(&l->ev, NULL((void *)0));
623 }
624}
625
626char safety[SEGSIZE_MAX65464 + 4];
627
628int
629proxy_dst4(struct cmsghdr *cmsg, struct sockaddr_storage *ss)
630{
631 struct sockaddr_in *sin = (struct sockaddr_in *)ss;
632
633 if (cmsg->cmsg_level != IPPROTO_IP0)
634 return (0);
635
636 switch (cmsg->cmsg_type) {
637 case IP_RECVDSTADDR7:
638 memcpy(&sin->sin_addr, CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
, sizeof(sin->sin_addr));
639 if (sin->sin_addr.s_addr == INADDR_BROADCAST((u_int32_t)(0xffffffff)))
640 return (-1);
641 break;
642
643 case IP_RECVDSTPORT33:
644 memcpy(&sin->sin_port, CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
, sizeof(sin->sin_port));
645 break;
646 }
647
648 return (0);
649}
650
651int
652proxy_dst6(struct cmsghdr *cmsg, struct sockaddr_storage *ss)
653{
654 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss;
655 struct in6_pktinfo *ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
;
656
657 if (cmsg->cmsg_level != IPPROTO_IPV641)
658 return (0);
659
660 switch (cmsg->cmsg_type) {
661 case IPV6_PKTINFO46:
662 memcpy(&sin6->sin6_addr, &ipi->ipi6_addr,
663 sizeof(sin6->sin6_addr));
664 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))
)
665 sin6->sin6_scope_id = ipi->ipi6_ifindex;
666 break;
667 case IPV6_RECVDSTPORT64:
668 memcpy(&sin6->sin6_port, CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
,
669 sizeof(sin6->sin6_port));
670 break;
671 }
672
673 return (0);
674}
675
676void
677proxy_recv(int fd, short events, void *arg)
678{
679 struct proxy_listener *l = arg;
680
681 union {
682 struct cmsghdr hdr;
683 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)))
+
684 CMSG_SPACE(sizeof(in_port_t))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(in_port_t
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
];
685 } cmsgbuf;
686 struct cmsghdr *cmsg;
687 struct msghdr msg;
688 struct iovec iov;
689 ssize_t n;
690
691 struct proxy_request *r;
692 struct tftphdr *tp;
693
694 r = calloc(1, sizeof(*r));
695 if (r == NULL((void *)0)) {
696 recv(fd, safety, sizeof(safety), 0);
697 return;
698 }
699 r->id = arc4random(); /* XXX unique? */
700
701 bzero(&msg, sizeof(msg));
702 iov.iov_base = r->buf;
703 iov.iov_len = sizeof(r->buf);
704 msg.msg_name = &r->addrs.src;
705 msg.msg_namelen = sizeof(r->addrs.src);
706 msg.msg_iov = &iov;
707 msg.msg_iovlen = 1;
708 msg.msg_control = &cmsgbuf.buf;
709 msg.msg_controllen = sizeof(cmsgbuf.buf);
710
711 n = recvmsg(fd, &msg, 0);
712 if (n == -1) {
713 switch (errno(*__errno())) {
714 case EAGAIN35:
715 case EINTR4:
716 goto err;
717 default:
718 lerr(1, "recvmsg")logger->err((1), "recvmsg");
719 /* NOTREACHED */
720 }
721 }
722 r->buflen = n;
723
724 /* check the packet */
725 if (n < 5) {
726 /* not enough to be a real packet */
727 goto err;
728 }
729 tp = (struct tftphdr *)r->buf;
730 switch (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))
) {
731 case RRQ01:
732 case WRQ02:
733 break;
734 default:
735 goto err;
736 }
737
738 r->addrs.dst.ss_family = r->addrs.src.ss_family;
739 r->addrs.dst.ss_len = r->addrs.src.ss_len;
740
741 /* get local address if possible */
742 for (cmsg = CMSG_FIRSTHDR(&msg)((&msg)->msg_controllen >= sizeof(struct cmsghdr) ?
(struct cmsghdr *)(&msg)->msg_control : (struct cmsghdr
*)((void *)0))
; cmsg != NULL((void *)0);
743 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))))
) {
744 if (l->cmsg2dst(cmsg, &r->addrs.dst) == -1)
745 goto err;
746 }
747
748 if (verbose) {
749 linfo("%s:%d -> %s:%d \"%s %s\"",logger->info("%s:%d -> %s:%d \"%s %s\"", sock_ntop((struct
sockaddr *)&r->addrs.src), (__uint16_t)(__builtin_constant_p
(((struct sockaddr_in *)&r->addrs.src)->sin_port) ?
(__uint16_t)(((__uint16_t)(((struct sockaddr_in *)&r->
addrs.src)->sin_port) & 0xffU) << 8 | ((__uint16_t
)(((struct sockaddr_in *)&r->addrs.src)->sin_port) &
0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)&
r->addrs.src)->sin_port)), sock_ntop((struct sockaddr *
)&r->addrs.dst), (__uint16_t)(__builtin_constant_p(((struct
sockaddr_in *)&r->addrs.dst)->sin_port) ? (__uint16_t
)(((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)->
sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in
*)&r->addrs.dst)->sin_port) & 0xff00U) >>
8) : __swap16md(((struct sockaddr_in *)&r->addrs.dst)
->sin_port)), 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))), tp->th_u.tu_stuff
)
750 sock_ntop((struct sockaddr *)&r->addrs.src),logger->info("%s:%d -> %s:%d \"%s %s\"", sock_ntop((struct
sockaddr *)&r->addrs.src), (__uint16_t)(__builtin_constant_p
(((struct sockaddr_in *)&r->addrs.src)->sin_port) ?
(__uint16_t)(((__uint16_t)(((struct sockaddr_in *)&r->
addrs.src)->sin_port) & 0xffU) << 8 | ((__uint16_t
)(((struct sockaddr_in *)&r->addrs.src)->sin_port) &
0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)&
r->addrs.src)->sin_port)), sock_ntop((struct sockaddr *
)&r->addrs.dst), (__uint16_t)(__builtin_constant_p(((struct
sockaddr_in *)&r->addrs.dst)->sin_port) ? (__uint16_t
)(((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)->
sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in
*)&r->addrs.dst)->sin_port) & 0xff00U) >>
8) : __swap16md(((struct sockaddr_in *)&r->addrs.dst)
->sin_port)), 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))), tp->th_u.tu_stuff
)
751 ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port),logger->info("%s:%d -> %s:%d \"%s %s\"", sock_ntop((struct
sockaddr *)&r->addrs.src), (__uint16_t)(__builtin_constant_p
(((struct sockaddr_in *)&r->addrs.src)->sin_port) ?
(__uint16_t)(((__uint16_t)(((struct sockaddr_in *)&r->
addrs.src)->sin_port) & 0xffU) << 8 | ((__uint16_t
)(((struct sockaddr_in *)&r->addrs.src)->sin_port) &
0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)&
r->addrs.src)->sin_port)), sock_ntop((struct sockaddr *
)&r->addrs.dst), (__uint16_t)(__builtin_constant_p(((struct
sockaddr_in *)&r->addrs.dst)->sin_port) ? (__uint16_t
)(((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)->
sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in
*)&r->addrs.dst)->sin_port) & 0xff00U) >>
8) : __swap16md(((struct sockaddr_in *)&r->addrs.dst)
->sin_port)), 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))), tp->th_u.tu_stuff
)
752 sock_ntop((struct sockaddr *)&r->addrs.dst),logger->info("%s:%d -> %s:%d \"%s %s\"", sock_ntop((struct
sockaddr *)&r->addrs.src), (__uint16_t)(__builtin_constant_p
(((struct sockaddr_in *)&r->addrs.src)->sin_port) ?
(__uint16_t)(((__uint16_t)(((struct sockaddr_in *)&r->
addrs.src)->sin_port) & 0xffU) << 8 | ((__uint16_t
)(((struct sockaddr_in *)&r->addrs.src)->sin_port) &
0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)&
r->addrs.src)->sin_port)), sock_ntop((struct sockaddr *
)&r->addrs.dst), (__uint16_t)(__builtin_constant_p(((struct
sockaddr_in *)&r->addrs.dst)->sin_port) ? (__uint16_t
)(((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)->
sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in
*)&r->addrs.dst)->sin_port) & 0xff00U) >>
8) : __swap16md(((struct sockaddr_in *)&r->addrs.dst)
->sin_port)), 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))), tp->th_u.tu_stuff
)
753 ntohs(((struct sockaddr_in *)&r->addrs.dst)->sin_port),logger->info("%s:%d -> %s:%d \"%s %s\"", sock_ntop((struct
sockaddr *)&r->addrs.src), (__uint16_t)(__builtin_constant_p
(((struct sockaddr_in *)&r->addrs.src)->sin_port) ?
(__uint16_t)(((__uint16_t)(((struct sockaddr_in *)&r->
addrs.src)->sin_port) & 0xffU) << 8 | ((__uint16_t
)(((struct sockaddr_in *)&r->addrs.src)->sin_port) &
0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)&
r->addrs.src)->sin_port)), sock_ntop((struct sockaddr *
)&r->addrs.dst), (__uint16_t)(__builtin_constant_p(((struct
sockaddr_in *)&r->addrs.dst)->sin_port) ? (__uint16_t
)(((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)->
sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in
*)&r->addrs.dst)->sin_port) & 0xff00U) >>
8) : __swap16md(((struct sockaddr_in *)&r->addrs.dst)
->sin_port)), 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))), tp->th_u.tu_stuff
)
754 opcode(ntohs(tp->th_opcode)), tp->th_stuff)logger->info("%s:%d -> %s:%d \"%s %s\"", sock_ntop((struct
sockaddr *)&r->addrs.src), (__uint16_t)(__builtin_constant_p
(((struct sockaddr_in *)&r->addrs.src)->sin_port) ?
(__uint16_t)(((__uint16_t)(((struct sockaddr_in *)&r->
addrs.src)->sin_port) & 0xffU) << 8 | ((__uint16_t
)(((struct sockaddr_in *)&r->addrs.src)->sin_port) &
0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)&
r->addrs.src)->sin_port)), sock_ntop((struct sockaddr *
)&r->addrs.dst), (__uint16_t)(__builtin_constant_p(((struct
sockaddr_in *)&r->addrs.dst)->sin_port) ? (__uint16_t
)(((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)->
sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in
*)&r->addrs.dst)->sin_port) & 0xff00U) >>
8) : __swap16md(((struct sockaddr_in *)&r->addrs.dst)
->sin_port)), 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))), tp->th_u.tu_stuff
)
;
755 /* XXX tp->th_stuff could be garbage */
756 }
757
758 TAILQ_INSERT_TAIL(&child->fdrequests, r, entry)do { (r)->entry.tqe_next = ((void *)0); (r)->entry.tqe_prev
= (&child->fdrequests)->tqh_last; *(&child->
fdrequests)->tqh_last = (r); (&child->fdrequests)->
tqh_last = &(r)->entry.tqe_next; } while (0)
;
759 evbuffer_add(child->buf, &r->addrs, sizeof(r->addrs));
760 event_add(&child->push_ev, NULL((void *)0));
761
762 return;
763
764err:
765 free(r);
766}
767
768void
769unprivproc_push(int fd, short events, void *arg)
770{
771 if (evbuffer_write(child->buf, fd) == -1)
772 lerr(1, "child evbuffer_write")logger->err((1), "child evbuffer_write");
773
774 if (EVBUFFER_LENGTH(child->buf)(child->buf)->off)
775 event_add(&child->push_ev, NULL((void *)0));
776}
777
778void
779unprivproc_pop(int fd, short events, void *arg)
780{
781 struct proxy_request *r;
782
783 struct msghdr msg;
784 union {
785 struct cmsghdr hdr;
786 char buf[CMSG_SPACE(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(int))
+ (sizeof(long) - 1)) &~(sizeof(long) - 1)))
];
787 } cmsgbuf;
788 struct cmsghdr *cmsg;
789 struct iovec iov;
790 struct src_addr *src_addr;
791 struct sockaddr_storage saddr;
792 socklen_t len;
793 int result;
794 int s;
795
796 len = sizeof(saddr);
797
798 do {
799 memset(&msg, 0, sizeof(msg));
800 iov.iov_base = &result;
801 iov.iov_len = sizeof(int);
802 msg.msg_iov = &iov;
803 msg.msg_iovlen = 1;
804 msg.msg_control = &cmsgbuf.buf;
805 msg.msg_controllen = sizeof(cmsgbuf.buf);
806
807 switch (recvmsg(fd, &msg, 0)) {
808 case sizeof(int):
809 break;
810
811 case -1:
812 switch (errno(*__errno())) {
813 case EAGAIN35:
814 case EINTR4:
815 return;
816 default:
817 lerr(1, "child recvmsg")logger->err((1), "child recvmsg");
818 }
819 /* NOTREACHED */
820
821 case 0:
822 lerrx(1, "privproc closed connection")logger->errx((1), "privproc closed connection");
823
824 default:
825 lerrx(1, "child recvmsg was weird")logger->errx((1), "child recvmsg was weird");
826 /* NOTREACHED */
827 }
828
829 if (result != 0) {
830 errno(*__errno()) = result;
831 lerr(1, "child fdpass fail")logger->err((1), "child fdpass fail");
832 }
833
834 cmsg = CMSG_FIRSTHDR(&msg)((&msg)->msg_controllen >= sizeof(struct cmsghdr) ?
(struct cmsghdr *)(&msg)->msg_control : (struct cmsghdr
*)((void *)0))
;
835 if (cmsg == NULL((void *)0))
836 lerrx(1, "%s: no message header", __func__)logger->errx((1), "%s: no message header", __func__);
837
838 if (cmsg->cmsg_type != SCM_RIGHTS0x01) {
839 lerrx(1, "%s: expected type %d got %d", __func__,logger->errx((1), "%s: expected type %d got %d", __func__,
0x01, cmsg->cmsg_type)
840 SCM_RIGHTS, cmsg->cmsg_type)logger->errx((1), "%s: expected type %d got %d", __func__,
0x01, cmsg->cmsg_type)
;
841 }
842
843 s = (*(int *)CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
);
844
845 r = TAILQ_FIRST(&child->fdrequests)((&child->fdrequests)->tqh_first);
846 if (r == NULL((void *)0))
847 lerrx(1, "got fd without a pending request")logger->errx((1), "got fd without a pending request");
848
849 TAILQ_REMOVE(&child->fdrequests, r, entry)do { if (((r)->entry.tqe_next) != ((void *)0)) (r)->entry
.tqe_next->entry.tqe_prev = (r)->entry.tqe_prev; else (
&child->fdrequests)->tqh_last = (r)->entry.tqe_prev
; *(r)->entry.tqe_prev = (r)->entry.tqe_next; ; ; } while
(0)
;
850
851 /* get ready to add rules */
852 if (prepare_commit(r->id) == -1)
853 lerr(1, "%s: prepare_commit", __func__)logger->err((1), "%s: prepare_commit", __func__);
854
855 TAILQ_FOREACH(src_addr, &src_addrs, entry)for((src_addr) = ((&src_addrs)->tqh_first); (src_addr)
!= ((void *)0); (src_addr) = ((src_addr)->entry.tqe_next)
)
856 if (src_addr->addr.ss_family == r->addrs.dst.ss_family)
857 break;
858 if (src_addr == NULL((void *)0)) {
859 if (add_filter(r->id, PF_IN, (struct sockaddr *)
860 &r->addrs.dst, (struct sockaddr *)&r->addrs.src,
861 ntohs(((struct sockaddr_in *)&r->addrs.src)(__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)&
r->addrs.src) ->sin_port) ? (__uint16_t)(((__uint16_t)(
((struct sockaddr_in *)&r->addrs.src) ->sin_port) &
0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)&
r->addrs.src) ->sin_port) & 0xff00U) >> 8) : __swap16md
(((struct sockaddr_in *)&r->addrs.src) ->sin_port))
862 ->sin_port)(__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)&
r->addrs.src) ->sin_port) ? (__uint16_t)(((__uint16_t)(
((struct sockaddr_in *)&r->addrs.src) ->sin_port) &
0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)&
r->addrs.src) ->sin_port) & 0xff00U) >> 8) : __swap16md
(((struct sockaddr_in *)&r->addrs.src) ->sin_port))
, IPPROTO_UDP17) == -1)
863 lerr(1, "%s: couldn't add pass in", __func__)logger->err((1), "%s: couldn't add pass in", __func__);
864 } else {
865 if (getsockname(s, (struct sockaddr*)&saddr, &len) == -1)
866 lerr(1, "%s: getsockname", __func__)logger->err((1), "%s: getsockname", __func__);
867 if (add_rdr(r->id, (struct sockaddr *)&r->addrs.dst,
868 (struct sockaddr*)&saddr,
869 ntohs(((struct sockaddr_in *)&saddr)->sin_port)(__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)&
saddr)->sin_port) ? (__uint16_t)(((__uint16_t)(((struct sockaddr_in
*)&saddr)->sin_port) & 0xffU) << 8 | ((__uint16_t
)(((struct sockaddr_in *)&saddr)->sin_port) & 0xff00U
) >> 8) : __swap16md(((struct sockaddr_in *)&saddr)
->sin_port))
,
870 (struct sockaddr *)&r->addrs.src,
871 ntohs(((struct sockaddr_in *)&r->addrs.src)->(__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)&
r->addrs.src)-> sin_port) ? (__uint16_t)(((__uint16_t)(
((struct sockaddr_in *)&r->addrs.src)-> sin_port) &
0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)&
r->addrs.src)-> sin_port) & 0xff00U) >> 8) : __swap16md
(((struct sockaddr_in *)&r->addrs.src)-> sin_port))
872 sin_port)(__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)&
r->addrs.src)-> sin_port) ? (__uint16_t)(((__uint16_t)(
((struct sockaddr_in *)&r->addrs.src)-> sin_port) &
0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)&
r->addrs.src)-> sin_port) & 0xff00U) >> 8) : __swap16md
(((struct sockaddr_in *)&r->addrs.src)-> sin_port))
, IPPROTO_UDP17 ) == -1)
873 lerr(1, "%s: couldn't add rdr rule", __func__)logger->err((1), "%s: couldn't add rdr rule", __func__);
874 }
875
876 if (add_filter(r->id, PF_OUT, (struct sockaddr *)&r->addrs.dst,
877 (struct sockaddr *)&r->addrs.src,
878 ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port)(__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)&
r->addrs.src)->sin_port) ? (__uint16_t)(((__uint16_t)((
(struct sockaddr_in *)&r->addrs.src)->sin_port) &
0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)&
r->addrs.src)->sin_port) & 0xff00U) >> 8) : __swap16md
(((struct sockaddr_in *)&r->addrs.src)->sin_port))
,
879 IPPROTO_UDP17) == -1)
880 lerr(1, "%s: couldn't add pass out", __func__)logger->err((1), "%s: couldn't add pass out", __func__);
881
882 if (do_commit() == -1)
883 lerr(1, "%s: couldn't commit rules", __func__)logger->err((1), "%s: couldn't commit rules", __func__);
884
885 /* forward the initial tftp request and start the insanity */
886 if (sendto(s, r->buf, r->buflen, 0,
887 (struct sockaddr *)&r->addrs.dst,
888 r->addrs.dst.ss_len) == -1)
889 lerr(1, "%s: unable to send", __func__)logger->err((1), "%s: unable to send", __func__);
890
891 close(s);
892
893 evtimer_set(&r->ev, unprivproc_timeout, r)event_set(&r->ev, -1, 0, unprivproc_timeout, r);
894 evtimer_add(&r->ev, &transwait)event_add(&r->ev, &transwait);
895
896 TAILQ_INSERT_TAIL(&child->tmrequests, r, entry)do { (r)->entry.tqe_next = ((void *)0); (r)->entry.tqe_prev
= (&child->tmrequests)->tqh_last; *(&child->
tmrequests)->tqh_last = (r); (&child->tmrequests)->
tqh_last = &(r)->entry.tqe_next; } while (0)
;
897 } while (!TAILQ_EMPTY(&child->fdrequests)(((&child->fdrequests)->tqh_first) == ((void *)0)));
898}
899
900void
901unprivproc_timeout(int fd, short events, void *arg)
902{
903 struct proxy_request *r = arg;
904
905 TAILQ_REMOVE(&child->tmrequests, r, entry)do { if (((r)->entry.tqe_next) != ((void *)0)) (r)->entry
.tqe_next->entry.tqe_prev = (r)->entry.tqe_prev; else (
&child->tmrequests)->tqh_last = (r)->entry.tqe_prev
; *(r)->entry.tqe_prev = (r)->entry.tqe_next; ; ; } while
(0)
;
906
907 /* delete our rdr rule and clean up */
908 prepare_commit(r->id);
909 do_commit();
910
911 free(r);
912}
913
914
915const char *
916opcode(int code)
917{
918 static char str[6];
919
920 switch (code) {
921 case 1:
922 (void)snprintf(str, sizeof(str), "RRQ");
923 break;
924 case 2:
925 (void)snprintf(str, sizeof(str), "WRQ");
926 break;
927 default:
928 (void)snprintf(str, sizeof(str), "(%d)", code);
929 break;
930 }
931
932 return (str);
933}
934
935const char *
936sock_ntop(struct sockaddr *sa)
937{
938 static int n = 0;
939
940 /* Cycle to next buffer. */
941 n = (n + 1) % NTOP_BUFS4;
942 ntop_buf[n][0] = '\0';
943
944 if (sa->sa_family == AF_INET2) {
945 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
946
947 return (inet_ntop(AF_INET2, &sin->sin_addr, ntop_buf[n],
948 sizeof ntop_buf[0]));
949 }
950
951 if (sa->sa_family == AF_INET624) {
952 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
953
954 return (inet_ntop(AF_INET624, &sin6->sin6_addr, ntop_buf[n],
955 sizeof ntop_buf[0]));
956 }
957
958 return (NULL((void *)0));
959}
960
961void
962syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
963{
964 char *s;
965
966 if (vasprintf(&s, fmt, ap) == -1) {
967 syslog(LOG_EMERG0, "unable to alloc in syslog_vstrerror");
968 exit(1);
969 }
970
971 syslog(priority, "%s: %s", s, strerror(e));
972
973 free(s);
974}
975
976void
977syslog_err(int ecode, const char *fmt, ...)
978{
979 va_list ap;
980
981 va_start(ap, fmt)__builtin_va_start(ap, fmt);
982 syslog_vstrerror(errno(*__errno()), LOG_CRIT2, fmt, ap);
983 va_end(ap)__builtin_va_end(ap);
984
985 exit(ecode);
986}
987
988void
989syslog_errx(int ecode, const char *fmt, ...)
990{
991 va_list ap;
992
993 va_start(ap, fmt)__builtin_va_start(ap, fmt);
994 vsyslog(LOG_CRIT2, fmt, ap);
995 va_end(ap)__builtin_va_end(ap);
996
997 exit(ecode);
998}
999
1000void
1001syslog_warn(const char *fmt, ...)
1002{
1003 va_list ap;
1004
1005 va_start(ap, fmt)__builtin_va_start(ap, fmt);
1006 syslog_vstrerror(errno(*__errno()), LOG_ERR3, fmt, ap);
1007 va_end(ap)__builtin_va_end(ap);
1008}
1009
1010void
1011syslog_warnx(const char *fmt, ...)
1012{
1013 va_list ap;
1014
1015 va_start(ap, fmt)__builtin_va_start(ap, fmt);
1016 vsyslog(LOG_ERR3, fmt, ap);
1017 va_end(ap)__builtin_va_end(ap);
1018}
1019
1020void
1021syslog_info(const char *fmt, ...)
1022{
1023 va_list ap;
1024
1025 va_start(ap, fmt)__builtin_va_start(ap, fmt);
1026 vsyslog(LOG_INFO6, fmt, ap);
1027 va_end(ap)__builtin_va_end(ap);
1028}
1029
1030void
1031syslog_debug(const char *fmt, ...)
1032{
1033 va_list ap;
1034
1035 if (!debug)
1036 return;
1037
1038 va_start(ap, fmt)__builtin_va_start(ap, fmt);
1039 vsyslog(LOG_DEBUG7, fmt, ap);
1040 va_end(ap)__builtin_va_end(ap);
1041}