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