GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/tftp-proxy/tftp-proxy.c Lines: 0 409 0.0 %
Date: 2017-11-07 Branches: 0 227 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: tftp-proxy.c,v 1.21 2017/07/04 12:47:51 florian 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.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"
56
#define NOPRIV_USER	"_tftp_proxy"
57
58
#define DEFTRANSWAIT	2
59
#define NTOP_BUFS	4
60
#define PKTSIZE		SEGSIZE+4
61
62
const char *opcode(int);
63
const char *sock_ntop(struct sockaddr *);
64
static void usage(void);
65
66
struct proxy_listener {
67
	struct event ev;
68
	TAILQ_ENTRY(proxy_listener) entry;
69
	int (*cmsg2dst)(struct cmsghdr *, struct sockaddr_storage *);
70
	int s;
71
};
72
73
void	proxy_listen(const char *, const char *, int);
74
void	proxy_listener_events(void);
75
int	proxy_dst4(struct cmsghdr *, struct sockaddr_storage *);
76
int	proxy_dst6(struct cmsghdr *, struct sockaddr_storage *);
77
void	proxy_recv(int, short, void *);
78
79
struct fd_reply {
80
	TAILQ_ENTRY(fd_reply) entry;
81
	int fd;
82
};
83
84
struct privproc {
85
	struct event pop_ev;
86
	struct event push_ev;
87
	TAILQ_HEAD(, fd_reply) replies;
88
	struct evbuffer *buf;
89
};
90
91
void	proxy_privproc(int, struct passwd *);
92
void	privproc_push(int, short, void *);
93
void	privproc_pop(int, short, void *);
94
95
void	unprivproc_push(int, short, void *);
96
void	unprivproc_pop(int, short, void *);
97
void	unprivproc_timeout(int, short, void *);
98
99
char	ntop_buf[NTOP_BUFS][INET6_ADDRSTRLEN];
100
101
struct loggers {
102
	__dead void (*err)(int, const char *, ...)
103
	    __attribute__((__format__ (printf, 2, 3)));
104
	__dead 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
116
const struct loggers conslogger = {
117
	err,
118
	errx,
119
	warn,
120
	warnx,
121
	warnx, /* info */
122
	warnx /* debug */
123
};
124
125
__dead void	syslog_err(int, const char *, ...)
126
		    __attribute__((__format__ (printf, 2, 3)));
127
__dead void	syslog_errx(int, const char *, ...)
128
		    __attribute__((__format__ (printf, 2, 3)));
129
void		syslog_warn(const char *, ...)
130
		    __attribute__((__format__ (printf, 1, 2)));
131
void		syslog_warnx(const char *, ...)
132
		    __attribute__((__format__ (printf, 1, 2)));
133
void		syslog_info(const char *, ...)
134
		    __attribute__((__format__ (printf, 1, 2)));
135
void		syslog_debug(const char *, ...)
136
		    __attribute__((__format__ (printf, 1, 2)));
137
void		syslog_vstrerror(int, int, const char *, va_list)
138
		    __attribute__((__format__ (printf, 3, 0)));
139
140
const struct loggers syslogger = {
141
	syslog_err,
142
	syslog_errx,
143
	syslog_warn,
144
	syslog_warnx,
145
	syslog_info,
146
	syslog_debug
147
};
148
149
const struct loggers *logger = &conslogger;
150
151
#define lerr(_e, _f...) logger->err((_e), _f)
152
#define lerrx(_e, _f...) logger->errx((_e), _f)
153
#define lwarn(_f...) logger->warn(_f)
154
#define lwarnx(_f...) logger->warnx(_f)
155
#define linfo(_f...) logger->info(_f)
156
#define ldebug(_f...) logger->debug(_f)
157
158
__dead void
159
usage(void)
160
{
161
	extern char *__progname;
162
	fprintf(stderr, "usage: %s [-46dv] [-a address] [-l address] [-p port]"
163
	    " [-w transwait]\n", __progname);
164
	exit(1);
165
}
166
167
int	debug = 0;
168
int	verbose = 0;
169
struct timeval transwait = { DEFTRANSWAIT, 0 };
170
171
int on = 1;
172
173
struct addr_pair {
174
	struct sockaddr_storage src;
175
	struct sockaddr_storage dst;
176
};
177
178
struct proxy_request {
179
	char buf[SEGSIZE_MAX + 4];
180
	size_t buflen;
181
182
	struct addr_pair addrs;
183
184
	struct event ev;
185
	TAILQ_ENTRY(proxy_request) entry;
186
	u_int32_t id;
187
};
188
189
struct proxy_child {
190
	TAILQ_HEAD(, proxy_request) fdrequests;
191
	TAILQ_HEAD(, proxy_request) tmrequests;
192
	struct event push_ev;
193
	struct event pop_ev;
194
	struct evbuffer *buf;
195
};
196
197
struct proxy_child *child = NULL;
198
TAILQ_HEAD(, proxy_listener) proxy_listeners;
199
200
struct src_addr {
201
	TAILQ_ENTRY(src_addr)	entry;
202
	struct sockaddr_storage	addr;
203
	socklen_t		addrlen;
204
};
205
TAILQ_HEAD(, src_addr) src_addrs;
206
207
void	source_addresses(const char*, int);
208
209
int
210
main(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_UNSPEC;
223
224
	int pair[2];
225
226
	TAILQ_INIT(&src_addrs);
227
228
	while ((c = getopt(argc, argv, "46a:dvl:p:w:")) != -1) {
229
		switch (c) {
230
		case '4':
231
			family = AF_INET;
232
			break;
233
		case '6':
234
			family = AF_INET6;
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");
264
265
	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, PF_UNSPEC, pair)
266
	    == -1)
267
		lerr(1, "socketpair");
268
269
	pw = getpwnam(NOPRIV_USER);
270
	if (pw == NULL)
271
		lerrx(1, "no %s user", NOPRIV_USER);
272
273
	/* Family option may have been specified late. */
274
	if (family != AF_UNSPEC)
275
		TAILQ_FOREACH_SAFE(saddr, &src_addrs, entry, saddr2)
276
			if (saddr->addr.ss_family != family) {
277
				TAILQ_REMOVE(&src_addrs, saddr, entry);
278
				free(saddr);
279
			}
280
281
	if (!debug) {
282
		if (daemon(1, 0) == -1)
283
			lerr(1, "daemon");
284
285
		openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
286
		tzset();
287
		logger = &syslogger;
288
	}
289
290
	switch (fork()) {
291
	case -1:
292
		lerr(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)
308
		lerr(1, "alloc(child)");
309
310
	child->buf = evbuffer_new();
311
	if (child->buf == NULL)
312
		lerr(1, "child evbuffer");
313
314
	TAILQ_INIT(&child->fdrequests);
315
	TAILQ_INIT(&child->tmrequests);
316
317
	proxy_listen(addr, port, family);
318
319
	/* open /dev/pf */
320
	init_filter(NULL, verbose);
321
322
	/* revoke privs */
323
	if (chroot(CHROOT_DIR) == -1)
324
		lerr(1, "chroot %s", CHROOT_DIR);
325
326
	if (chdir("/") == -1)
327
		lerr(1, "chdir %s", CHROOT_DIR);
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_READ | EV_PERSIST,
339
	    unprivproc_pop, NULL);
340
	event_set(&child->push_ev, pair[1], EV_WRITE,
341
	    unprivproc_push, NULL);
342
343
	event_add(&child->pop_ev, NULL);
344
345
	event_dispatch();
346
347
	return(0);
348
}
349
350
void
351
source_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_DGRAM;
360
	hints.ai_flags = AI_PASSIVE;
361
	error = getaddrinfo(name, NULL, &hints, &res0);
362
	if (error)
363
		lerrx(1, "%s: %s", name, gai_strerror(error));
364
	for (res = res0; res != NULL; res = res->ai_next) {
365
		if ((saddr = calloc(1, sizeof(struct src_addr))) == NULL)
366
			lerrx(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);
370
	}
371
	freeaddrinfo(res0);
372
}
373
374
void
375
proxy_privproc(int s, struct passwd *pw)
376
{
377
	struct privproc p;
378
379
	if (chroot(CHROOT_DIR) == -1)
380
		lerr(1, "chroot to %s", CHROOT_DIR);
381
382
	if (chdir("/") == -1)
383
		lerr(1, "chdir to %s", CHROOT_DIR);
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");
388
389
	if (pledge("stdio inet sendfd flock rpath cpath wpath", NULL) == -1)
390
		err(1, "pledge");
391
392
	TAILQ_INIT(&p.replies);
393
394
	p.buf = evbuffer_new();
395
	if (p.buf == NULL)
396
		err(1, "pop evbuffer_new");
397
398
	event_init();
399
400
	event_set(&p.pop_ev, s, EV_READ | EV_PERSIST, privproc_pop, &p);
401
	event_set(&p.push_ev, s, EV_WRITE, privproc_push, &p);
402
403
	event_add(&p.pop_ev, NULL);
404
405
	event_dispatch();
406
}
407
408
void
409
privproc_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");
420
	case -1:
