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