tftpd.c revision 1.43
1/*	$OpenBSD: tftpd.c,v 1.43 2019/07/03 03:24:03 deraadt 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.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 TIMEOUT		5		/* packet rexmt timeout */
90#define TIMEOUT_MIN	1		/* minimal packet rexmt timeout */
91#define TIMEOUT_MAX	255		/* maximal packet rexmt timeout */
92
93#define RETRIES		5
94
95#define SEEDPATH	"/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) entry;
121	int s;
122};
123
124TAILQ_HEAD(, tftp_server) tftp_servers;
125
126struct tftp_client {
127	char buf[SEGSIZE_MAX + 4];
128	struct event sev;
129	struct sockaddr_storage ss;
130
131	struct timeval tv;
132
133	TAILQ_ENTRY(tftp_client) 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 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 *);
184int		tftp_wrq_ack_packet(struct tftp_client *);
185void		tftp_rrq_ack(int, short, void *);
186void		tftp_wrq_ack(struct tftp_client *client);
187void		tftp_wrq(int, short, void *);
188void		tftp_wrq_end(int, short, void *);
189
190int		parse_options(struct tftp_client *, char *, size_t,
191		    struct opt_client *);
192int		validate_access(struct tftp_client *, const char *);
193
194struct tftp_client *
195		client_alloc(void);
196void		client_free(struct tftp_client *client);
197
198struct formats {
199	const char	*f_mode;
200	int (*f_getc)(struct tftp_client *);
201	int (*f_putc)(struct tftp_client *, int);
202} formats[] = {
203	{ "octet",	fget_octet,	fput_octet },
204	{ "netascii",	fget_netascii,	fput_netascii },
205	{ NULL,		NULL }
206};
207
208struct errmsg {
209	int		 e_code;
210	const char	*e_msg;
211} errmsgs[] = {
212	{ EUNDEF,	"Undefined error code" },
213	{ ENOTFOUND,	"File not found" },
214	{ EACCESS,	"Access violation" },
215	{ ENOSPACE,	"Disk full or allocation exceeded" },
216	{ EBADOP,	"Illegal TFTP operation" },
217	{ EBADID,	"Unknown transfer ID" },
218	{ EEXISTS,	"File already exists" },
219	{ ENOUSER,	"No such user" },
220	{ EOPTNEG,	"Option negotiation failed" },
221	{ -1,		NULL }
222};
223
224struct loggers {
225	__dead void (*err)(int, const char *, ...)
226	    __attribute__((__format__ (printf, 2, 3)));
227	__dead void (*errx)(int, const char *, ...)
228	    __attribute__((__format__ (printf, 2, 3)));
229	void (*warn)(const char *, ...)
230	    __attribute__((__format__ (printf, 1, 2)));
231	void (*warnx)(const char *, ...)
232	    __attribute__((__format__ (printf, 1, 2)));
233	void (*info)(const char *, ...)
234	    __attribute__((__format__ (printf, 1, 2)));
235	void (*debug)(const char *, ...)
236	    __attribute__((__format__ (printf, 1, 2)));
237};
238
239const struct loggers conslogger = {
240	err,
241	errx,
242	warn,
243	warnx,
244	warnx, /* info */
245	warnx /* debug */
246};
247
248__dead void	syslog_err(int, const char *, ...)
249		    __attribute__((__format__ (printf, 2, 3)));
250__dead void	syslog_errx(int, const char *, ...)
251		    __attribute__((__format__ (printf, 2, 3)));
252void		syslog_warn(const char *, ...)
253		    __attribute__((__format__ (printf, 1, 2)));
254void		syslog_warnx(const char *, ...)
255		    __attribute__((__format__ (printf, 1, 2)));
256void		syslog_info(const char *, ...)
257		    __attribute__((__format__ (printf, 1, 2)));
258void		syslog_debug(const char *, ...)
259		    __attribute__((__format__ (printf, 1, 2)));
260void		syslog_vstrerror(int, int, const char *, va_list)
261		    __attribute__((__format__ (printf, 3, 0)));
262
263const struct loggers syslogger = {
264	syslog_err,
265	syslog_errx,
266	syslog_warn,
267	syslog_warnx,
268	syslog_info,
269	syslog_debug
270};
271
272const struct loggers *logger = &conslogger;
273
274#define lerr(_e, _f...) logger->err((_e), _f)
275#define lerrx(_e, _f...) logger->errx((_e), _f)
276#define lwarn(_f...) logger->warn(_f)
277#define lwarnx(_f...) logger->warnx(_f)
278#define linfo(_f...) logger->info(_f)
279#define ldebug(_f...) logger->debug(_f)
280
281__dead void
282usage(void)
283{
284	extern char *__progname;
285	fprintf(stderr, "usage: %s [-46cdiv] [-l address] [-p port] [-r socket]"
286	    " directory\n", __progname);
287	exit(1);
288}
289
290int		  cancreate = 0;
291int		  verbose = 0;
292int		  debug = 0;
293int		  iflag = 0;
294
295int
296main(int argc, char *argv[])
297{
298	extern char *__progname;
299
300	int		 c;
301	struct passwd	*pw;
302
303	char *dir = NULL;
304	char *rewrite = NULL;
305
306	char *addr = NULL;
307	char *port = "tftp";
308	int family = AF_UNSPEC;
309	int devnull = -1;
310
311	while ((c = getopt(argc, argv, "46cdil:p:r:v")) != -1) {
312		switch (c) {
313		case '4':
314			family = AF_INET;
315			break;
316		case '6':
317			family = AF_INET6;
318			break;
319		case 'c':
320			cancreate = 1;
321			break;
322		case 'd':
323			verbose = debug = 1;
324			break;
325		case 'i':
326			if (rewrite != NULL)
327				errx(1, "options -i and -r are incompatible");
328			iflag = 1;
329			break;
330		case 'l':
331			addr = optarg;
332			break;
333		case 'p':
334			port = optarg;
335			break;
336		case 'r':
337			if (iflag == 1)
338				errx(1, "options -i and -r are incompatible");
339			rewrite = optarg;
340			break;
341		case 'v':
342			verbose = 1;
343			break;
344		default:
345			usage();
346			/* NOTREACHED */
347		}
348	}
349
350	argc -= optind;
351	argv += optind;
352
353	if (argc != 1)
354		usage();
355
356	dir = argv[0];
357
358	if (geteuid() != 0)
359		errx(1, "need root privileges");
360
361	pw = getpwnam("_tftpd");
362	if (pw == NULL)
363		errx(1, "no _tftpd user");
364
365	if (!debug) {
366		openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
367		tzset();
368		logger = &syslogger;
369		devnull = open(_PATH_DEVNULL, O_RDWR, 0);
370		if (devnull == -1)
371			err(1, "open %s", _PATH_DEVNULL);
372	}
373
374	if (rewrite != NULL)
375		rewrite_connect(rewrite);
376
377	tftpd_listen(addr, port, family);
378
379	if (chroot(dir))
380		err(1, "chroot %s", dir);
381	if (chdir("/"))
382		err(1, "chdir %s", dir);
383
384	/* drop privs */
385	if (setgroups(1, &pw->pw_gid) ||
386	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
387	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
388		errx(1, "can't drop privileges");
389
390	if (!debug && rdaemon(devnull) == -1)
391		err(1, "unable to daemonize");
392
393	if (pledge("stdio rpath wpath cpath fattr dns inet", NULL) == -1)
394		lerr(1, "pledge");
395
396	event_init();
397
398	if (rewrite != NULL)
399		rewrite_events();
400
401	tftpd_events();
402
403	event_dispatch();
404
405	exit(0);
406}
407
408struct rewritemap {
409	struct event wrev;
410	struct event rdev;
411	struct evbuffer *wrbuf;
412	struct evbuffer *rdbuf;
413
414	TAILQ_HEAD(, tftp_client) clients;
415
416	int s;
417};
418
419struct rewritemap *rwmap = NULL;
420
421void
422rewrite_connect(const char *path)
423{
424	int s;
425	struct sockaddr_un remote;
426	size_t len;
427
428	rwmap = malloc(sizeof(*rwmap));
429	if (rwmap == NULL)
430		err(1, "rewrite event malloc");
431
432	rwmap->wrbuf = evbuffer_new();
433	if (rwmap->wrbuf == NULL)
434		err(1, "rewrite wrbuf");
435
436	rwmap->rdbuf = evbuffer_new();
437	if (rwmap->rdbuf == NULL)
438		err(1, "rewrite rdbuf");
439
440	TAILQ_INIT(&rwmap->clients);
441
442	s = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
443	if (s == -1)
444		err(1, "rewrite socket");
445
446	remote.sun_family = AF_UNIX;
447	len = strlcpy(remote.sun_path, path, sizeof(remote.sun_path));
448	if (len >= sizeof(remote.sun_path))
449		errx(1, "rewrite socket path is too long");
450
451	len += sizeof(remote.sun_family) + 1;
452	if (connect(s, (struct sockaddr *)&remote, len) == -1)
453		err(1, "%s", path);
454
455	rwmap->s = s;
456}
457
458void
459rewrite_events(void)
460{
461	event_set(&rwmap->wrev, rwmap->s, EV_WRITE, rewrite_req, NULL);
462	event_set(&rwmap->rdev, rwmap->s, EV_READ | EV_PERSIST, rewrite_res, NULL);
463	event_add(&rwmap->rdev, NULL);
464}
465
466void
467rewrite_map(struct tftp_client *client, const char *filename)
468{
469	char *nicebuf;
470
471	if (stravis(&nicebuf, filename, VIS_SAFE|VIS_OCTAL) == -1)
472		lerr(1, "rwmap stravis");
473
474	if (evbuffer_add_printf(rwmap->wrbuf, "%s %s %s\n", getip(&client->ss),
475	    client->opcode == WRQ ? "write" : "read", nicebuf) == -1)
476		lerr(1, "rwmap printf");
477
478	free(nicebuf);
479
480	TAILQ_INSERT_TAIL(&rwmap->clients, client, entry);
481
482	event_add(&rwmap->wrev, NULL);
483}
484
485void
486rewrite_req(int fd, short events, void *arg)
487{
488	if (evbuffer_write(rwmap->wrbuf, fd) == -1) {
489		switch (errno) {
490		case EINTR:
491		case EAGAIN:
492			event_add(&rwmap->wrev, NULL);
493			return;
494		}
495
496		lerr(1, "rewrite socket write");
497	}
498
499	if (EVBUFFER_LENGTH(rwmap->wrbuf))
500		event_add(&rwmap->wrev, NULL);
501}
502
503void
504rewrite_res(int fd, short events, void *arg)
505{
506	struct tftp_client *client;
507	char *filename;
508	size_t len;
509
510	switch (evbuffer_read(rwmap->rdbuf, fd, PATH_MAX)) {
511	case -1:
512		switch (errno) {
513		case EINTR:
514		case EAGAIN:
515			return;
516		}
517		lerr(1, "rewrite socket read");
518	case 0:
519		lerrx(1, "rewrite socket closed");
520	default:
521		break;
522	}
523
524	while ((filename = evbuffer_readln(rwmap->rdbuf, &len,
525	    EVBUFFER_EOL_LF)) != NULL) {
526		client = TAILQ_FIRST(&rwmap->clients);
527		if (client == NULL)
528			lerrx(1, "unexpected rwmap reply");
529
530		TAILQ_REMOVE(&rwmap->clients, client, entry);
531
532		tftp_open(client, filename);
533
534		free(filename);
535	};
536}
537
538int
539tftpd_listen(const char *addr, const char *port, int family)
540{
541	struct tftp_server *server;
542
543	struct addrinfo hints, *res, *res0;
544	int error;
545	int s;
546
547	int cerrno = EADDRNOTAVAIL;
548	const char *cause = "getaddrinfo";
549
550	int on = 1;
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(&tftp_servers);
558
559	error = getaddrinfo(addr, port, &hints, &res0);
560	if (error) {
561		errx(1, "%s:%s: %s", addr ? addr : "*", port,
562		    gai_strerror(error));
563	}
564
565	for (res = res0; res != NULL; res = res->ai_next) {
566		s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK,
567		    res->ai_protocol);
568		if (s == -1) {
569			cause = "socket";
570			cerrno = errno;
571			continue;
572		}
573
574		if (bind(s, res->ai_addr, res->ai_addrlen) == -1) {
575			cause = "bind";
576			cerrno = errno;
577			close(s);
578			continue;
579		}
580
581		switch (res->ai_family) {
582		case AF_INET:
583			if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR,
584			    &on, sizeof(on)) == -1)
585				err(1, "setsockopt(IP_RECVDSTADDR)");
586			break;
587		case AF_INET6:
588			if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
589			    &on, sizeof(on)) == -1)
590				err(1, "setsockopt(IPV6_RECVPKTINFO)");
591			break;
592		}
593
594		server = malloc(sizeof(*server));
595		if (server == NULL)
596			err(1, "malloc");
597
598		server->s = s;
599		TAILQ_INSERT_TAIL(&tftp_servers, server, entry);
600	}
601
602	if (TAILQ_EMPTY(&tftp_servers))
603		errc(1, cerrno, "%s", cause);
604
605	freeaddrinfo(res0);
606	return (0);
607}
608
609void
610tftpd_events(void)
611{
612	struct tftp_server *server;
613	TAILQ_FOREACH(server, &tftp_servers, entry) {
614		event_set(&server->ev, server->s, EV_READ | EV_PERSIST,
615		    tftpd_recv, server);
616		event_add(&server->ev, NULL);
617	}
618}
619
620struct tftp_client *
621client_alloc(void)
622{
623	struct tftp_client *client;
624
625	client = calloc(1, sizeof(*client));
626	if (client == NULL)
627		return (NULL);
628
629	client->segment_size = SEGSIZE;
630	client->packet_size = SEGSIZE + 4;
631
632	client->tv.tv_sec = TIMEOUT;
633	client->tv.tv_usec = 0;
634
635	client->sock = -1;
636	client->file = NULL;
637	client->newline = 0;
638
639	return (client);
640}
641
642void
643client_free(struct tftp_client *client)
644{
645	free(client->options);
646
647	if (client->file != NULL)
648		fclose(client->file);
649
650	close(client->sock);
651
652	free(client);
653}
654
655void
656tftpd_recv(int fd, short events, void *arg)
657{
658	union {
659		struct cmsghdr hdr;
660		char	buf[CMSG_SPACE(sizeof(struct sockaddr_storage))];
661	} cmsgbuf;
662	struct cmsghdr *cmsg;
663	struct msghdr msg;
664	struct iovec iov;
665
666	ssize_t n;
667	struct sockaddr_storage s_in;
668	int dobind = 1;
669	int on = 1;
670
671	struct tftphdr *tp;
672
673	struct tftp_client *client;
674
675	client = client_alloc();
676	if (client == NULL) {
677		char buf[SEGSIZE_MAX + 4];
678		/* no memory! flush this request... */
679		recv(fd, buf, SEGSIZE_MAX + 4, 0);
680		/* dont care if it fails */
681		return;
682	}
683
684	bzero(&msg, sizeof(msg));
685	iov.iov_base = client->buf;
686	iov.iov_len = client->packet_size;
687	msg.msg_name = &client->ss;
688	msg.msg_namelen = sizeof(client->ss);
689	msg.msg_iov = &iov;
690	msg.msg_iovlen = 1;
691	msg.msg_control = &cmsgbuf.buf;
692	msg.msg_controllen = sizeof(cmsgbuf.buf);
693
694	n = recvmsg(fd, &msg, 0);
695	if (n == -1) {
696		lwarn("recvmsg");
697		goto err;
698	}
699	if (n < 4)
700		goto err;
701
702	client->sock = socket(client->ss.ss_family,
703	    SOCK_DGRAM | SOCK_NONBLOCK, 0);
704	if (client->sock == -1) {
705		lwarn("socket");
706		goto err;
707	}
708	memset(&s_in, 0, sizeof(s_in));
709	s_in.ss_family = client->ss.ss_family;
710	s_in.ss_len = client->ss.ss_len;
711
712	/* get local address if possible */
713	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
714	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
715		if (cmsg->cmsg_level == IPPROTO_IP &&
716		    cmsg->cmsg_type == IP_RECVDSTADDR) {
717			memcpy(&((struct sockaddr_in *)&s_in)->sin_addr,
718			    CMSG_DATA(cmsg), sizeof(struct in_addr));
719			if (((struct sockaddr_in *)&s_in)->sin_addr.s_addr ==
720			    INADDR_BROADCAST)
721				dobind = 0;
722			break;
723		}
724		if (cmsg->cmsg_level == IPPROTO_IPV6 &&
725		    cmsg->cmsg_type == IPV6_PKTINFO) {
726			struct in6_pktinfo *ipi;
727
728			ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg);
729			memcpy(&((struct sockaddr_in6 *)&s_in)->sin6_addr,
730			    &ipi->ipi6_addr, sizeof(struct in6_addr));
731#ifdef __KAME__
732			if (IN6_IS_ADDR_LINKLOCAL(&ipi->ipi6_addr))
733				((struct sockaddr_in6 *)&s_in)->sin6_scope_id =
734				    ipi->ipi6_ifindex;
735#endif
736			break;
737		}
738	}
739
740	if (dobind) {
741		setsockopt(client->sock, SOL_SOCKET, SO_REUSEADDR,
742		    &on, sizeof(on));
743		setsockopt(client->sock, SOL_SOCKET, SO_REUSEPORT,
744		    &on, sizeof(on));
745
746		if (bind(client->sock, (struct sockaddr *)&s_in,
747		    s_in.ss_len) == -1) {
748			lwarn("bind to %s", getip(&s_in));
749			goto err;
750		}
751	}
752	if (connect(client->sock, (struct sockaddr *)&client->ss,
753	    client->ss.ss_len) == -1) {
754		lwarn("connect to %s", getip(&client->ss));
755		goto err;
756	}
757
758	tp = (struct tftphdr *)client->buf;
759	client->opcode = ntohs(tp->th_opcode);
760	if (client->opcode != RRQ && client->opcode != WRQ) {
761		/* bad request */
762		goto err;
763	}
764
765	tftp(client, tp, n);
766
767	return;
768
769err:
770	client_free(client);
771}
772
773int
774parse_options(struct tftp_client *client, char *cp, size_t size,
775    struct opt_client *options)
776{
777	char *option;
778	char *ccp;
779	int has_options = 0;
780	int i;
781
782	while (++cp < client->buf + size) {
783		for (i = 2, ccp = cp; i > 0; ccp++) {
784			if (ccp >= client->buf + size) {
785				/*
786				 * Don't reject the request, just stop trying
787				 * to parse the option and get on with it.
788				 * Some Apple OpenFirmware versions have
789				 * trailing garbage on the end of otherwise
790				 * valid requests.
791				 */
792				return (has_options);
793			} else if (*ccp == '\0')
794				i--;
795		}
796
797		for (option = cp; *cp; cp++)
798			*cp = tolower((unsigned char)*cp);
799
800		for (i = 0; i < NOPT; i++) {
801			if (strcmp(option, opt_names[i]) == 0) {
802				options[i].o_request = ++cp;
803				has_options = 1;
804			}
805		}
806		cp = ccp - 1;
807	}
808
809	return (has_options);
810}
811
812/*
813 * Handle initial connection protocol.
814 */
815void
816tftp(struct tftp_client *client, struct tftphdr *tp, size_t size)
817{
818	struct opt_client *options;
819
820	char		*cp;
821	int		 i, first = 1, ecode, to;
822	struct formats	*pf;
823	char		*mode = NULL;
824	char		 filename[PATH_MAX];
825	const char	*errstr;
826
827	if (size < 5) {
828		ecode = EBADOP;
829		goto error;
830	}
831
832	cp = tp->th_stuff;
833again:
834	while (cp < client->buf + size) {
835		if (*cp == '\0')
836			break;
837		cp++;
838	}
839	if (*cp != '\0') {
840		ecode = EBADOP;
841		goto error;
842	}
843	i = cp - tp->th_stuff;
844	if (i >= sizeof(filename)) {
845		ecode = EBADOP;
846		goto error;
847	}
848	memcpy(filename, tp->th_stuff, i);
849	filename[i] = '\0';
850	if (first) {
851		mode = ++cp;
852		first = 0;
853		goto again;
854	}
855	for (cp = mode; *cp; cp++)
856		*cp = tolower((unsigned char)*cp);
857
858	for (pf = formats; pf->f_mode; pf++) {
859		if (strcmp(pf->f_mode, mode) == 0)
860			break;
861	}
862	if (pf->f_mode == 0) {
863		ecode = EBADOP;
864		goto error;
865	}
866	client->fgetc = pf->f_getc;
867	client->fputc = pf->f_putc;
868
869	client->options = options = calloc(NOPT, sizeof(*client->options));
870	if (options == NULL) {
871		ecode = 100 + ENOMEM;
872		goto error;
873	}
874
875	if (parse_options(client, cp, size, options)) {
876		if (options[OPT_TIMEOUT].o_request != NULL) {
877			to = strtonum(options[OPT_TIMEOUT].o_request,
878			    TIMEOUT_MIN, TIMEOUT_MAX, &errstr);
879			if (errstr) {
880				ecode = EBADOP;
881				goto error;
882			}
883			options[OPT_TIMEOUT].o_reply = client->tv.tv_sec = to;
884		}
885
886		if (options[OPT_BLKSIZE].o_request) {
887			client->segment_size = strtonum(
888			    options[OPT_BLKSIZE].o_request,
889			    SEGSIZE_MIN, SEGSIZE_MAX, &errstr);
890			if (errstr) {
891				ecode = EBADOP;
892				goto error;
893			}
894			client->packet_size = client->segment_size + 4;
895			options[OPT_BLKSIZE].o_reply = client->segment_size;
896		}
897	} else {
898		free(options);
899		client->options = NULL;
900	}
901
902	if (verbose) {
903		char nicebuf[PATH_MAX];
904
905		(void)strnvis(nicebuf, filename, PATH_MAX,
906		    VIS_SAFE|VIS_OCTAL);
907
908		linfo("%s: %s request for '%s'", getip(&client->ss),
909		    client->opcode == WRQ ? "write" : "read", nicebuf);
910	}
911
912	if (rwmap != NULL)
913		rewrite_map(client, filename);
914	else
915		tftp_open(client, filename);
916
917	return;
918
919error:
920	nak(client, ecode);
921}
922
923void
924tftp_open(struct tftp_client *client, const char *filename)
925{
926	int ecode;
927
928	ecode = validate_access(client, filename);
929	if (ecode)
930		goto error;
931
932	if (client->options) {
933		if (oack(client) == -1)
934			goto error;
935
936		free(client->options);
937		client->options = NULL;
938	} else if (client->opcode == WRQ) {
939		recvfile(client);
940	} else
941		sendfile(client);
942
943	return;
944error:
945	nak(client, ecode);
946}
947
948/*
949 * Validate file access.  Since we
950 * have no uid or gid, for now require
951 * file to exist and be publicly
952 * readable/writable.
953 * If we were invoked with arguments
954 * from inetd then the file must also be
955 * in one of the given directory prefixes.
956 * Note also, full path name must be
957 * given as we have no login directory.
958 */
959int
960validate_access(struct tftp_client *client, const char *requested)
961{
962	int		 mode = client->opcode;
963	struct opt_client *options = client->options;
964	struct stat	 stbuf;
965	int		 fd, wmode;
966	const char	*errstr, *filename;
967	char		 rewritten[PATH_MAX];
968
969	if (strcmp(requested, SEEDPATH) == 0) {
970		char *buf;
971		if (mode != RRQ)
972			return (EACCESS);
973
974		buf = client->buf + sizeof(client->buf) - 512;
975		arc4random_buf(buf, 512);
976		if (options != NULL && options[OPT_TSIZE].o_request)
977			options[OPT_TSIZE].o_reply = 512;
978		client->file = fmemopen(buf, 512, "r");
979		if (client->file == NULL)
980			return (errno + 100);
981
982		return (0);
983	}
984
985	if (iflag) {
986		int ret;
987
988		/*
989		 * In -i mode, look in the directory named after the
990		 * client address.
991		 */
992		ret = snprintf(rewritten, sizeof(rewritten), "%s/%s",
993		    getip(&client->ss), requested);
994		if (ret < 0 || ret >= sizeof(rewritten))
995			return (ENAMETOOLONG + 100);
996		filename = rewritten;
997	} else {
998retryread:
999		filename = requested;
1000	}
1001
1002	/*
1003	 * We use a different permissions scheme if `cancreate' is
1004	 * set.
1005	 */
1006	wmode = O_TRUNC;
1007	if (stat(filename, &stbuf) == -1) {
1008		if (!cancreate) {
1009			/*
1010			 * In -i mode, retry failed read requests from
1011			 * the root directory.
1012			 */
1013			if (mode == RRQ && errno == ENOENT &&
1014			    filename == rewritten)
1015				goto retryread;
1016			return (errno == ENOENT ? ENOTFOUND : EACCESS);
1017		} else {
1018			if ((errno == ENOENT) && (mode != RRQ))
1019				wmode |= O_CREAT;
1020			else
1021				return (EACCESS);
1022		}
1023	} else {
1024		if (mode == RRQ) {
1025			if ((stbuf.st_mode & (S_IRUSR >> 6)) == 0)
1026				return (EACCESS);
1027		} else {
1028			if ((stbuf.st_mode & (S_IWUSR >> 6)) == 0)
1029				return (EACCESS);
1030		}
1031	}
1032
1033	if (options != NULL && options[OPT_TSIZE].o_request) {
1034		if (mode == RRQ)
1035			options[OPT_TSIZE].o_reply = stbuf.st_size;
1036		else {
1037			/* allows writes of 65535 blocks * SEGSIZE_MAX bytes */
1038			options[OPT_TSIZE].o_reply =
1039			    strtonum(options[OPT_TSIZE].o_request,
1040			    1, 65535LL * SEGSIZE_MAX, &errstr);
1041			if (errstr)
1042				return (EOPTNEG);
1043		}
1044	}
1045	fd = open(filename, mode == RRQ ? O_RDONLY : (O_WRONLY|wmode), 0666);
1046	if (fd == -1)
1047		return (errno + 100);
1048	/*
1049	 * If the file was created, set default permissions.
1050	 */
1051	if ((wmode & O_CREAT) && fchmod(fd, 0666) == -1) {
1052		int serrno = errno;
1053
1054		close(fd);
1055		unlink(filename);
1056
1057		return (serrno + 100);
1058	}
1059	client->file = fdopen(fd, mode == RRQ ? "r" : "w");
1060	if (client->file == NULL) {
1061		close(fd);
1062		return (errno + 100);
1063	}
1064
1065	return (0);
1066}
1067
1068int
1069fget_octet(struct tftp_client *client)
1070{
1071	return (getc(client->file));
1072}
1073
1074int
1075fput_octet(struct tftp_client *client, int c)
1076{
1077	return (putc(c, client->file));
1078}
1079
1080int
1081fget_netascii(struct tftp_client *client)
1082{
1083	int c = -1;
1084
1085	switch (client->newline) {
1086	case 0:
1087		c = getc(client->file);
1088		if (c == EOF)
1089			break;
1090
1091		if (c == '\n' || c == '\r') {
1092			client->newline = c;
1093			c = '\r';
1094		}
1095		break;
1096	case '\n':
1097		client->newline = 0;
1098		c = '\n';
1099		break;
1100	case '\r':
1101		client->newline = 0;
1102		c = '\0';
1103		break;
1104	}
1105
1106	return (c);
1107}
1108
1109int
1110fput_netascii(struct tftp_client *client, int c)
1111{
1112	if (client->newline == '\r') {
1113		client->newline = 0;
1114
1115		if (c == '\0')
1116			c = '\r';
1117
1118	} else if (c == '\r') {
1119		client->newline = c;
1120		return (c);
1121	}
1122
1123	return (putc(c, client->file));
1124}
1125
1126void
1127sendfile(struct tftp_client *client)
1128{
1129	event_set(&client->sev, client->sock, EV_READ, tftp_rrq_ack, client);
1130	client->block = 1;
1131
1132	file_read(client);
1133}
1134
1135void
1136file_read(struct tftp_client *client)
1137{
1138	u_int8_t *buf;
1139	struct tftphdr *dp;
1140	int i;
1141	int c;
1142
1143	dp = (struct tftphdr *)client->buf;
1144	dp->th_opcode = htons((u_short)DATA);
1145	dp->th_block = htons(client->block);
1146	buf = (u_int8_t *)dp->th_data;
1147
1148	for (i = 0; i < client->segment_size; i++) {
1149		c = client->fgetc(client);
1150		if (c == EOF) {
1151			if (ferror(client->file)) {
1152				nak(client, 100 + EIO);
1153				return;
1154			}
1155
1156			break;
1157		}
1158		buf[i] = c;
1159	}
1160
1161	client->buflen = i + 4;
1162	client->retries = RETRIES;
1163
1164	if (send(client->sock, client->buf, client->buflen, 0) == -1) {
1165		lwarn("send(block)");
1166		client_free(client);
1167		return;
1168	}
1169
1170	event_add(&client->sev, &client->tv);
1171}
1172
1173void
1174tftp_rrq_ack(int fd, short events, void *arg)
1175{
1176	struct tftp_client *client = arg;
1177	struct tftphdr *ap; /* ack packet */
1178	char rbuf[SEGSIZE_MIN];
1179	ssize_t n;
1180
1181	if (events & EV_TIMEOUT) {
1182		if (retry(client) == -1) {
1183			lwarn("%s: retry", getip(&client->ss));
1184			goto done;
1185		}
1186
1187		return;
1188	}
1189
1190	n = recv(fd, rbuf, sizeof(rbuf), 0);
1191	if (n == -1) {
1192		switch (errno) {
1193		case EINTR:
1194		case EAGAIN:
1195			event_add(&client->sev, &client->tv);
1196			return;
1197
1198		default:
1199			lwarn("%s: recv", getip(&client->ss));
1200			goto done;
1201		}
1202	}
1203
1204	ap = (struct tftphdr *)rbuf;
1205	ap->th_opcode = ntohs((u_short)ap->th_opcode);
1206	ap->th_block = ntohs((u_short)ap->th_block);
1207
1208	switch (ap->th_opcode) {
1209	case ERROR:
1210		goto done;
1211	case ACK:
1212		break;
1213	default:
1214		goto retry;
1215	}
1216
1217	if (ap->th_block != client->block) {
1218		if (tftp_flush(client) == -1) {
1219			lwarnx("%s: flush", getip(&client->ss));
1220			goto done;
1221		}
1222
1223		if (ap->th_block != (client->block - 1))
1224			goto done;
1225
1226		goto retry;
1227	}
1228
1229	if (client->buflen != client->packet_size) {
1230		/* this was the last packet in the stream */
1231		goto done;
1232	}
1233
1234	client->block++;
1235	file_read(client);
1236	return;
1237
1238retry:
1239	event_add(&client->sev, &client->tv);
1240	return;
1241
1242done:
1243	client_free(client);
1244}
1245
1246int
1247tftp_flush(struct tftp_client *client)
1248{
1249	char rbuf[SEGSIZE_MIN];
1250	ssize_t n;
1251
1252	for (;;) {
1253		n = recv(client->sock, rbuf, sizeof(rbuf), 0);
1254		if (n == -1) {
1255			switch (errno) {
1256			case EAGAIN:
1257				return (0);
1258
1259			case EINTR:
1260				break;
1261
1262			default:
1263				return (-1);
1264			}
1265		}
1266	}
1267}
1268
1269void
1270recvfile(struct tftp_client *client)
1271{
1272	event_set(&client->sev, client->sock, EV_READ, tftp_wrq, client);
1273	tftp_wrq_ack(client);
1274}
1275
1276int
1277tftp_wrq_ack_packet(struct tftp_client *client)
1278{
1279	struct tftphdr *ap; /* ack packet */
1280
1281	ap = (struct tftphdr *)client->buf;
1282	ap->th_opcode = htons((u_short)ACK);
1283	ap->th_block = htons(client->block);
1284
1285	client->buflen = 4;
1286	client->retries = RETRIES;
1287
1288	return (send(client->sock, client->buf, client->buflen, 0) != 4);
1289}
1290
1291void
1292tftp_wrq_ack(struct tftp_client *client)
1293{
1294	if (tftp_wrq_ack_packet(client) != 0) {
1295		lwarn("tftp wrq ack");
1296		client_free(client);
1297		return;
1298	}
1299
1300	client->block++;
1301	event_add(&client->sev, &client->tv);
1302}
1303
1304void
1305tftp_wrq(int fd, short events, void *arg)
1306{
1307	char wbuf[SEGSIZE_MAX + 4];
1308	struct tftp_client *client = arg;
1309	struct tftphdr *dp;
1310	ssize_t n;
1311	int i;
1312
1313	if (events & EV_TIMEOUT) {
1314		if (retry(client) == -1) {
1315			lwarn("%s", getip(&client->ss));
1316			goto done;
1317		}
1318
1319		return;
1320	}
1321
1322	n = recv(fd, wbuf, client->packet_size, 0);
1323	if (n == -1) {
1324		switch (errno) {
1325		case EINTR:
1326		case EAGAIN:
1327			goto retry;
1328
1329		default:
1330			lwarn("tftp_wrq recv");
1331			goto done;
1332		}
1333	}
1334
1335	if (n < 4)
1336		goto done;
1337
1338	dp = (struct tftphdr *)wbuf;
1339	dp->th_opcode = ntohs((u_short)dp->th_opcode);
1340	dp->th_block = ntohs((u_short)dp->th_block);
1341
1342	switch (dp->th_opcode) {
1343	case ERROR:
1344		goto done;
1345	case DATA:
1346		break;
1347	default:
1348		goto retry;
1349	}
1350
1351	if (dp->th_block != client->block) {
1352		if (tftp_flush(client) == -1) {
1353			lwarnx("%s: flush", getip(&client->ss));
1354			goto done;
1355		}
1356
1357		if (dp->th_block != (client->block - 1))
1358			goto done;
1359
1360		goto retry;
1361	}
1362
1363	for (i = 4; i < n; i++) {
1364		if (client->fputc(client, wbuf[i]) == EOF) {
1365			lwarn("tftp wrq");
1366			goto done;
1367		}
1368	}
1369
1370	if (n < client->packet_size) {
1371		tftp_wrq_ack_packet(client);
1372		fclose(client->file);
1373		client->file = NULL;
1374		event_set(&client->sev, client->sock, EV_READ,
1375		    tftp_wrq_end, client);
1376		event_add(&client->sev, &client->tv);
1377		return;
1378	}
1379
1380	tftp_wrq_ack(client);
1381	return;
1382
1383retry:
1384	event_add(&client->sev, &client->tv);
1385	return;
1386done:
1387	client_free(client);
1388}
1389
1390void
1391tftp_wrq_end(int fd, short events, void *arg)
1392{
1393	char wbuf[SEGSIZE_MAX + 4];
1394	struct tftp_client *client = arg;
1395	struct tftphdr *dp;
1396	ssize_t n;
1397
1398	if (events & EV_TIMEOUT) {
1399		/* this was the last packet, we can clean up */
1400		goto done;
1401	}
1402
1403	n = recv(fd, wbuf, client->packet_size, 0);
1404	if (n == -1) {
1405		switch (errno) {
1406		case EINTR:
1407		case EAGAIN:
1408			goto retry;
1409
1410		default:
1411			lwarn("tftp_wrq_end recv");
1412			goto done;
1413		}
1414	}
1415
1416	if (n < 4)
1417		goto done;
1418
1419	dp = (struct tftphdr *)wbuf;
1420	dp->th_opcode = ntohs((u_short)dp->th_opcode);
1421	dp->th_block = ntohs((u_short)dp->th_block);
1422
1423	switch (dp->th_opcode) {
1424	case ERROR:
1425		goto done;
1426	case DATA:
1427		break;
1428	default:
1429		goto retry;
1430	}
1431
1432	if (dp->th_block != client->block)
1433		goto done;
1434
1435retry:
1436	if (retry(client) == -1) {
1437		lwarn("%s", getip(&client->ss));
1438		goto done;
1439	}
1440	return;
1441done:
1442	client_free(client);
1443	return;
1444}
1445
1446
1447/*
1448 * Send a nak packet (error message).
1449 * Error code passed in is one of the
1450 * standard TFTP codes, or a UNIX errno
1451 * offset by 100.
1452 */
1453void
1454nak(struct tftp_client *client, int error)
1455{
1456	struct tftphdr	*tp;
1457	struct errmsg	*pe;
1458	size_t		 length;
1459
1460	tp = (struct tftphdr *)client->buf;
1461	tp->th_opcode = htons((u_short)ERROR);
1462	tp->th_code = htons((u_short)error);
1463
1464	for (pe = errmsgs; pe->e_code >= 0; pe++) {
1465		if (pe->e_code == error)
1466			break;
1467	}
1468	if (pe->e_code < 0) {
1469		pe->e_msg = strerror(error - 100);
1470		tp->th_code = htons(EUNDEF);   /* set 'undef' errorcode */
1471	}
1472
1473	length = strlcpy(tp->th_msg, pe->e_msg, client->packet_size - 5) + 5;
1474	if (length > client->packet_size)
1475		length = client->packet_size;
1476
1477	if (send(client->sock, client->buf, length, 0) != length)
1478		lwarn("nak");
1479
1480	client_free(client);
1481}
1482
1483/*
1484 * Send an oack packet (option acknowledgement).
1485 */
1486int
1487oack(struct tftp_client *client)
1488{
1489	struct opt_client *options = client->options;
1490	struct tftphdr *tp;
1491	char *bp;
1492	int i, n, size;
1493
1494	tp = (struct tftphdr *)client->buf;
1495	bp = (char *)tp->th_stuff;
1496	size = sizeof(client->buf) - 2;
1497
1498	tp->th_opcode = htons((u_short)OACK);
1499	for (i = 0; i < NOPT; i++) {
1500		if (options[i].o_request == NULL)
1501			continue;
1502
1503		n = snprintf(bp, size, "%s%c%lld", opt_names[i], '\0',
1504		    options[i].o_reply);
1505		if (n < 0 || n >= size) {
1506			lwarnx("oack: no buffer space");
1507			goto error;
1508		}
1509
1510		bp += n + 1;
1511		size -= n + 1;
1512		if (size < 0) {
1513			lwarnx("oack: no buffer space");
1514			goto error;
1515		}
1516	}
1517
1518	client->buflen = bp - client->buf;
1519	client->retries = RETRIES;
1520
1521	if (send(client->sock, client->buf, client->buflen, 0) == -1) {
1522		lwarn("oack");
1523		goto error;
1524	}
1525
1526	/* no client ACK for write requests with options */
1527	if (client->opcode == WRQ) {
1528		client->block = 1;
1529		event_set(&client->sev, client->sock, EV_READ,
1530		    tftp_wrq, client);
1531	} else
1532		event_set(&client->sev, client->sock, EV_READ,
1533		    oack_done, client);
1534
1535	event_add(&client->sev, &client->tv);
1536	return (0);
1537
1538error:
1539	return (-1);
1540}
1541
1542int
1543retry(struct tftp_client *client)
1544{
1545	if (--client->retries == 0) {
1546		errno = ETIMEDOUT;
1547		return (-1);
1548	}
1549
1550	if (send(client->sock, client->buf, client->buflen, 0) == -1)
1551		return (-1);
1552
1553	event_add(&client->sev, &client->tv);
1554
1555	return (0);
1556}
1557
1558void
1559oack_done(int fd, short events, void *arg)
1560{
1561	struct tftp_client *client = arg;
1562	struct tftphdr *ap;
1563	ssize_t n;
1564
1565	if (events & EV_TIMEOUT) {
1566		if (retry(client) == -1) {
1567			lwarn("%s", getip(&client->ss));
1568			goto done;
1569		}
1570
1571		return;
1572	}
1573
1574	n = recv(client->sock, client->buf, client->packet_size, 0);
1575	if (n == -1) {
1576		switch (errno) {
1577		case EINTR:
1578		case EAGAIN:
1579			event_add(&client->sev, &client->tv);
1580			return;
1581
1582		default:
1583			lwarn("%s: recv", getip(&client->ss));
1584			goto done;
1585		}
1586	}
1587
1588	if (n < 4)
1589		goto done;
1590
1591	ap = (struct tftphdr *)client->buf;
1592	ap->th_opcode = ntohs((u_short)ap->th_opcode);
1593	ap->th_block = ntohs((u_short)ap->th_block);
1594
1595	if (ap->th_opcode != ACK || ap->th_block != 0)
1596		goto done;
1597
1598	sendfile(client);
1599	return;
1600
1601done:
1602	client_free(client);
1603}
1604
1605const char *
1606getip(void *s)
1607{
1608	struct sockaddr *sa = s;
1609	static char hbuf[NI_MAXHOST];
1610
1611	if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf),
1612	    NULL, 0, NI_NUMERICHOST))
1613		strlcpy(hbuf, "0.0.0.0", sizeof(hbuf));
1614
1615	return(hbuf);
1616}
1617
1618/* daemon(3) clone, intended to be used in a "r"estricted environment */
1619int
1620rdaemon(int devnull)
1621{
1622	if (devnull == -1) {
1623		errno = EBADF;
1624		return (-1);
1625	}
1626	if (fcntl(devnull, F_GETFL) == -1)
1627		return (-1);
1628
1629	switch (fork()) {
1630	case -1:
1631		return (-1);
1632	case 0:
1633		break;
1634	default:
1635		_exit(0);
1636	}
1637
1638	if (setsid() == -1)
1639		return (-1);
1640
1641	(void)dup2(devnull, STDIN_FILENO);
1642	(void)dup2(devnull, STDOUT_FILENO);
1643	(void)dup2(devnull, STDERR_FILENO);
1644	if (devnull > 2)
1645		(void)close(devnull);
1646
1647	return (0);
1648}
1649
1650void
1651syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
1652{
1653	char *s;
1654
1655	if (vasprintf(&s, fmt, ap) == -1) {
1656		syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror");
1657		exit(1);
1658	}
1659
1660	syslog(priority, "%s: %s", s, strerror(e));
1661
1662	free(s);
1663}
1664
1665void
1666syslog_err(int ecode, const char *fmt, ...)
1667{
1668	va_list ap;
1669
1670	va_start(ap, fmt);
1671	syslog_vstrerror(errno, LOG_CRIT, fmt, ap);
1672	va_end(ap);
1673
1674	exit(ecode);
1675}
1676
1677void
1678syslog_errx(int ecode, const char *fmt, ...)
1679{
1680	va_list ap;
1681
1682	va_start(ap, fmt);
1683	vsyslog(LOG_CRIT, fmt, ap);
1684	va_end(ap);
1685
1686	exit(ecode);
1687}
1688
1689void
1690syslog_warn(const char *fmt, ...)
1691{
1692	va_list ap;
1693
1694	va_start(ap, fmt);
1695	syslog_vstrerror(errno, LOG_ERR, fmt, ap);
1696	va_end(ap);
1697}
1698
1699void
1700syslog_warnx(const char *fmt, ...)
1701{
1702	va_list ap;
1703
1704	va_start(ap, fmt);
1705	vsyslog(LOG_ERR, fmt, ap);
1706	va_end(ap);
1707}
1708
1709void
1710syslog_info(const char *fmt, ...)
1711{
1712	va_list ap;
1713
1714	va_start(ap, fmt);
1715	vsyslog(LOG_INFO, fmt, ap);
1716	va_end(ap);
1717}
1718
1719void
1720syslog_debug(const char *fmt, ...)
1721{
1722	va_list ap;
1723
1724	if (!debug)
1725		return;
1726
1727	va_start(ap, fmt);
1728	vsyslog(LOG_DEBUG, fmt, ap);
1729	va_end(ap);
1730}
1731