421
		switch (errno) {
422
		case EAGAIN:
423
		case EINTR:
424
			return;
425
		default:
426
			lerr(1, "privproc_pop read");
427
		}
428
	default:
429
		break;
430
	}
431
432
	while (EVBUFFER_LENGTH(p->buf) >= 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");
438
439
		rep = calloc(1, sizeof(*rep));
440
		if (rep == NULL)
441
			lerr(1, "reply calloc");
442
443
		rep->fd = socket(req.src.ss_family, SOCK_DGRAM | SOCK_NONBLOCK,
444
		    IPPROTO_UDP);
445
		if (rep->fd == -1)
446
			lerr(1, "privproc socket");
447
448
		if (setsockopt(rep->fd, SOL_SOCKET, SO_BINDANY,
449
		    &on, sizeof(on)) == -1)
450
			lerr(1, "privproc setsockopt(BINDANY)");
451
452
		if (setsockopt(rep->fd, SOL_SOCKET, SO_REUSEADDR,
453
		    &on, sizeof(on)) == -1)
454
			lerr(1, "privproc setsockopt(REUSEADDR)");
455
456
		if (setsockopt(rep->fd, SOL_SOCKET, SO_REUSEPORT,
457
		    &on, sizeof(on)) == -1)
458
			lerr(1, "privproc setsockopt(REUSEPORT)");
459
460
		TAILQ_FOREACH(saddr, &src_addrs, entry)
461
			if (saddr->addr.ss_family == req.src.ss_family)
462
				break;
463
		if (saddr == NULL) {
464
			if (bind(rep->fd, (struct sockaddr *)&req.src,
465
			    req.src.ss_len) == -1)
466
				lerr(1, "privproc bind");
467
		} else {
468
			if (bind(rep->fd, (struct sockaddr*)&saddr->addr,
469
			    saddr->addrlen) == -1)
470
				lerr(1, "privproc bind");
471
		}
472
473
		if (TAILQ_EMPTY(&p->replies))
474
			add = 1;
475
476
		TAILQ_INSERT_TAIL(&p->replies, rep, entry);
477
	}
