xref: /openbsd-src/usr.sbin/identd/identd.c (revision e5157e49389faebcb42b7237d55fbf096d9c2523)
1 /*	$OpenBSD: identd.c,v 1.26 2014/07/13 17:53:41 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2013 David Gwynne <dlg@openbsd.org>
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 #include <sys/types.h>
20 #include <sys/ioctl.h>
21 #include <sys/socket.h>
22 #include <sys/socketvar.h>
23 #include <sys/stat.h>
24 #include <sys/sysctl.h>
25 #include <sys/uio.h>
26 
27 #include <netinet/in.h>
28 #include <netinet/tcp.h>
29 #include <netinet/tcp_timer.h>
30 #include <netinet/tcp_var.h>
31 
32 #include <netdb.h>
33 
34 #include <err.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <event.h>
38 #include <fcntl.h>
39 #include <pwd.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <syslog.h>
44 #include <unistd.h>
45 
46 #define IDENTD_USER "_identd"
47 
48 #define DOTNOIDENT ".noident"
49 
50 #define TIMEOUT_MIN 4
51 #define TIMEOUT_MAX 240
52 #define TIMEOUT_DEFAULT 120
53 #define INPUT_MAX 256
54 
55 enum ident_client_state {
56 	S_BEGINNING = 0,
57 	S_SERVER_PORT,
58 	S_PRE_COMMA,
59 	S_POST_COMMA,
60 	S_CLIENT_PORT,
61 	S_PRE_EOL,
62 	S_EOL,
63 
64 	S_DEAD,
65 	S_QUEUED
66 };
67 
68 #define E_NONE		0
69 #define E_NOUSER	1
70 #define E_UNKNOWN	2
71 #define E_HIDDEN	3
72 
73 struct ident_client {
74 	struct {
75 		/* from the socket */
76 		struct sockaddr_storage ss;
77 		socklen_t len;
78 
79 		/* from the request */
80 		u_int port;
81 	} client, server;
82 	SIMPLEQ_ENTRY(ident_client) entry;
83 	enum ident_client_state state;
84 	struct event ev;
85 	struct event tmo;
86 	size_t rxbytes;
87 
88 	char *buf;
89 	size_t buflen;
90 	size_t bufoff;
91 	uid_t uid;
92 };
93 
94 struct ident_resolver {
95 	SIMPLEQ_ENTRY(ident_resolver) entry;
96 	char *buf;
97 	size_t buflen;
98 	u_int error;
99 };
100 
101 struct identd_listener {
102 	struct event ev, pause;
103 };
104 
105 void	parent_rd(int, short, void *);
106 void	parent_wr(int, short, void *);
107 int	parent_username(struct ident_resolver *, struct passwd *);
108 int	parent_uid(struct ident_resolver *, struct passwd *);
109 int	parent_token(struct ident_resolver *, struct passwd *);
110 void	parent_noident(struct ident_resolver *, struct passwd *);
111 
112 void	child_rd(int, short, void *);
113 void	child_wr(int, short, void *);
114 
115 void	identd_listen(const char *, const char *, int);
116 void	identd_paused(int, short, void *);
117 void	identd_accept(int, short, void *);
118 int	identd_error(struct ident_client *, const char *);
119 void	identd_close(struct ident_client *);
120 void	identd_timeout(int, short, void *);
121 void	identd_request(int, short, void *);
122 enum ident_client_state
123 	identd_parse(struct ident_client *, int);
124 void	identd_resolving(int, short, void *);
125 void	identd_response(int, short, void *);
126 int	fetchuid(struct ident_client *);
127 
128 const char *gethost(struct sockaddr_storage *);
129 const char *getport(struct sockaddr_storage *);
130 const char *gentoken(void);
131 
132 struct loggers {
133 	void (*err)(int, const char *, ...);
134 	void (*errx)(int, const char *, ...);
135 	void (*warn)(const char *, ...);
136 	void (*warnx)(const char *, ...);
137 	void (*notice)(const char *, ...);
138 	void (*debug)(const char *, ...);
139 };
140 
141 const struct loggers conslogger = {
142 	err,
143 	errx,
144 	warn,
145 	warnx,
146 	warnx, /* notice */
147 	warnx /* debug */
148 };
149 
150 void	syslog_err(int, const char *, ...);
151 void	syslog_errx(int, const char *, ...);
152 void	syslog_warn(const char *, ...);
153 void	syslog_warnx(const char *, ...);
154 void	syslog_notice(const char *, ...);
155 void	syslog_debug(const char *, ...);
156 void	syslog_vstrerror(int, int, const char *, va_list);
157 
158 const struct loggers syslogger = {
159 	syslog_err,
160 	syslog_errx,
161 	syslog_warn,
162 	syslog_warnx,
163 	syslog_notice,
164 	syslog_debug
165 };
166 
167 const struct loggers *logger = &conslogger;
168 
169 #define lerr(_e, _f...) logger->err((_e), _f)
170 #define lerrx(_e, _f...) logger->errx((_e), _f)
171 #define lwarn(_f...) logger->warn(_f)
172 #define lwarnx(_f...) logger->warnx(_f)
173 #define lnotice(_f...) logger->notice(_f)
174 #define ldebug(_f...) logger->debug(_f)
175 
176 #define sa(_ss) ((struct sockaddr *)(_ss))
177 
178 static __dead void
179 usage(void)
180 {
181 	extern char *__progname;
182 	fprintf(stderr, "usage: %s [-46deHhNn] [-l address] [-t timeout]\n",
183 	    __progname);
184 	exit(1);
185 }
186 
187 struct timeval timeout = { TIMEOUT_DEFAULT, 0 };
188 int debug = 0;
189 int noident = 0;
190 int on = 1;
191 int unknown_err = 0;
192 int hideall = 0;
193 
194 int (*parent_uprintf)(struct ident_resolver *, struct passwd *) =
195     parent_username;
196 
197 struct event proc_rd, proc_wr;
198 union {
199 	struct {
200 		SIMPLEQ_HEAD(, ident_resolver) replies;
201 	} parent;
202 	struct {
203 		SIMPLEQ_HEAD(, ident_client) pushing, popping;
204 	} child;
205 } sc;
206 
207 int
208 main(int argc, char *argv[])
209 {
210 	extern char *__progname;
211 	const char *errstr = NULL;
212 
213 	int		 c;
214 	struct passwd	*pw;
215 
216 	char *addr = NULL;
217 	int family = AF_UNSPEC;
218 
219 	int pair[2];
220 	pid_t parent;
221 	int sibling;
222 
223 	while ((c = getopt(argc, argv, "46deHhl:Nnt:")) != -1) {
224 		switch (c) {
225 		case '4':
226 			family = AF_INET;
227 			break;
228 		case '6':
229 			family = AF_INET6;
230 			break;
231 		case 'd':
232 			debug = 1;
233 			break;
234 		case 'e':
235 			unknown_err = 1;
236 			break;
237 		case 'H':
238 			hideall = 1;
239 			/* FALLTHROUGH */
240 		case 'h':
241 			parent_uprintf = parent_token;
242 			break;
243 		case 'l':
244 			addr = optarg;
245 			break;
246 		case 'N':
247 			noident = 1;
248 			break;
249 		case 'n':
250 			parent_uprintf = parent_uid;
251 			break;
252 		case 't':
253 			timeout.tv_sec = strtonum(optarg,
254 			    TIMEOUT_MIN, TIMEOUT_MAX, &errstr);
255 			if (errstr != NULL)
256 				errx(1, "timeout %s is %s", optarg, errstr);
257 			break;
258 		default:
259 			usage();
260 			/* NOTREACHED */
261 		}
262 	}
263 
264 	argc -= optind;
265 	argv += optind;
266 
267 	if (argc != 0)
268 		usage();
269 
270 	if (geteuid() != 0)
271 		errx(1, "need root privileges");
272 
273 	if (socketpair(AF_UNIX, SOCK_SEQPACKET, PF_UNSPEC, pair) == -1)
274 		err(1, "socketpair");
275 
276 	pw = getpwnam(IDENTD_USER);
277 	if (pw == NULL)
278 		errx(1, "no %s user", IDENTD_USER);
279 
280 	if (!debug && daemon(1, 0) == -1)
281 		err(1, "daemon");
282 
283 	parent = fork();
284 	switch (parent) {
285 	case -1:
286 		lerr(1, "fork");
287 
288 	case 0:
289 		/* child */
290 		setproctitle("listener");
291 		close(pair[1]);
292 		sibling = pair[0];
293 		break;
294 
295 	default:
296 		/* parent */
297 		setproctitle("resolver");
298 		close(pair[0]);
299 		sibling = pair[1];
300 		break;
301 	}
302 
303 	if (!debug) {
304 		openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
305 		tzset();
306 		logger = &syslogger;
307 	}
308 
309 	event_init();
310 
311 	if (ioctl(sibling, FIONBIO, &on) == -1)
312 		lerr(1, "sibling ioctl(FIONBIO)");
313 
314 	if (parent) {
315 		SIMPLEQ_INIT(&sc.parent.replies);
316 
317 		event_set(&proc_rd, sibling, EV_READ | EV_PERSIST,
318 		    parent_rd, NULL);
319 		event_set(&proc_wr, sibling, EV_WRITE,
320 		    parent_wr, NULL);
321 	} else {
322 		SIMPLEQ_INIT(&sc.child.pushing);
323 		SIMPLEQ_INIT(&sc.child.popping);
324 
325 		identd_listen(addr, "auth", family);
326 
327 		if (chroot(pw->pw_dir) == -1)
328 			lerr(1, "chroot(%s)", pw->pw_dir);
329 
330 		if (chdir("/") == -1)
331 			lerr(1, "chdir(%s)", pw->pw_dir);
332 
333 		event_set(&proc_rd, sibling, EV_READ | EV_PERSIST,
334 		    child_rd, NULL);
335 		event_set(&proc_wr, sibling, EV_WRITE,
336 		    child_wr, NULL);
337 	}
338 
339 	if (setgroups(1, &pw->pw_gid) ||
340 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
341 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
342 		lerr(1, "unable to revoke privs");
343 
344 	event_add(&proc_rd, NULL);
345 	event_dispatch();
346 	return (0);
347 }
348 
349 void
350 parent_rd(int fd, short events, void *arg)
351 {
352 	struct ident_resolver *r;
353 	struct passwd *pw;
354 	ssize_t n;
355 	uid_t uid;
356 
357 	n = read(fd, &uid, sizeof(uid));
358 	switch (n) {
359 	case -1:
360 		switch (errno) {
361 		case EAGAIN:
362 		case EINTR:
363 			return;
364 		default:
365 			lerr(1, "parent read");
366 		}
367 		break;
368 	case 0:
369 		lerrx(1, "child has gone");
370 	case sizeof(uid):
371 		break;
372 	default:
373 		lerrx(1, "unexpected %zd data from child", n);
374 	}
375 
376 	r = calloc(1, sizeof(*r));
377 	if (r == NULL)
378 		lerr(1, "resolver alloc");
379 
380 	pw = getpwuid(uid);
381 	if (pw == NULL && !hideall) {
382 		r->error = E_NOUSER;
383 		goto done;
384 	}
385 
386 	if (noident && !hideall) {
387 		parent_noident(r, pw);
388 		if (r->error != E_NONE)
389 			goto done;
390 	}
391 
392 	n = (*parent_uprintf)(r, pw);
393 	if (n == -1) {
394 		r->error = E_UNKNOWN;
395 		goto done;
396 	}
397 
398 	r->buflen = n + 1;
399 
400 done:
401 	SIMPLEQ_INSERT_TAIL(&sc.parent.replies, r, entry);
402 	event_add(&proc_wr, NULL);
403 }
404 
405 int
406 parent_username(struct ident_resolver *r, struct passwd *pw)
407 {
408 	return (asprintf(&r->buf, "%s", pw->pw_name));
409 }
410 
411 int
412 parent_uid(struct ident_resolver *r, struct passwd *pw)
413 {
414 	return (asprintf(&r->buf, "%u", (u_int)pw->pw_uid));
415 }
416 
417 int
418 parent_token(struct ident_resolver *r, struct passwd *pw)
419 {
420 	const char *token;
421 	int rv;
422 
423 	token = gentoken();
424 	rv = asprintf(&r->buf, "%s", token);
425 	if (rv != -1) {
426 		if (pw)
427 			lnotice("token %s == uid %u (%s)", token,
428 			    (u_int)pw->pw_uid, pw->pw_name);
429 		else
430 			lnotice("token %s == NO USER", token);
431 	}
432 
433 	return (rv);
434 }
435 
436 void
437 parent_noident(struct ident_resolver *r, struct passwd *pw)
438 {
439 	char path[MAXPATHLEN];
440 	struct stat st;
441 	int rv;
442 
443 	rv = snprintf(path, sizeof(path), "%s/%s", pw->pw_dir, DOTNOIDENT);
444 	if (rv == -1 || rv >= sizeof(path)) {
445 		r->error = E_UNKNOWN;
446 		return;
447 	}
448 
449 	if (stat(path, &st) == -1)
450 		return;
451 
452 	r->error = E_HIDDEN;
453 }
454 
455 void
456 parent_wr(int fd, short events, void *arg)
457 {
458 	struct ident_resolver *r = SIMPLEQ_FIRST(&sc.parent.replies);
459 	struct iovec iov[2];
460 	int iovcnt = 0;
461 	ssize_t n;
462 
463 	iov[iovcnt].iov_base = &r->error;
464 	iov[iovcnt].iov_len = sizeof(r->error);
465 	iovcnt++;
466 
467 	if (r->buflen > 0) {
468 		iov[iovcnt].iov_base = r->buf;
469 		iov[iovcnt].iov_len = r->buflen;
470 		iovcnt++;
471 	}
472 
473 	n = writev(fd, iov, iovcnt);
474 	if (n == -1) {
475 		if (errno == EAGAIN) {
476 			event_add(&proc_wr, NULL);
477 			return;
478 		}
479 		lerr(1, "parent write");
480 	}
481 
482 	if (n != sizeof(r->error) + r->buflen)
483 		lerrx(1, "unexpected parent write length %zd", n);
484 
485 	SIMPLEQ_REMOVE_HEAD(&sc.parent.replies, entry);
486 
487 	if (r->buflen > 0)
488 		free(r->buf);
489 
490 	free(r);
491 }
492 
493 void
494 child_rd(int fd, short events, void *arg)
495 {
496 	struct ident_client *c;
497 	struct {
498 		u_int error;
499 		char buf[512];
500 	} reply;
501 	ssize_t n;
502 
503 	n = read(fd, &reply, sizeof(reply));
504 	switch (n) {
505 	case -1:
506 		switch (errno) {
507 		case EAGAIN:
508 		case EINTR:
509 			return;
510 		default:
511 			lerr(1, "child read");
512 		}
513 		break;
514 	case 0:
515 		lerrx(1, "parent has gone");
516 	default:
517 		break;
518 	}
519 
520 	c = SIMPLEQ_FIRST(&sc.child.popping);
521 	if (c == NULL)
522 		lerrx(1, "unsolicited data from parent");
523 
524 	SIMPLEQ_REMOVE_HEAD(&sc.child.popping, entry);
525 
526 	if (n < sizeof(reply.error))
527 		lerrx(1, "short data from parent");
528 
529 	/* check if something went wrong while the parent was working */
530 	if (c->state == S_DEAD) {
531 		free(c);
532 		return;
533 	}
534 	c->state = S_DEAD;
535 
536 	switch (reply.error) {
537 	case E_NONE:
538 		n = asprintf(&c->buf, "%u , %u : USERID : UNIX : %s\r\n",
539 		    c->server.port, c->client.port, reply.buf);
540 		break;
541 	case E_NOUSER:
542 		n = asprintf(&c->buf, "%u , %u : ERROR : %s\r\n",
543 		    c->server.port, c->client.port,
544 		    unknown_err ? "UNKNOWN-ERROR" : "NO-USER");
545 		break;
546 	case E_UNKNOWN:
547 		n = asprintf(&c->buf, "%u , %u : ERROR : UNKNOWN-ERROR\r\n",
548 		    c->server.port, c->client.port);
549 		break;
550 	case E_HIDDEN:
551 		n = asprintf(&c->buf, "%u , %u : ERROR : HIDDEN-USER\r\n",
552 		    c->server.port, c->client.port);
553 		break;
554 	default:
555 		lerrx(1, "unexpected error from parent %u", reply.error);
556 	}
557 	if (n == -1)
558 		goto fail;
559 
560 	c->buflen = n;
561 
562 	fd = EVENT_FD(&c->ev);
563 	event_del(&c->ev);
564 	event_set(&c->ev, fd, EV_READ | EV_WRITE | EV_PERSIST,
565 	    identd_response, c);
566 	event_add(&c->ev, NULL);
567 	return;
568 
569 fail:
570 	identd_close(c);
571 }
572 
573 void
574 child_wr(int fd, short events, void *arg)
575 {
576 	struct ident_client *c = SIMPLEQ_FIRST(&sc.child.pushing);
577 	const char *errstr = NULL;
578 	ssize_t n;
579 
580 	n = write(fd, &c->uid, sizeof(c->uid));
581 	switch (n) {
582 	case -1:
583 		switch (errno) {
584 		case EAGAIN:
585 			event_add(&proc_wr, NULL);
586 			return;
587 		case ENOBUFS: /* parent has a backlog of requests */
588 			errstr = "UNKNOWN-ERROR";
589 			break;
590 		default:
591 			lerr(1, "child write");
592 		}
593 		break;
594 	case sizeof(c->uid):
595 		break;
596 	default:
597 		lerrx(1, "unexpected child write length %zd", n);
598 	}
599 
600 	SIMPLEQ_REMOVE_HEAD(&sc.child.pushing, entry);
601 	if (errstr == NULL)
602 		SIMPLEQ_INSERT_TAIL(&sc.child.popping, c, entry);
603 	else if (identd_error(c, errstr) == -1)
604 		identd_close(c);
605 
606 	if (!SIMPLEQ_EMPTY(&sc.child.pushing))
607 		event_add(&proc_wr, NULL);
608 }
609 
610 void
611 identd_listen(const char *addr, const char *port, int family)
612 {
613 	struct identd_listener *l = NULL;
614 
615 	struct addrinfo hints, *res, *res0;
616 	int error, s;
617 	const char *cause = NULL;
618 
619 	memset(&hints, 0, sizeof(hints));
620 	hints.ai_family = family;
621 	hints.ai_socktype = SOCK_STREAM;
622 	hints.ai_flags = AI_PASSIVE;
623 
624 	error = getaddrinfo(addr, port, &hints, &res0);
625 	if (error)
626 		lerrx(1, "%s/%s: %s", addr, port, gai_strerror(error));
627 
628 	for (res = res0; res != NULL; res = res->ai_next) {
629 		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
630 		if (s == -1) {
631 			cause = "socket";
632 			continue;
633 		}
634 
635 		if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
636 		    &on, sizeof(on)) == -1)
637 			err(1, "listener setsockopt(SO_REUSEADDR)");
638 
639 		if (bind(s, res->ai_addr, res->ai_addrlen) == -1) {
640 			int serrno = errno;
641 
642 			cause = "bind";
643 			close(s);
644 			errno = serrno;
645 			continue;
646 		}
647 
648 		if (ioctl(s, FIONBIO, &on) == -1)
649 			err(1, "listener ioctl(FIONBIO)");
650 
651 		if (listen(s, 5) == -1)
652 			err(1, "listen");
653 
654 		l = calloc(1, sizeof(*l));
655 		if (l == NULL)
656 			err(1, "listener ev alloc");
657 
658 		event_set(&l->ev, s, EV_READ | EV_PERSIST, identd_accept, l);
659 		event_add(&l->ev, NULL);
660 		evtimer_set(&l->pause, identd_paused, l);
661 	}
662 	if (l == NULL)
663 		err(1, "%s", cause);
664 
665 	freeaddrinfo(res0);
666 }
667 
668 void
669 identd_paused(int fd, short events, void *arg)
670 {
671 	struct identd_listener *l = arg;
672 	event_add(&l->ev, NULL);
673 }
674 
675 void
676 identd_accept(int fd, short events, void *arg)
677 {
678 	struct identd_listener *l = arg;
679 	struct sockaddr_storage ss;
680 	struct timeval pause = { 1, 0 };
681 	struct ident_client *c = NULL;
682 	socklen_t len;
683 	int s;
684 
685 	len = sizeof(ss);
686 	s = accept(fd, sa(&ss), &len);
687 	if (s == -1) {
688 		switch (errno) {
689 		case EINTR:
690 		case EWOULDBLOCK:
691 		case ECONNABORTED:
692 			return;
693 		case EMFILE:
694 		case ENFILE:
695 			event_del(&l->ev);
696 			evtimer_add(&l->pause, &pause);
697 			return;
698 		default:
699 			lerr(1, "accept");
700 		}
701 	}
702 
703 	if (ioctl(s, FIONBIO, &on) == -1)
704 		lerr(1, "client ioctl(FIONBIO)");
705 
706 	c = calloc(1, sizeof(*c));
707 	if (c == NULL) {
708 		lwarn("client alloc");
709 		close(fd);
710 		return;
711 	}
712 
713 	memcpy(&c->client.ss, &ss, len);
714 	c->client.len = len;
715 	ldebug("client: %s", gethost(&ss));
716 
717 	/* lookup the local ip it connected to */
718 	c->server.len = sizeof(c->server.ss);
719 	if (getsockname(s, sa(&c->server.ss), &c->server.len) == -1)
720 		lerr(1, "getsockname");
721 
722 	event_set(&c->ev, s, EV_READ | EV_PERSIST, identd_request, c);
723 	event_add(&c->ev, NULL);
724 
725 	event_set(&c->tmo, s, 0, identd_timeout, c);
726 	event_add(&c->tmo, &timeout);
727 }
728 
729 void
730 identd_timeout(int fd, short events, void *arg)
731 {
732 	struct ident_client *c = arg;
733 
734 	event_del(&c->ev);
735 	close(fd);
736 	free(c->buf);
737 
738 	if (c->state == S_QUEUED) /* it is queued for resolving */
739 		c->state = S_DEAD;
740 	else
741 		free(c);
742 }
743 
744 void
745 identd_request(int fd, short events, void *arg)
746 {
747 	struct ident_client *c = arg;
748 	unsigned char buf[64];
749 	ssize_t n, i;
750 	char *errstr = unknown_err ? "UNKNOWN-ERROR" : "INVALID-PORT";
751 
752 	n = read(fd, buf, sizeof(buf));
753 	switch (n) {
754 	case -1:
755 		switch (errno) {
756 		case EINTR:
757 		case EAGAIN:
758 			return;
759 		default:
760 			lwarn("%s read", gethost(&c->client.ss));
761 			goto fail;
762 		}
763 		break;
764 
765 	case 0:
766 		ldebug("%s closed connection", gethost(&c->client.ss));
767 		goto fail;
768 	default:
769 		break;
770 	}
771 
772 	c->rxbytes += n;
773 	if (c->rxbytes >= INPUT_MAX)
774 		goto fail;
775 
776 	for (i = 0; c->state < S_EOL && i < n; i++)
777 		c->state = identd_parse(c, buf[i]);
778 
779 	if (c->state == S_DEAD)
780 		goto error;
781 	if (c->state != S_EOL)
782 		return;
783 
784 	if (c->server.port < 1 || c->client.port < 1)
785 		goto error;
786 
787 	if (fetchuid(c) == -1) {
788 		errstr = unknown_err ? "UNKNOWN-ERROR" : "NO-USER";
789 		goto error;
790 	}
791 
792 	SIMPLEQ_INSERT_TAIL(&sc.child.pushing, c, entry);
793 	c->state = S_QUEUED;
794 
795 	event_del(&c->ev);
796 	event_set(&c->ev, fd, EV_READ | EV_PERSIST, identd_resolving, c);
797 	event_add(&c->ev, NULL);
798 
799 	event_add(&proc_wr, NULL);
800 	return;
801 
802 error:
803 	if (identd_error(c, errstr) == -1)
804 		goto fail;
805 
806 	return;
807 
808 fail:
809 	identd_close(c);
810 }
811 
812 int
813 identd_error(struct ident_client *c, const char *errstr)
814 {
815 	int fd = EVENT_FD(&c->ev);
816 	ssize_t n;
817 
818 	n = asprintf(&c->buf, "%u , %u : ERROR : %s\r\n",
819 	    c->server.port, c->client.port, errstr);
820 	if (n == -1)
821 		return (-1);
822 
823 	c->buflen = n;
824 
825 	event_del(&c->ev);
826 	event_set(&c->ev, fd, EV_READ | EV_WRITE | EV_PERSIST,
827 	    identd_response, c);
828 	event_add(&c->ev, NULL);
829 
830 	return (0);
831 }
832 
833 void
834 identd_close(struct ident_client *c)
835 {
836 	int fd = EVENT_FD(&c->ev);
837 
838 	evtimer_del(&c->tmo);
839 	event_del(&c->ev);
840 	close(fd);
841 	free(c->buf);
842 	free(c);
843 }
844 
845 void
846 identd_resolving(int fd, short events, void *arg)
847 {
848 	struct ident_client *c = arg;
849 	char buf[64];
850 	ssize_t n;
851 
852 	/*
853 	 * something happened while we're waiting for the parent to lookup
854 	 * the user.
855 	 */
856 
857 	n = read(fd, buf, sizeof(buf));
858 	switch (n) {
859 	case -1:
860 		switch (errno) {
861 		case EINTR:
862 		case EAGAIN:
863 			return;
864 		default:
865 			lerrx(1, "resolving read");
866 		}
867 		/* NOTREACHED */
868 	case 0:
869 		ldebug("%s closed connection during resolving",
870 		    gethost(&c->client.ss));
871 		break;
872 	default:
873 		c->rxbytes += n;
874 		if (c->rxbytes >= INPUT_MAX)
875 			break;
876 
877 		/* ignore extra input */
878 		return;
879 	}
880 
881 	evtimer_del(&c->tmo);
882 	event_del(&c->ev);
883 	close(fd);
884 	c->state = S_DEAD; /* on the resolving queue */
885 }
886 
887 enum ident_client_state
888 identd_parse(struct ident_client *c, int ch)
889 {
890 	enum ident_client_state s = c->state;
891 
892 	switch (s) {
893 	case S_BEGINNING:
894 		/* ignore leading space */
895 		if (ch == '\t' || ch == ' ')
896 			return (s);
897 
898 		if (ch == '0' || !isdigit(ch))
899 			return (S_DEAD);
900 
901 		c->server.port = ch - '0';
902 		return (S_SERVER_PORT);
903 
904 	case S_SERVER_PORT:
905 		if (ch == '\t' || ch == ' ')
906 			return (S_PRE_COMMA);
907 		if (ch == ',')
908 			return (S_POST_COMMA);
909 
910 		if (!isdigit(ch))
911 			return (S_DEAD);
912 
913 		c->server.port *= 10;
914 		c->server.port += ch - '0';
915 		if (c->server.port > 65535)
916 			return (S_DEAD);
917 
918 		return (s);
919 
920 	case S_PRE_COMMA:
921 		if (ch == '\t' || ch == ' ')
922 			return (s);
923 		if (ch == ',')
924 			return (S_POST_COMMA);
925 
926 		return (S_DEAD);
927 
928 	case S_POST_COMMA:
929 		if (ch == '\t' || ch == ' ')
930 			return (s);
931 
932 		if (ch == '0' || !isdigit(ch))
933 			return (S_DEAD);
934 
935 		c->client.port = ch - '0';
936 		return (S_CLIENT_PORT);
937 
938 	case S_CLIENT_PORT:
939 		if (ch == '\t' || ch == ' ')
940 			return (S_PRE_EOL);
941 		if (ch == '\r' || ch == '\n')
942 			return (S_EOL);
943 
944 		if (!isdigit(ch))
945 			return (S_DEAD);
946 
947 		c->client.port *= 10;
948 		c->client.port += ch - '0';
949 		if (c->client.port > 65535)
950 			return (S_DEAD);
951 
952 		return (s);
953 
954 	case S_PRE_EOL:
955 		if (ch == '\t' || ch == ' ')
956 			return (s);
957 		if (ch == '\r' || ch == '\n')
958 			return (S_EOL);
959 
960 		return (S_DEAD);
961 
962 	case S_EOL:
963 		/* ignore trailing garbage */
964 		return (s);
965 
966 	default:
967 		return (S_DEAD);
968 	}
969 }
970 
971 void
972 identd_response(int fd, short events, void *arg)
973 {
974 	struct ident_client *c = arg;
975 	char buf[64];
976 	ssize_t n;
977 
978 	if (events & EV_READ) {
979 		n = read(fd, buf, sizeof(buf));
980 		switch (n) {
981 		case -1:
982 			switch (errno) {
983 			case EINTR:
984 			case EAGAIN:
985 				/* meh, try a write */
986 				break;
987 			default:
988 				lerrx(1, "response read");
989 			}
990 			break;
991 		case 0:
992 			ldebug("%s closed connection during response",
993 			    gethost(&c->client.ss));
994 			goto done;
995 		default:
996 			c->rxbytes += n;
997 			if (c->rxbytes >= INPUT_MAX)
998 				goto done;
999 
1000 			/* ignore extra input */
1001 			break;
1002 		}
1003 	}
1004 
1005 	if (!(events & EV_WRITE))
1006 		return; /* try again later */
1007 
1008 	n = write(fd, c->buf + c->bufoff, c->buflen - c->bufoff);
1009 	if (n == -1) {
1010 		switch (errno) {
1011 		case EAGAIN:
1012 			return; /* try again later */
1013 		default:
1014 			lerr(1, "response write");
1015 		}
1016 	}
1017 
1018 	c->bufoff += n;
1019 	if (c->bufoff != c->buflen)
1020 		return; /* try again later */
1021 
1022 done:
1023 	identd_close(c);
1024 }
1025 
1026 void
1027 syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
1028 {
1029 	char *s;
1030 
1031 	if (vasprintf(&s, fmt, ap) == -1) {
1032 		syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror");
1033 		exit(1);
1034 	}
1035 	syslog(priority, "%s: %s", s, strerror(e));
1036 	free(s);
1037 }
1038 
1039 void
1040 syslog_err(int ecode, const char *fmt, ...)
1041 {
1042 	va_list ap;
1043 
1044 	va_start(ap, fmt);
1045 	syslog_vstrerror(errno, LOG_EMERG, fmt, ap);
1046 	va_end(ap);
1047 	exit(ecode);
1048 }
1049 
1050 void
1051 syslog_errx(int ecode, const char *fmt, ...)
1052 {
1053 	va_list ap;
1054 
1055 	va_start(ap, fmt);
1056 	vsyslog(LOG_WARNING, fmt, ap);
1057 	va_end(ap);
1058 	exit(ecode);
1059 }
1060 
1061 void
1062 syslog_warn(const char *fmt, ...)
1063 {
1064 	va_list ap;
1065 
1066 	va_start(ap, fmt);
1067 	syslog_vstrerror(errno, LOG_WARNING, fmt, ap);
1068 	va_end(ap);
1069 }
1070 
1071 void
1072 syslog_warnx(const char *fmt, ...)
1073 {
1074 	va_list ap;
1075 
1076 	va_start(ap, fmt);
1077 	vsyslog(LOG_WARNING, fmt, ap);
1078 	va_end(ap);
1079 }
1080 
1081 void
1082 syslog_notice(const char *fmt, ...)
1083 {
1084 	va_list ap;
1085 
1086 	va_start(ap, fmt);
1087 	vsyslog(LOG_NOTICE, fmt, ap);
1088 	va_end(ap);
1089 }
1090 
1091 void
1092 syslog_debug(const char *fmt, ...)
1093 {
1094 	va_list ap;
1095 
1096 	if (!debug)
1097 		return;
1098 
1099 	va_start(ap, fmt);
1100 	vsyslog(LOG_DEBUG, fmt, ap);
1101 	va_end(ap);
1102 }
1103 
1104 const char *
1105 gethost(struct sockaddr_storage *ss)
1106 {
1107 	struct sockaddr *sa = (struct sockaddr *)ss;
1108 	static char buf[NI_MAXHOST];
1109 
1110 	if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf),
1111 	    NULL, 0, NI_NUMERICHOST) != 0)
1112 		return ("(unknown)");
1113 
1114 	return (buf);
1115 }
1116 
1117 const char *
1118 getport(struct sockaddr_storage *ss)
1119 {
1120 	struct sockaddr *sa = (struct sockaddr *)ss;
1121 	static char buf[NI_MAXSERV];
1122 
1123 	if (getnameinfo(sa, sa->sa_len, NULL, 0, buf, sizeof(buf),
1124 	    NI_NUMERICSERV) != 0)
1125 		return ("(unknown)");
1126 
1127 	return (buf);
1128 }
1129 
1130 const char *
1131 gentoken(void)
1132 {
1133 	static char buf[21];
1134 	u_int32_t r;
1135 	int i;
1136 
1137 	buf[0] = 'a' + arc4random_uniform(26);
1138 	for (i = 1; i < sizeof(buf) - 1; i++) {
1139 		r = arc4random_uniform(36);
1140 		buf[i] = (r < 26 ? 'a' : '0' - 26) + r;
1141 	}
1142 	buf[i] = '\0';
1143 
1144 	return (buf);
1145 }
1146 
1147 int
1148 fetchuid(struct ident_client *c)
1149 {
1150 	struct tcp_ident_mapping tir;
1151 	int mib[] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_IDENT };
1152 	struct sockaddr_in *s4;
1153 	struct sockaddr_in6 *s6;
1154 	int err = 0;
1155 	size_t len;
1156 
1157 	memset(&tir, 0, sizeof(tir));
1158 	memcpy(&tir.faddr, &c->client.ss, sizeof(tir.faddr));
1159 	memcpy(&tir.laddr, &c->server.ss, sizeof(tir.laddr));
1160 
1161 	switch (c->server.ss.ss_family) {
1162 	case AF_INET:
1163 		s4 = (struct sockaddr_in *)&tir.faddr;
1164 		s4->sin_port = htons(c->client.port);
1165 
1166 		s4 = (struct sockaddr_in *)&tir.laddr;
1167 		s4->sin_port = htons(c->server.port);
1168 		break;
1169 	case AF_INET6:
1170 		s6 = (struct sockaddr_in6 *)&tir.faddr;
1171 		s6->sin6_port = htons(c->client.port);
1172 
1173 		s6 = (struct sockaddr_in6 *)&tir.laddr;
1174 		s6->sin6_port = htons(c->server.port);
1175 		break;
1176 	default:
1177 		lerrx(1, "unexpected family %d", c->server.ss.ss_family);
1178 	}
1179 
1180 	len = sizeof(tir);
1181 	err = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &tir, &len, NULL, 0);
1182 	if (err == -1)
1183 		lerr(1, "sysctl");
1184 
1185 	if (tir.ruid == -1)
1186 		return (-1);
1187 
1188 	c->uid = tir.ruid;
1189 	return (0);
1190 }
1191