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