478
479
	if (add)
480
		event_add(&p->push_ev, NULL);
481
}
482
483
void
484
privproc_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))];
493
	} cmsgbuf;
494
	struct cmsghdr *cmsg;
495
	struct iovec iov;
496
	int result = 0;
497
498
	while ((rep = TAILQ_FIRST(&p->replies)) != NULL) {
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);
504
		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
505
		cmsg->cmsg_level = SOL_SOCKET;
506
		cmsg->cmsg_type = SCM_RIGHTS;
507
		*(int *)CMSG_DATA(cmsg) = rep->fd;
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)) {
515
		case sizeof(int):
516
			break;
517
518
		case -1:
519
			if (errno == EAGAIN)
520
				goto again;
521
522
			lerr(1, "privproc sendmsg");
523
			/* NOTREACHED */
524
525
		default:
526
			lerrx(1, "privproc sendmsg weird len");
527
		}
528
529
		TAILQ_REMOVE(&p->replies, rep, entry);
530
		close(rep->fd);
531
		free(rep);
532
	}
533
534
	if (TAILQ_EMPTY(&p->replies))
535
		return;
536
537
again:
538
	event_add(&p->push_ev, NULL);
539
}
540
541
void
542
proxy_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;
551
552
	memset(&hints, 0, sizeof(hints));
