identd.c revision 1.21
1/* $OpenBSD: identd.c,v 1.21 2013/10/24 02:55:50 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/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 55enum 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 73struct 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 94struct ident_resolver { 95 SIMPLEQ_ENTRY(ident_resolver) entry; 96 char *buf; 97 size_t buflen; 98 u_int error; 99}; 100 101struct identd_listener { 102 struct event ev, pause; 103}; 104 105void parent_rd(int, short, void *); 106void parent_wr(int, short, void *); 107int parent_username(struct ident_resolver *, struct passwd *); 108int parent_uid(struct ident_resolver *, struct passwd *); 109int parent_token(struct ident_resolver *, struct passwd *); 110void parent_noident(struct ident_resolver *, struct passwd *); 111 112void child_rd(int, short, void *); 113void child_wr(int, short, void *); 114 115void identd_listen(const char *, const char *, int); 116void identd_paused(int, short, void *); 117void identd_accept(int, short, void *); 118int identd_error(struct ident_client *, const char *); 119void identd_close(struct ident_client *); 120void identd_timeout(int, short, void *); 121void identd_request(int, short, void *); 122enum ident_client_state 123 identd_parse(struct ident_client *, int); 124void identd_resolving(int, short, void *); 125void identd_response(int, short, void *); 126int fetchuid(struct ident_client *); 127 128const char *gethost(struct sockaddr_storage *); 129const char *getport(struct sockaddr_storage *); 130const char *gentoken(void); 131 132struct 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 141const struct loggers conslogger = { 142 err, 143 errx, 144 warn, 145 warnx, 146 warnx, /* notice */ 147 warnx /* debug */ 148}; 149 150void syslog_err(int, const char *, ...); 151void syslog_errx(int, const char *, ...); 152void syslog_warn(const char *, ...); 153void syslog_warnx(const char *, ...); 154void syslog_notice(const char *, ...); 155void syslog_debug(const char *, ...); 156void syslog_vstrerror(int, int, const char *, va_list); 157 158const struct loggers syslogger = { 159 syslog_err, 160 syslog_errx, 161 syslog_warn, 162 syslog_warnx, 163 syslog_notice, 164 syslog_debug 165}; 166 167const 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__dead void 179usage(void) 180{ 181 extern char *__progname; 182 fprintf(stderr, "usage: %s [-46deHhNn] [-l address] [-t timeout]\n", 183 __progname); 184 exit(1); 185} 186 187struct timeval timeout = { TIMEOUT_DEFAULT, 0 }; 188int debug = 0; 189int noident = 0; 190int on = 1; 191int unknown_err = 0; 192int hideall = 0; 193 194int (*parent_uprintf)(struct ident_resolver *, struct passwd *) = 195 parent_username; 196 197struct event proc_rd, proc_wr; 198union { 199 struct { 200 SIMPLEQ_HEAD(, ident_resolver) replies; 201 } parent; 202 struct { 203 SIMPLEQ_HEAD(, ident_client) pushing, popping; 204 } child; 205} sc; 206 207int 208main(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:Nnp:t:")) != -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 err(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 349void 350parent_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; 399 400done: 401 SIMPLEQ_INSERT_TAIL(&sc.parent.replies, r, entry); 402 event_add(&proc_wr, NULL); 403} 404 405int 406parent_username(struct ident_resolver *r, struct passwd *pw) 407{ 408 return (asprintf(&r->buf, "%s", pw->pw_name)); 409} 410 411int 412parent_uid(struct ident_resolver *r, struct passwd *pw) 413{ 414 return (asprintf(&r->buf, "%u", (u_int)pw->pw_uid)); 415} 416 417int 418parent_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 436void 437parent_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 455void 456parent_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 493void 494child_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 569fail: 570 identd_close(c); 571} 572 573void 574child_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 610void 611identd_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 668void 669identd_paused(int fd, short events, void *arg) 670{ 671 struct identd_listener *l = arg; 672 event_add(&l->ev, NULL); 673} 674 675void 676identd_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 729void 730identd_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 744void 745identd_request(int fd, short events, void *arg) 746{ 747 struct ident_client *c = arg; 748 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 802error: 803 if (identd_error(c, errstr) == -1) 804 goto fail; 805 806 return; 807 808fail: 809 identd_close(c); 810} 811 812int 813identd_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 833void 834identd_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 845void 846identd_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 887enum ident_client_state 888identd_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 971void 972identd_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 1022done: 1023 identd_close(c); 1024} 1025 1026void 1027syslog_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 1039void 1040syslog_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 1050void 1051syslog_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 1061void 1062syslog_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 1071void 1072syslog_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 1081void 1082syslog_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 1091void 1092syslog_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 1104const char * 1105gethost(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 1117const char * 1118getport(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 1130const char * 1131gentoken(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 1147int 1148fetchuid(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