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 58enum 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 76struct 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 97struct ident_resolver { 98 SIMPLEQ_ENTRY(ident_resolver) entry; 99 char *buf; 100 size_t buflen; 101 u_int error; 102}; 103 104struct identd_listener { 105 struct event ev, pause; 106}; 107 108void parent_rd(int, short, void *); 109void parent_wr(int, short, void *); 110int parent_username(struct ident_resolver *, struct passwd *); 111int parent_uid(struct ident_resolver *, struct passwd *); 112int parent_token(struct ident_resolver *, struct passwd *); 113void parent_noident(struct ident_resolver *, struct passwd *); 114 115void child_rd(int, short, void *); 116void child_wr(int, short, void *); 117 118void identd_listen(const char *, const char *, int); 119void identd_paused(int, short, void *); 120void identd_accept(int, short, void *); 121int identd_error(struct ident_client *, const char *); 122void identd_close(struct ident_client *); 123void identd_timeout(int, short, void *); 124void identd_request(int, short, void *); 125enum ident_client_state 126 identd_parse(struct ident_client *, int); 127void identd_resolving(int, short, void *); 128void identd_response(int, short, void *); 129int fetchuid(struct ident_client *); 130 131const char *gethost(struct sockaddr_storage *); 132const char *gentoken(void); 133 134struct 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 149const 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))); 162void syslog_warn(const char *, ...) 163 __attribute__((__format__ (printf, 1, 2))); 164void syslog_warnx(const char *, ...) 165 __attribute__((__format__ (printf, 1, 2))); 166void syslog_notice(const char *, ...) 167 __attribute__((__format__ (printf, 1, 2))); 168void syslog_debug(const char *, ...) 169 __attribute__((__format__ (printf, 1, 2))); 170void syslog_vstrerror(int, int, const char *, va_list) 171 __attribute__((__format__ (printf, 3, 0))); 172 173const struct loggers syslogger = { 174 syslog_err, 175 syslog_errx, 176 syslog_warn, 177 syslog_warnx, 178 syslog_notice, 179 syslog_debug 180}; 181 182const 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 193static __dead void 194usage(void) 195{ 196 extern char *__progname; 197 fprintf(stderr, "usage: %s [-46deHhNn] [-l address] [-t timeout]\n", 198 __progname); 199 exit(1); 200} 201 202struct timeval timeout = { TIMEOUT_DEFAULT, 0 }; 203int debug = 0; 204int noident = 0; 205int unknown_err = 0; 206int hideall = 0; 207 208int (*parent_uprintf)(struct ident_resolver *, struct passwd *) = 209 parent_username; 210 211struct event proc_rd, proc_wr; 212union { 213 struct { 214 SIMPLEQ_HEAD(, ident_resolver) replies; 215 } parent; 216 struct { 217 SIMPLEQ_HEAD(, ident_client) pushing, popping; 218 } child; 219} sc; 220 221int 222main(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 377void 378parent_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 428done: 429 SIMPLEQ_INSERT_TAIL(&sc.parent.replies, r, entry); 430 event_add(&proc_wr, NULL); 431} 432 433int 434parent_username(struct ident_resolver *r, struct passwd *pw) 435{ 436 return (asprintf(&r->buf, "%s", pw->pw_name)); 437} 438 439int 440parent_uid(struct ident_resolver *r, struct passwd *pw) 441{ 442 return (asprintf(&r->buf, "%u", (u_int)pw->pw_uid)); 443} 444 445int 446parent_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 464void 465parent_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 483void 484parent_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 527void 528child_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 603fail: 604 identd_close(c); 605} 606 607void 608child_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 645void 646identd_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 702void 703identd_paused(int fd, short events, void *arg) 704{ 705 struct identd_listener *l = arg; 706 event_add(&l->ev, NULL); 707} 708 709void 710identd_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 760void 761identd_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 775void 776identd_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 833error: 834 if (identd_error(c, errstr) == -1) 835 goto fail; 836 837 return; 838 839fail: 840 identd_close(c); 841} 842 843int 844identd_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 864void 865identd_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 876void 877identd_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 919enum ident_client_state 920identd_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 1003void 1004identd_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 1059done: 1060 identd_close(c); 1061} 1062 1063void 1064syslog_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 1076void 1077syslog_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 1087void 1088syslog_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 1098void 1099syslog_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 1108void 1109syslog_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 1118void 1119syslog_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 1128void 1129syslog_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 1141const char * 1142gethost(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 1154const char * 1155gentoken(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 1171int 1172fetchuid(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