553
	hints.ai_family = family;
554
	hints.ai_socktype = SOCK_DGRAM;
555
	hints.ai_flags = AI_PASSIVE;
556
557
	TAILQ_INIT(&proxy_listeners);
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; res = res->ai_next) {
564
		s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK,
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;
574
			close(s);
575
			errno = serrno;
576
			continue;
577
		}
578
579
		l = calloc(1, sizeof(*l));
580
		if (l == NULL)
581
			err(1, "listener alloc");
582
583
		switch (res->ai_family) {
584
		case AF_INET:
585
			l->cmsg2dst = proxy_dst4;
586
587
			if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR,
588
			    &on, sizeof(on)) == -1)
589
				errx(1, "setsockopt(IP_RECVDSTADDR)");
590
			if (setsockopt(s, IPPROTO_IP, IP_RECVDSTPORT,
591
			    &on, sizeof(on)) == -1)
592
				errx(1, "setsockopt(IP_RECVDSTPORT)");
593
			break;
594
		case AF_INET6:
595
			l->cmsg2dst = proxy_dst6;
596
597
			if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
598
			    &on, sizeof(on)) == -1)
599
				errx(1, "setsockopt(IPV6_RECVPKTINFO)");
600
			if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTPORT,
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);
608
	}
609
	freeaddrinfo(res0);
610
611
	if (TAILQ_EMPTY(&proxy_listeners))
612
		err(1, "%s", cause);
613
}
614
615
void
616
proxy_listener_events(void)
617
{
618
	struct proxy_listener *l;
619
620
	TAILQ_FOREACH(l, &proxy_listeners, entry) {
621
		event_set(&l->ev, l->s, EV_READ | EV_PERSIST, proxy_recv, l);
622
		event_add(&l->ev, NULL);
623
	}
624
}
625
626
char safety[SEGSIZE_MAX + 4];
627
628
int
629
proxy_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_IP)
634
		return (0);
635
636
	switch (cmsg->cmsg_type) {
637
	case IP_RECVDSTADDR:
638
		memcpy(&sin->sin_addr, CMSG_DATA(cmsg), sizeof(sin->sin_addr));
639
		if (sin->sin_addr.s_addr == INADDR_BROADCAST)
640
			return (-1);
641
		break;
642
643
	case IP_RECVDSTPORT:
644
		memcpy(&sin->sin_port, CMSG_DATA(cmsg), sizeof(sin->sin_port));
645
		break;
646
	}
647
648
	return (0);
649
}
650
651
int
652
proxy_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);
656
657
	if (cmsg->cmsg_level != IPPROTO_IPV6)
658
		return (0);
659
660
	switch (cmsg->cmsg_type) {
661
	case IPV6_PKTINFO:
662
		memcpy(&sin6->sin6_addr, &ipi->ipi6_addr,
663
		    sizeof(sin6->sin6_addr));
664
#ifdef __KAME__
665
		if (IN6_IS_ADDR_LINKLOCAL(&ipi->ipi6_addr))
666
		    sin6->sin6_scope_id = ipi->ipi6_ifindex;
667
#endif
668
		break;
669
	case IPV6_RECVDSTPORT:
670
		memcpy(&sin6->sin6_port, CMSG_DATA(cmsg),
671
		    sizeof(sin6->sin6_port));
672
		break;
673
	}
674
675
	return (0);
