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