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