676
}
677
678
void
679
proxy_recv(int fd, short events, void *arg)
680
{
681
	struct proxy_listener *l = arg;
682
683
	union {
684
		struct cmsghdr hdr;
685
		char buf[CMSG_SPACE(sizeof(struct sockaddr_storage)) +
686
		    CMSG_SPACE(sizeof(in_port_t))];
687
	} cmsgbuf;
688
	struct cmsghdr *cmsg;
689
	struct msghdr msg;
690
	struct iovec iov;
691
	ssize_t n;
692
693
	struct proxy_request *r;
694
	struct tftphdr *tp;
695
696
	r = calloc(1, sizeof(*r));
697
	if (r == NULL) {
698
		recv(fd, safety, sizeof(safety), 0);
699
		return;
700
	}
701
	r->id = arc4random(); /* XXX unique? */
702
703
	bzero(&msg, sizeof(msg));
704
	iov.iov_base = r->buf;
705
	iov.iov_len = sizeof(r->buf);
706
	msg.msg_name = &r->addrs.src;
707
	msg.msg_namelen = sizeof(r->addrs.src);
708
	msg.msg_iov = &iov;
709
	msg.msg_iovlen = 1;
710
	msg.msg_control = &cmsgbuf.buf;
711
	msg.msg_controllen = sizeof(cmsgbuf.buf);
712
713
	n = recvmsg(fd, &msg, 0);
714
	if (n == -1) {
715
		switch (errno) {
716
		case EAGAIN:
717
		case EINTR:
718
			goto err;
719
		default:
720
			lerr(1, "recvmsg");
721
			/* NOTREACHED */
722
		}
723
	}
724
	r->buflen = n;
725
726
	/* check the packet */
727
	if (n < 5) {
728
		/* not enough to be a real packet */
729
		goto err;
730
	}
731
	tp = (struct tftphdr *)r->buf;
732
	switch (ntohs(tp->th_opcode)) {
733
	case RRQ:
734
	case WRQ:
735
		break;
736
	default:
737
		goto err;
738
	}
739
740
	r->addrs.dst.ss_family = r->addrs.src.ss_family;
741
	r->addrs.dst.ss_len = r->addrs.src.ss_len;
742
743
	/* get local address if possible */
744
	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
745
	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
746
		if (l->cmsg2dst(cmsg, &r->addrs.dst) == -1)
747
			goto err;
748
	}
749
750
	if (verbose) {
751
		linfo("%s:%d -> %s:%d \"%s %s\"",
752
		    sock_ntop((struct sockaddr *)&r->addrs.src),
753
		    ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port),
754
		    sock_ntop((struct sockaddr *)&r->addrs.dst),
755
		    ntohs(((struct sockaddr_in *)&r->addrs.dst)->sin_port),
756
		    opcode(ntohs(tp->th_opcode)), tp->th_stuff);
757
		/* XXX tp->th_stuff could be garbage */
758
	}
759
760
	TAILQ_INSERT_TAIL(&child->fdrequests, r, entry);
761
	evbuffer_add(child->buf, &r->addrs, sizeof(r->addrs));
762
	event_add(&child->push_ev, NULL);
763
764
	return;
765
766
err:
767
	free(r);
