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