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