768
}
769
770
void
771
unprivproc_push(int fd, short events, void *arg)
772
{
773
	if (evbuffer_write(child->buf, fd) == -1)
774
		lerr(1, "child evbuffer_write");
775
776
	if (EVBUFFER_LENGTH(child->buf))
777
		event_add(&child->push_ev, NULL);
778
}
779
780
void
781
unprivproc_pop(int fd, short events, void *arg)
782
{
783
	struct proxy_request *r;
784
785
	struct msghdr msg;
786
	union {
787
		struct cmsghdr hdr;
788
		char buf[CMSG_SPACE(sizeof(int))];
789
	} cmsgbuf;
790
	struct cmsghdr *cmsg;
791
	struct iovec iov;
792
	struct src_addr *src_addr;
793
	struct sockaddr_storage saddr;
794
	socklen_t len;
795
	int result;
796
	int s;
797
798
	len = sizeof(saddr);
799
800
	do {
801
		memset(&msg, 0, sizeof(msg));
802
		iov.iov_base = &result;
803
		iov.iov_len = sizeof(int);
804
		msg.msg_iov = &iov;
805
		msg.msg_iovlen = 1;
806
		msg.msg_control = &cmsgbuf.buf;
807
		msg.msg_controllen = sizeof(cmsgbuf.buf);
808
809
		switch (recvmsg(fd, &msg, 0)) {
810
		case sizeof(int):
811
			break;
812
813
		case -1:
814
			switch (errno) {
815
			case EAGAIN:
816
			case EINTR:
817
				return;
818
			default:
819
				lerr(1, "child recvmsg");
820
			}
821
			/* NOTREACHED */
822
823
		case 0:
824
			lerrx(1, "privproc closed connection");
825
826
		default:
827
			lerrx(1, "child recvmsg was weird");
828
			/* NOTREACHED */
829
		}
830
831
		if (result != 0) {
832
			errno = result;
833
			lerr(1, "child fdpass fail");
834
		}
835
836
		cmsg = CMSG_FIRSTHDR(&msg);
837
		if (cmsg == NULL)
838
			lerrx(1, "%s: no message header", __func__);
839
840
		if (cmsg->cmsg_type != SCM_RIGHTS) {
841
			lerrx(1, "%s: expected type %d got %d", __func__,
842
			    SCM_RIGHTS, cmsg->cmsg_type);
843
		}
844
845
		s = (*(int *)CMSG_DATA(cmsg));
846
847
		r = TAILQ_FIRST(&child->fdrequests);
848
		if (r == NULL)
849
			lerrx(1, "got fd without a pending request");
850
851
		TAILQ_REMOVE(&child->fdrequests, r, entry);
852
853
		/* get ready to add rules */
854
		if (prepare_commit(r->id) == -1)
855
			lerr(1, "%s: prepare_commit", __func__);
856
857
		TAILQ_FOREACH(src_addr, &src_addrs, entry)
858
			if (src_addr->addr.ss_family == r->addrs.dst.ss_family)
859
				break;
860
		if (src_addr == NULL) {
861
			if (add_filter(r->id, PF_IN, (struct sockaddr *)
862
			    &r->addrs.dst, (struct sockaddr *)&r->addrs.src,
863
			    ntohs(((struct sockaddr_in *)&r->addrs.src)
864
			    ->sin_port), IPPROTO_UDP) == -1)
865
				lerr(1, "%s: couldn't add pass in", __func__);
866
		} else {
867
			if (getsockname(s, (struct sockaddr*)&saddr, &len) == -1)
868
				lerr(1, "%s: getsockname", __func__);
869
			if (add_rdr(r->id, (struct sockaddr *)&r->addrs.dst,
870
			    (struct sockaddr*)&saddr,
871
			    ntohs(((struct sockaddr_in *)&saddr)->sin_port),
872
			    (struct sockaddr *)&r->addrs.src,
873
			    ntohs(((struct sockaddr_in *)&r->addrs.src)->
874
			    sin_port), IPPROTO_UDP ) == -1)
875
				lerr(1, "%s: couldn't add rdr rule", __func__);
876
		}
877
878
		if (add_filter(r->id, PF_OUT, (struct sockaddr *)&r->addrs.dst,
879
		    (struct sockaddr *)&r->addrs.src,
880
		    ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port),
881
		    IPPROTO_UDP) == -1)
882
			lerr(1, "%s: couldn't add pass out", __func__);
883
884
		if (do_commit() == -1)
885
			lerr(1, "%s: couldn't commit rules", __func__);
886
887
		/* forward the initial tftp request and start the insanity */
888
		if (sendto(s, r->buf, r->buflen, 0,
889
		    (struct sockaddr *)&r->addrs.dst,
890
		    r->addrs.dst.ss_len) == -1)
891
			lerr(1, "%s: unable to send", __func__);
892
893
		close(s);
894
895
		evtimer_set(&r->ev, unprivproc_timeout, r);
896
		evtimer_add(&r->ev, &transwait);
897
898
		TAILQ_INSERT_TAIL(&child->tmrequests, r, entry);
899
	} while (!TAILQ_EMPTY(&child->fdrequests));
