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