900
}
901
902
void
903
unprivproc_timeout(int fd, short events, void *arg)
904
{
905
	struct proxy_request *r = arg;
906
907
	TAILQ_REMOVE(&child->tmrequests, r, entry);
908
909
	/* delete our rdr rule and clean up */
910
	prepare_commit(r->id);
911
	do_commit();
912
913
	free(r);
914
}
915
916
917
const char *
918
opcode(int code)
919
{
920
	static char str[6];
921
922
	switch (code) {
923
	case 1:
924
		(void)snprintf(str, sizeof(str), "RRQ");
925
		break;
926
	case 2:
927
		(void)snprintf(str, sizeof(str), "WRQ");
928
		break;
929
	default:
930
		(void)snprintf(str, sizeof(str), "(%d)", code);
931
		break;
932
	}
933
934
	return (str);
935
}
936
937
const char *
938
sock_ntop(struct sockaddr *sa)
939
{
940
	static int n = 0;
941
942
	/* Cycle to next buffer. */
943
	n = (n + 1) % NTOP_BUFS;
944
	ntop_buf[n][0] = '\0';
945
946
	if (sa->sa_family == AF_INET) {
947
		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
948
949
		return (inet_ntop(AF_INET, &sin->sin_addr, ntop_buf[n],
950
		    sizeof ntop_buf[0]));
951
	}
952
953
	if (sa->sa_family == AF_INET6) {
954
		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
955
956
		return (inet_ntop(AF_INET6, &sin6->sin6_addr, ntop_buf[n],
957
		    sizeof ntop_buf[0]));
958
	}
959
960
	return (NULL);
961
}
962
963
void
964
syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
965
{
966
	char *s;
967
968
	if (vasprintf(&s, fmt, ap) == -1) {
969
		syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror");
970
		exit(1);
971
	}
972
973
	syslog(priority, "%s: %s", s, strerror(e));
974
975
	free(s);
976
}
977
978
void
979
syslog_err(int ecode, const char *fmt, ...)
980
{
981
	va_list ap;
982
983
	va_start(ap, fmt);
984
	syslog_vstrerror(errno, LOG_CRIT, fmt, ap);
985
	va_end(ap);
986
987
	exit(ecode);
988
}
989
990
void
991
syslog_errx(int ecode, const char *fmt, ...)
992
{
993
	va_list ap;
994
995
	va_start(ap, fmt);
996
	vsyslog(LOG_CRIT, fmt, ap);
997
	va_end(ap);
998
999
	exit(ecode);
1000
}
1001
1002
void
1003
syslog_warn(const char *fmt, ...)
1004
{
1005
	va_list ap;
1006
1007
	va_start(ap, fmt);
1008
	syslog_vstrerror(errno, LOG_ERR, fmt, ap);
1009
	va_end(ap);
1010
}
1011
1012
void
1013
syslog_warnx(const char *fmt, ...)
1014
{
1015
	va_list ap;
1016
1017
	va_start(ap, fmt);
1018
	vsyslog(LOG_ERR, fmt, ap);
1019
	va_end(ap);
1020
}
1021
1022
void
1023
syslog_info(const char *fmt, ...)
1024
{
1025
	va_list ap;
1026
1027
	va_start(ap, fmt);
1028
	vsyslog(LOG_INFO, fmt, ap);
1029
	va_end(ap);
1030
}
1031
1032
void
1033
syslog_debug(const char *fmt, ...)
1034
{
1035
	va_list ap;
1036
1037
	if (!debug)
1038
		return;
1039
1040
	va_start(ap, fmt);
1041
	vsyslog(LOG_DEBUG, fmt, ap);
1042
	va_end(ap);
1043
}