1 /* $NetBSD: identd.c,v 1.36 2016/12/10 22:08:13 christos Exp $ */ 2 3 /* 4 * identd.c - TCP/IP Ident protocol server. 5 * 6 * This software is in the public domain. 7 * Written by Peter Postma <peter@NetBSD.org> 8 */ 9 10 #include <sys/cdefs.h> 11 __RCSID("$NetBSD: identd.c,v 1.36 2016/12/10 22:08:13 christos Exp $"); 12 13 #include <sys/param.h> 14 #include <sys/socket.h> 15 #include <sys/stat.h> 16 #include <sys/sysctl.h> 17 18 #include <netinet/in.h> 19 #include <netinet/ip_var.h> 20 #include <netinet/tcp.h> 21 #include <netinet/tcp_timer.h> 22 #include <netinet/tcp_var.h> 23 24 #include <arpa/inet.h> 25 26 #include <ctype.h> 27 #include <err.h> 28 #include <errno.h> 29 #include <fcntl.h> 30 #include <grp.h> 31 #include <netdb.h> 32 #include <poll.h> 33 #include <pwd.h> 34 #include <signal.h> 35 #include <stdarg.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <syslog.h> 40 #include <unistd.h> 41 42 #include "identd.h" 43 44 #define OPSYS_NAME "UNIX" 45 #define IDENT_SERVICE "auth" 46 #define TIMEOUT 30 /* seconds */ 47 48 static int idhandle(int, const char *, const char *, const char *, 49 const char *, struct sockaddr *, int); 50 static void idparse(int, int, int, const char *, const char *, const char *); 51 static void iderror(int, int, int, const char *); 52 static const char *gethost(struct sockaddr *); 53 static int *socketsetup(const char *, const char *, int); 54 static int ident_getuid(struct sockaddr_storage *, socklen_t, 55 struct sockaddr *, uid_t *); 56 static int sysctl_getuid(struct sockaddr_storage *, socklen_t, uid_t *); 57 static int sysctl_proxy_getuid(struct sockaddr_storage *, 58 struct sockaddr *, uid_t *); 59 static int forward(int, struct sockaddr *, int, int, int); 60 static int check_noident(const char *); 61 static int check_userident(const char *, char *, size_t); 62 static void random_string(char *, size_t); 63 static int change_format(const char *, struct passwd *, char *, size_t); 64 __dead static void timeout_handler(int); 65 __dead static void fatal(const char *); 66 __dead static void die(const char *, ...) __printflike(1, 2); 67 68 static int bflag, dflag, eflag, fflag, iflag, Iflag; 69 static int lflag, Lflag, nflag, Nflag, rflag; 70 71 /* NAT lookup function pointer. */ 72 typedef int (*nat_lookup_t)(const struct sockaddr_storage *, 73 struct sockaddr_storage *, in_port_t *); 74 75 static nat_lookup_t nat_lookup; 76 77 /* Packet filters. */ 78 static const struct { 79 const char *name; 80 nat_lookup_t fn; 81 } filters[] = { 82 #ifdef WITH_PF 83 { "pf", pf_natlookup }, 84 #endif 85 #ifdef WITH_IPF 86 { "ipfilter", ipf_natlookup }, 87 #endif 88 #ifdef WITH_NPF 89 { "npf", npf_natlookup }, 90 #endif 91 { NULL, NULL } 92 }; 93 94 int 95 main(int argc, char *argv[]) 96 { 97 int IPv4or6, ch, error, i, *socks, timeout; 98 const char *filter, *osname, *portno, *proxy; 99 char *address, *charset, *fmt, *p; 100 char user[LOGIN_NAME_MAX]; 101 struct addrinfo *ai, hints; 102 struct sockaddr *proxy_addr; 103 struct group *grp; 104 struct passwd *pw; 105 gid_t gid; 106 uid_t uid; 107 108 socks = NULL; 109 IPv4or6 = AF_UNSPEC; 110 osname = OPSYS_NAME; 111 portno = IDENT_SERVICE; 112 timeout = TIMEOUT; 113 nat_lookup = NULL; 114 proxy_addr = NULL; 115 filter = proxy = NULL; 116 address = charset = fmt = NULL; 117 uid = gid = 0; 118 bflag = dflag = eflag = fflag = iflag = Iflag = 0; 119 lflag = Lflag = nflag = Nflag = rflag = 0; 120 121 /* Started from a tty? then run as daemon. */ 122 if (isatty(STDIN_FILENO)) 123 bflag = 1; 124 125 /* Parse command line arguments. */ 126 while ((ch = getopt(argc, argv, 127 "46a:bcdeF:f:g:IiL:lm:Nno:P:p:rt:u:")) != -1) { 128 switch (ch) { 129 case '4': 130 IPv4or6 = AF_INET; 131 break; 132 case '6': 133 IPv4or6 = AF_INET6; 134 break; 135 case 'a': 136 address = optarg; 137 break; 138 case 'b': 139 bflag = 1; 140 break; 141 case 'c': 142 charset = optarg; 143 break; 144 case 'd': 145 dflag++; 146 break; 147 case 'e': 148 eflag = 1; 149 break; 150 case 'F': 151 fmt = optarg; 152 break; 153 case 'f': 154 fflag = 1; 155 (void)strlcpy(user, optarg, sizeof(user)); 156 break; 157 case 'g': 158 gid = (gid_t)strtol(optarg, &p, 0); 159 if (*p != '\0') { 160 if ((grp = getgrnam(optarg)) != NULL) 161 gid = grp->gr_gid; 162 else 163 die("No such group `%s'", optarg); 164 } 165 break; 166 case 'I': 167 Iflag = 1; 168 /* FALLTHROUGH */ 169 case 'i': 170 iflag = 1; 171 break; 172 case 'L': 173 Lflag = 1; 174 (void)strlcpy(user, optarg, sizeof(user)); 175 break; 176 case 'l': 177 if (!lflag) 178 openlog("identd", LOG_PID, LOG_DAEMON); 179 lflag = 1; 180 break; 181 case 'm': 182 filter = optarg; 183 break; 184 case 'N': 185 Nflag = 1; 186 break; 187 case 'n': 188 nflag = 1; 189 break; 190 case 'o': 191 osname = optarg; 192 break; 193 case 'P': 194 proxy = optarg; 195 break; 196 case 'p': 197 portno = optarg; 198 break; 199 case 'r': 200 rflag = 1; 201 break; 202 case 't': 203 timeout = (int)strtol(optarg, &p, 0); 204 if (*p != '\0' || timeout < 1) 205 die("Invalid timeout value `%s'", optarg); 206 break; 207 case 'u': 208 uid = (uid_t)strtol(optarg, &p, 0); 209 if (*p != '\0') { 210 if ((pw = getpwnam(optarg)) != NULL) { 211 uid = pw->pw_uid; 212 gid = pw->pw_gid; 213 } else 214 die("No such user `%s'", optarg); 215 } 216 break; 217 default: 218 exit(EXIT_FAILURE); 219 } 220 } 221 222 /* Verify proxy address, if enabled. */ 223 if (proxy != NULL) { 224 (void)memset(&hints, 0, sizeof(hints)); 225 hints.ai_family = IPv4or6; 226 hints.ai_socktype = SOCK_STREAM; 227 error = getaddrinfo(proxy, NULL, &hints, &ai); 228 if (error != 0) 229 die("Bad proxy `%s': %s", proxy, gai_strerror(error)); 230 if (ai->ai_next != NULL) 231 die("Bad proxy `%s': resolves to multiple addresses", 232 proxy); 233 proxy_addr = ai->ai_addr; 234 } 235 236 /* Verify filter, if enabled. */ 237 if (filter != NULL) { 238 for (i = 0; filters[i].name != NULL; i++) { 239 if (strcasecmp(filter, filters[i].name) == 0) { 240 nat_lookup = filters[i].fn; 241 break; 242 } 243 } 244 if (nat_lookup == NULL) 245 die("Packet filter `%s' is not supported", filter); 246 } 247 248 /* Setup sockets when running in the background. */ 249 if (bflag) 250 socks = socketsetup(address, portno, IPv4or6); 251 252 /* Switch to another uid/gid? */ 253 if (gid && setgid(gid) == -1) 254 die("Failed to set GID to `%d': %s", gid, strerror(errno)); 255 if (uid && setuid(uid) == -1) 256 die("Failed to set UID to `%d': %s", uid, strerror(errno)); 257 258 /* 259 * When running as daemon: daemonize, setup pollfds and go into 260 * the mainloop. Otherwise, just read the input from stdin and 261 * let inetd handle the sockets. 262 */ 263 if (bflag) { 264 int fd, nfds, rv; 265 struct pollfd *rfds; 266 267 if (!dflag && daemon(0, 0) < 0) 268 die("daemon: %s", strerror(errno)); 269 270 rfds = malloc(*socks * sizeof(struct pollfd)); 271 if (rfds == NULL) 272 fatal("malloc"); 273 nfds = *socks; 274 for (i = 0; i < nfds; i++) { 275 rfds[i].fd = socks[i+1]; 276 rfds[i].events = POLLIN; 277 rfds[i].revents = 0; 278 } 279 /* Mainloop for daemon. */ 280 for (;;) { 281 rv = poll(rfds, nfds, INFTIM); 282 if (rv < 0) { 283 if (errno == EINTR) 284 continue; 285 fatal("poll"); 286 } 287 for (i = 0; i < nfds; i++) { 288 if (rfds[i].revents & POLLIN) { 289 fd = accept(rfds[i].fd, NULL, NULL); 290 if (fd < 0) { 291 maybe_syslog(LOG_ERR, 292 "accept: %m"); 293 continue; 294 } 295 switch (fork()) { 296 case -1: /* error */ 297 maybe_syslog(LOG_ERR, 298 "fork: %m"); 299 (void)sleep(1); 300 break; 301 case 0: /* child */ 302 (void)idhandle(fd, charset, 303 fmt, osname, user, 304 proxy_addr, timeout); 305 _exit(EXIT_SUCCESS); 306 default: /* parent */ 307 (void)signal(SIGCHLD, SIG_IGN); 308 (void)close(fd); 309 } 310 } 311 } 312 } 313 } else 314 (void)idhandle(STDIN_FILENO, charset, fmt, osname, user, 315 proxy_addr, timeout); 316 317 return 0; 318 } 319 320 /* 321 * Handle a request on the ident port. Returns 0 on success or 1 on 322 * failure. The return values are currently ignored. 323 */ 324 static int 325 idhandle(int fd, const char *charset, const char *fmt, const char *osname, 326 const char *user, struct sockaddr *proxy, int timeout) 327 { 328 struct sockaddr_storage ss[2]; 329 char userbuf[LOGIN_NAME_MAX]; /* actual user name (or numeric uid) */ 330 char idbuf[LOGIN_NAME_MAX]; /* name to be used in response */ 331 char buf[BUFSIZ], *p; 332 struct passwd *pw; 333 int lport, fport; 334 socklen_t len; 335 uid_t uid; 336 ssize_t n; 337 size_t qlen; 338 339 lport = fport = 0; 340 341 (void)strlcpy(idbuf, user, sizeof(idbuf)); 342 (void)signal(SIGALRM, timeout_handler); 343 (void)alarm(timeout); 344 345 /* Get foreign internet address. */ 346 len = sizeof(ss[0]); 347 if (getpeername(fd, (struct sockaddr *)&ss[0], &len) < 0) 348 fatal("getpeername"); 349 350 maybe_syslog(LOG_INFO, "Connection from %s", 351 gethost((struct sockaddr *)&ss[0])); 352 353 /* Get local internet address. */ 354 len = sizeof(ss[1]); 355 if (getsockname(fd, (struct sockaddr *)&ss[1], &len) < 0) 356 fatal("getsockname"); 357 358 /* Be sure to have the same address families. */ 359 if (ss[0].ss_family != ss[1].ss_family) { 360 maybe_syslog(LOG_ERR, "Different foreign/local address family"); 361 return 1; 362 } 363 364 /* Receive data from the client. */ 365 qlen = 0; 366 for (;;) { 367 if ((n = recv(fd, &buf[qlen], sizeof(buf) - qlen, 0)) < 0) { 368 fatal("recv"); 369 } else if (n == 0) { 370 maybe_syslog(LOG_NOTICE, "recv: EOF"); 371 iderror(fd, 0, 0, "UNKNOWN-ERROR"); 372 return 1; 373 } 374 /* 375 * 1413 is not clear on what to do if data follows the first 376 * CRLF before we respond. We do not consider the query 377 * complete until we get a CRLF _at the end of the buffer_. 378 */ 379 qlen += n; 380 if (qlen >= sizeof(buf)) { 381 maybe_syslog(LOG_NOTICE, "recv: message too long"); 382 exit(0); 383 } 384 if ((qlen >= 2) && (buf[qlen - 2] == '\r') && 385 (buf[qlen - 1] == '\n')) 386 break; 387 } 388 buf[qlen - 2] = '\0'; 389 390 /* Get local and remote ports from the received data. */ 391 p = buf; 392 while (*p != '\0' && isspace((unsigned char)*p)) 393 p++; 394 if ((p = strtok(p, " \t,")) != NULL) { 395 lport = atoi(p); 396 if ((p = strtok(NULL, " \t,")) != NULL) 397 fport = atoi(p); 398 } 399 400 /* Are the ports valid? */ 401 if (lport < 1 || lport > 65535 || fport < 1 || fport > 65535) { 402 maybe_syslog(LOG_NOTICE, "Invalid port(s): %d, %d from %s", 403 lport, fport, gethost((struct sockaddr *)&ss[0])); 404 iderror(fd, 0, 0, eflag ? "UNKNOWN-ERROR" : "INVALID-PORT"); 405 return 1; 406 } 407 408 /* If there is a 'lie' user enabled, then handle it now and stop. */ 409 if (Lflag) { 410 maybe_syslog(LOG_NOTICE, "Lying with name %s to %s", 411 idbuf, gethost((struct sockaddr *)&ss[0])); 412 idparse(fd, lport, fport, charset, osname, idbuf); 413 return 0; 414 } 415 416 /* Protocol dependent stuff. */ 417 switch (ss[0].ss_family) { 418 case AF_INET: 419 satosin(&ss[0])->sin_port = htons(fport); 420 satosin(&ss[1])->sin_port = htons(lport); 421 break; 422 case AF_INET6: 423 satosin6(&ss[0])->sin6_port = htons(fport); 424 satosin6(&ss[1])->sin6_port = htons(lport); 425 break; 426 default: 427 maybe_syslog(LOG_ERR, "Unsupported protocol (no. %d)", 428 ss[0].ss_family); 429 return 1; 430 } 431 432 /* Try to get the UID of the connection owner using sysctl. */ 433 if (ident_getuid(ss, sizeof(ss), proxy, &uid) == -1) { 434 /* Lookup failed, try to forward if enabled. */ 435 if (nat_lookup != NULL) { 436 struct sockaddr_storage nat_addr; 437 in_port_t nat_lport; 438 439 (void)memset(&nat_addr, 0, sizeof(nat_addr)); 440 if ((*nat_lookup)(ss, &nat_addr, &nat_lport) && 441 forward(fd, (struct sockaddr *)&nat_addr, 442 nat_lport, fport, lport)) { 443 maybe_syslog(LOG_INFO, 444 "Succesfully forwarded the request to %s", 445 gethost((struct sockaddr *)&nat_addr)); 446 return 0; 447 } 448 } 449 /* Fall back to a default name? */ 450 if (fflag) { 451 maybe_syslog(LOG_NOTICE, "Using fallback name %s to %s", 452 idbuf, gethost((struct sockaddr *)&ss[0])); 453 idparse(fd, lport, fport, charset, osname, idbuf); 454 return 0; 455 } 456 maybe_syslog(LOG_ERR, "Lookup failed, returning error to %s", 457 gethost((struct sockaddr *)&ss[0])); 458 iderror(fd, lport, fport, eflag ? "UNKNOWN-ERROR" : "NO-USER"); 459 return 1; 460 } 461 462 /* Fill in userbuf with user name if possible, else numeric UID. */ 463 if ((pw = getpwuid(uid)) == NULL) { 464 maybe_syslog(LOG_ERR, "Couldn't map uid (%u) to name", uid); 465 (void)snprintf(userbuf, sizeof(userbuf), "%u", uid); 466 } else { 467 maybe_syslog(LOG_INFO, "Successful lookup: %d, %d: %s for %s", 468 lport, fport, pw->pw_name, 469 gethost((struct sockaddr *)&ss[0])); 470 (void)strlcpy(userbuf, pw->pw_name, sizeof(userbuf)); 471 } 472 473 /* No ident enabled? */ 474 if (Nflag && pw && check_noident(pw->pw_dir)) { 475 maybe_syslog(LOG_NOTICE, "Returning HIDDEN-USER for user %s" 476 " to %s", pw->pw_name, gethost((struct sockaddr *)&ss[0])); 477 iderror(fd, lport, fport, "HIDDEN-USER"); 478 return 1; 479 } 480 481 /* User ident enabled? */ 482 if (iflag && pw && check_userident(pw->pw_dir, idbuf, sizeof(idbuf))) { 483 if (!Iflag) { 484 if ((strspn(idbuf, "0123456789") && 485 getpwuid(atoi(idbuf)) != NULL) || 486 (getpwnam(idbuf) != NULL)) { 487 maybe_syslog(LOG_NOTICE, 488 "Ignoring user-specified '%s' for user %s", 489 idbuf, userbuf); 490 (void)strlcpy(idbuf, userbuf, sizeof(idbuf)); 491 } 492 } 493 maybe_syslog(LOG_NOTICE, 494 "Returning user-specified '%s' for user %s to %s", 495 idbuf, userbuf, gethost((struct sockaddr *)&ss[0])); 496 idparse(fd, lport, fport, charset, osname, idbuf); 497 return 0; 498 } 499 500 /* Send a random message? */ 501 if (rflag) { 502 /* Random number or string? */ 503 if (nflag) 504 (void)snprintf(idbuf, sizeof(idbuf), "%u", 505 (unsigned int)(arc4random() % 65535)); 506 else 507 random_string(idbuf, sizeof(idbuf)); 508 509 maybe_syslog(LOG_NOTICE, 510 "Returning random '%s' for user %s to %s", 511 idbuf, userbuf, gethost((struct sockaddr *)&ss[0])); 512 idparse(fd, lport, fport, charset, osname, idbuf); 513 return 0; 514 } 515 516 /* Return numberic user ID? */ 517 if (nflag) 518 (void)snprintf(idbuf, sizeof(idbuf), "%u", uid); 519 else 520 (void)strlcpy(idbuf, userbuf, sizeof(idbuf)); 521 522 /* 523 * Change the output format? Note that 512 is the maximum 524 * size of the result according to RFC 1413. 525 */ 526 if (fmt && change_format(fmt, pw, buf, 512 + 1)) 527 idparse(fd, lport, fport, charset, osname, buf); 528 else 529 idparse(fd, lport, fport, charset, osname, idbuf); 530 531 return 0; 532 } 533 534 /* Send/parse the ident result. */ 535 static void 536 idparse(int fd, int lport, int fport, const char *charset, const char *osname, 537 const char *user) 538 { 539 char *p; 540 541 if (asprintf(&p, "%d,%d:USERID:%s%s%s:%s\r\n", lport, fport, 542 osname, charset ? "," : "", charset ? charset : "", user) < 0) 543 fatal("asprintf"); 544 if (send(fd, p, strlen(p), 0) < 0) { 545 free(p); 546 fatal("send"); 547 } 548 free(p); 549 } 550 551 /* Return a specified ident error. */ 552 static void 553 iderror(int fd, int lport, int fport, const char *error) 554 { 555 char *p; 556 557 if (asprintf(&p, "%d,%d:ERROR:%s\r\n", lport, fport, error) < 0) 558 fatal("asprintf"); 559 if (send(fd, p, strlen(p), 0) < 0) { 560 free(p); 561 fatal("send"); 562 } 563 free(p); 564 } 565 566 /* Return the IP address of the connecting host. */ 567 static const char * 568 gethost(struct sockaddr *sa) 569 { 570 static char host[NI_MAXHOST]; 571 572 if (getnameinfo(sa, sa->sa_len, host, sizeof(host), 573 NULL, 0, NI_NUMERICHOST) == 0) 574 return host; 575 576 return "UNKNOWN"; 577 } 578 579 /* Setup sockets, for daemon mode. */ 580 static int * 581 socketsetup(const char *address, const char *port, int af) 582 { 583 struct addrinfo hints, *res, *res0; 584 int error, maxs, *s, *socks; 585 const char *cause = NULL; 586 socklen_t y = 1; 587 588 (void)memset(&hints, 0, sizeof(hints)); 589 hints.ai_flags = AI_PASSIVE; 590 hints.ai_family = af; 591 hints.ai_socktype = SOCK_STREAM; 592 error = getaddrinfo(address, port, &hints, &res0); 593 if (error) { 594 die("getaddrinfo: %s", gai_strerror(error)); 595 /* NOTREACHED */ 596 } 597 598 /* Count max number of sockets we may open. */ 599 for (maxs = 0, res = res0; res != NULL; res = res->ai_next) 600 maxs++; 601 602 socks = malloc((maxs + 1) * sizeof(int)); 603 if (socks == NULL) { 604 die("malloc: %s", strerror(errno)); 605 /* NOTREACHED */ 606 } 607 608 *socks = 0; 609 s = socks + 1; 610 for (res = res0; res != NULL; res = res->ai_next) { 611 *s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 612 if (*s < 0) { 613 cause = "socket"; 614 continue; 615 } 616 (void)setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(y)); 617 if (bind(*s, res->ai_addr, res->ai_addrlen) < 0) { 618 cause = "bind"; 619 (void)close(*s); 620 continue; 621 } 622 if (listen(*s, 5) < 0) { 623 cause = "listen"; 624 (void)close(*s); 625 continue; 626 } 627 *socks = *socks + 1; 628 s++; 629 } 630 631 if (*socks == 0) { 632 free(socks); 633 die("%s: %s", cause, strerror(errno)); 634 /* NOTREACHED */ 635 } 636 if (res0) 637 freeaddrinfo(res0); 638 639 return socks; 640 } 641 642 /* UID lookup wrapper. */ 643 static int 644 ident_getuid(struct sockaddr_storage *ss, socklen_t len, 645 struct sockaddr *proxy, uid_t *uid) 646 { 647 int rc; 648 649 rc = sysctl_getuid(ss, len, uid); 650 if (rc == -1 && proxy != NULL) 651 rc = sysctl_proxy_getuid(ss, proxy, uid); 652 653 return rc; 654 } 655 656 /* Try to get the UID of the connection owner using sysctl. */ 657 static int 658 sysctl_getuid(struct sockaddr_storage *ss, socklen_t len, uid_t *uid) 659 { 660 int mib[4]; 661 uid_t myuid; 662 size_t uidlen; 663 664 uidlen = sizeof(myuid); 665 666 mib[0] = CTL_NET; 667 mib[1] = ss->ss_family; 668 mib[2] = IPPROTO_TCP; 669 mib[3] = TCPCTL_IDENT; 670 671 if (sysctl(mib, sizeof(mib)/ sizeof(int), &myuid, &uidlen, ss, len) < 0) 672 return -1; 673 *uid = myuid; 674 675 return 0; 676 } 677 678 /* Try to get the UID of the connection owner using sysctl (proxy version). */ 679 static int 680 sysctl_proxy_getuid(struct sockaddr_storage *ss, struct sockaddr *proxy, 681 uid_t *uid) 682 { 683 struct sockaddr_storage new[2]; 684 int rc, name[CTL_MAXNAME]; 685 size_t i; 686 struct kinfo_pcb *kp; 687 size_t sz, len; 688 const char *list; 689 690 rc = -1; 691 sz = CTL_MAXNAME; 692 list = NULL; 693 694 /* Retrieve a list of sockets. */ 695 switch (ss[0].ss_family) { 696 case AF_INET: 697 /* We only accept queries from the proxy. */ 698 if (in_hosteq(satosin(&ss[0])->sin_addr, 699 satosin(proxy)->sin_addr)) 700 list = "net.inet.tcp.pcblist"; 701 break; 702 case AF_INET6: 703 /* We only accept queries from the proxy. */ 704 if (IN6_ARE_ADDR_EQUAL(&satosin6(&ss[0])->sin6_addr, 705 &satosin6(proxy)->sin6_addr)) 706 list = "net.inet6.tcp.pcblist"; 707 break; 708 default: 709 maybe_syslog(LOG_ERR, "Unsupported protocol for proxy (no. %d)", 710 ss[0].ss_family); 711 } 712 if (list != NULL) 713 rc = sysctlnametomib(list, &name[0], &sz); 714 if (rc == -1) 715 return -1; 716 len = sz; 717 718 name[len++] = PCB_ALL; 719 name[len++] = 0; 720 name[len++] = sizeof(struct kinfo_pcb); 721 name[len++] = INT_MAX; 722 723 kp = NULL; 724 sz = 0; 725 do { 726 rc = sysctl(&name[0], len, kp, &sz, NULL, 0); 727 if (rc == -1 && errno != ENOMEM) 728 return -1; 729 if (kp == NULL) { 730 kp = malloc(sz); 731 rc = -1; 732 } 733 if (kp == NULL) 734 return -1; 735 } while (rc == -1); 736 737 rc = -1; 738 /* 739 * Walk through the list of sockets and try to find a match. 740 * We don't know who has sent the query (we only know that the 741 * proxy has forwarded to us) so just try to match the ports and 742 * the local address. 743 */ 744 for (i = 0; i < sz / sizeof(struct kinfo_pcb); i++) { 745 switch (ss[0].ss_family) { 746 case AF_INET: 747 /* Foreign and local ports must match. */ 748 if (satosin(&ss[0])->sin_port != 749 satosin(&kp[i].ki_src)->sin_port) 750 continue; 751 if (satosin(&ss[1])->sin_port != 752 satosin(&kp[i].ki_dst)->sin_port) 753 continue; 754 /* Foreign address may not match proxy address. */ 755 if (in_hosteq(satosin(proxy)->sin_addr, 756 satosin(&kp[i].ki_dst)->sin_addr)) 757 continue; 758 /* Local addresses must match. */ 759 if (!in_hosteq(satosin(&ss[1])->sin_addr, 760 satosin(&kp[i].ki_src)->sin_addr)) 761 continue; 762 break; 763 case AF_INET6: 764 /* Foreign and local ports must match. */ 765 if (satosin6(&ss[0])->sin6_port != 766 satosin6(&kp[i].ki_src)->sin6_port) 767 continue; 768 if (satosin6(&ss[1])->sin6_port != 769 satosin6(&kp[i].ki_dst)->sin6_port) 770 continue; 771 /* Foreign address may not match proxy address. */ 772 if (IN6_ARE_ADDR_EQUAL(&satosin6(proxy)->sin6_addr, 773 &satosin6(&kp[i].ki_dst)->sin6_addr)) 774 continue; 775 /* Local addresses must match. */ 776 if (!IN6_ARE_ADDR_EQUAL(&satosin6(&ss[1])->sin6_addr, 777 &satosin6(&kp[i].ki_src)->sin6_addr)) 778 continue; 779 break; 780 } 781 782 /* 783 * We have found the foreign address, copy it to a new 784 * struct and retrieve the UID of the connection owner. 785 */ 786 (void)memcpy(&new[0], &kp[i].ki_dst, kp[i].ki_dst.sa_len); 787 (void)memcpy(&new[1], &kp[i].ki_src, kp[i].ki_src.sa_len); 788 789 rc = sysctl_getuid(new, sizeof(new), uid); 790 791 /* Done. */ 792 break; 793 } 794 795 free(kp); 796 return rc; 797 } 798 799 /* Forward ident queries. Returns 1 when succesful, or zero if not. */ 800 static int 801 forward(int fd, struct sockaddr *nat_addr, int nat_lport, int fport, int lport) 802 { 803 char buf[BUFSIZ], reply[BUFSIZ], *p; 804 ssize_t n; 805 int sock; 806 807 /* Connect to the NAT host. */ 808 sock = socket(nat_addr->sa_family, SOCK_STREAM, 0); 809 if (sock < 0) { 810 maybe_syslog(LOG_ERR, "socket: %m"); 811 return 0; 812 } 813 if (connect(sock, nat_addr, nat_addr->sa_len) < 0) { 814 maybe_syslog(LOG_ERR, "Can't connect to %s: %m", 815 gethost(nat_addr)); 816 (void)close(sock); 817 return 0; 818 } 819 820 /* 821 * Send the ident query to the NAT host, but use as local port 822 * the port of the NAT host. 823 */ 824 (void)snprintf(buf, sizeof(buf), "%d , %d\r\n", fport, nat_lport); 825 if (send(sock, buf, strlen(buf), 0) < 0) { 826 maybe_syslog(LOG_ERR, "send: %m"); 827 (void)close(sock); 828 return 0; 829 } 830 831 /* Read the reply from the NAT host. */ 832 if ((n = recv(sock, reply, sizeof(reply) - 1, 0)) < 0) { 833 maybe_syslog(LOG_ERR, "recv: %m"); 834 (void)close(sock); 835 return 0; 836 } else if (n == 0) { 837 maybe_syslog(LOG_NOTICE, "recv: EOF"); 838 (void)close(sock); 839 return 0; 840 } 841 reply[n] = '\0'; 842 if (dflag) 843 maybe_syslog(LOG_ERR, "Replied %s", reply); 844 (void)close(sock); 845 846 /* Extract everything after the port specs from the ident reply. */ 847 for (p = reply; *p != '\0' && *p != ':'; p++) 848 continue; 849 if (*p == '\0' || *++p == '\0') { 850 maybe_syslog(LOG_ERR, "Malformed ident reply from %s", 851 gethost(nat_addr)); 852 return 0; 853 } 854 /* Build reply for the requesting host, use the original local port. */ 855 (void)snprintf(buf, sizeof(buf), "%d,%d:%s", lport, fport, p); 856 857 /* Send the reply from the NAT host back to the requesting host. */ 858 if (send(fd, buf, strlen(buf), 0) < 0) { 859 maybe_syslog(LOG_ERR, "send: %m"); 860 return 0; 861 } 862 863 return 1; 864 } 865 866 /* Check if a .noident file exists in the user home directory. */ 867 static int 868 check_noident(const char *homedir) 869 { 870 struct stat sb; 871 char *path; 872 int ret; 873 874 if (homedir == NULL) 875 return 0; 876 if (asprintf(&path, "%s/.noident", homedir) < 0) 877 return 0; 878 ret = stat(path, &sb); 879 880 free(path); 881 return (ret == 0); 882 } 883 884 /* 885 * Check if a .ident file exists in the user home directory and 886 * return the contents of that file. 887 */ 888 static int 889 check_userident(const char *homedir, char *username, size_t len) 890 { 891 struct stat sb; 892 char *path, *p; 893 ssize_t n; 894 int fd; 895 896 if (len == 0 || homedir == NULL) 897 return 0; 898 if (asprintf(&path, "%s/.ident", homedir) < 0) 899 return 0; 900 if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_NOFOLLOW, 0)) < 0) { 901 free(path); 902 return 0; 903 } 904 if (fstat(fd, &sb) < 0 || !S_ISREG(sb.st_mode)) { 905 (void)close(fd); 906 free(path); 907 return 0; 908 } 909 if ((n = read(fd, username, len - 1)) < 1) { 910 (void)close(fd); 911 free(path); 912 return 0; 913 } 914 username[n] = '\0'; 915 916 if ((p = strpbrk(username, "\r\n")) != NULL) 917 *p = '\0'; 918 919 (void)close(fd); 920 free(path); 921 return 1; 922 } 923 924 /* Generate a random string. */ 925 static void 926 random_string(char *str, size_t len) 927 { 928 static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890"; 929 char *p; 930 931 if (len == 0) 932 return; 933 for (p = str; len > 1; len--) 934 *p++ = chars[arc4random() % (sizeof(chars) - 1)]; 935 *p = '\0'; 936 } 937 938 /* Change the output format. */ 939 static int 940 change_format(const char *format, struct passwd *pw, char *dest, size_t len) 941 { 942 struct group *gr; 943 const char *cp; 944 char **gmp; 945 size_t bp; 946 947 if (len == 0 || ((gr = getgrgid(pw->pw_gid)) == NULL)) 948 return 0; 949 950 for (bp = 0, cp = format; *cp != '\0' && bp < len - 1; cp++) { 951 if (*cp != '%') { 952 dest[bp++] = *cp; 953 continue; 954 } 955 if (*++cp == '\0') 956 break; 957 switch (*cp) { 958 case 'u': 959 (void)snprintf(&dest[bp], len - bp, "%s", pw->pw_name); 960 break; 961 case 'U': 962 (void)snprintf(&dest[bp], len - bp, "%d", pw->pw_uid); 963 break; 964 case 'g': 965 (void)snprintf(&dest[bp], len - bp, "%s", gr->gr_name); 966 break; 967 case 'G': 968 (void)snprintf(&dest[bp], len - bp, "%d", gr->gr_gid); 969 break; 970 case 'l': 971 (void)snprintf(&dest[bp], len - bp, "%s", gr->gr_name); 972 bp += strlen(&dest[bp]); 973 if (bp >= len) 974 break; 975 setgrent(); 976 while ((gr = getgrent()) != NULL) { 977 if (gr->gr_gid == pw->pw_gid) 978 continue; 979 for (gmp = gr->gr_mem; *gmp && **gmp; gmp++) { 980 if (strcmp(*gmp, pw->pw_name) == 0) { 981 (void)snprintf(&dest[bp], 982 len - bp, ",%s", 983 gr->gr_name); 984 bp += strlen(&dest[bp]); 985 break; 986 } 987 } 988 if (bp >= len) 989 break; 990 } 991 endgrent(); 992 break; 993 case 'L': 994 (void)snprintf(&dest[bp], len - bp, "%u", gr->gr_gid); 995 bp += strlen(&dest[bp]); 996 if (bp >= len) 997 break; 998 setgrent(); 999 while ((gr = getgrent()) != NULL) { 1000 if (gr->gr_gid == pw->pw_gid) 1001 continue; 1002 for (gmp = gr->gr_mem; *gmp && **gmp; gmp++) { 1003 if (strcmp(*gmp, pw->pw_name) == 0) { 1004 (void)snprintf(&dest[bp], 1005 len - bp, ",%u", 1006 gr->gr_gid); 1007 bp += strlen(&dest[bp]); 1008 break; 1009 } 1010 } 1011 if (bp >= len) 1012 break; 1013 } 1014 endgrent(); 1015 break; 1016 default: 1017 dest[bp] = *cp; 1018 dest[bp+1] = '\0'; 1019 break; 1020 } 1021 bp += strlen(&dest[bp]); 1022 } 1023 dest[bp] = '\0'; 1024 1025 return 1; 1026 } 1027 1028 /* Just exit when we caught SIGALRM. */ 1029 static void 1030 timeout_handler(int __unused s) 1031 { 1032 maybe_syslog(LOG_INFO, "Timeout for request, closing connection..."); 1033 exit(EXIT_FAILURE); 1034 } 1035 1036 /* Report error message string through syslog and quit. */ 1037 static void 1038 fatal(const char *func) 1039 { 1040 maybe_syslog(LOG_ERR, "%s: %m", func); 1041 exit(EXIT_FAILURE); 1042 } 1043 1044 /* 1045 * Report an error through syslog and/or stderr and quit. Only used when 1046 * running identd in the background and when it isn't a daemon yet. 1047 */ 1048 static void 1049 die(const char *message, ...) 1050 { 1051 va_list ap; 1052 1053 if (bflag) { 1054 va_start(ap, message); 1055 vwarnx(message, ap); 1056 va_end(ap); 1057 } 1058 1059 if (lflag) { 1060 va_start(ap, message); 1061 vsyslog(LOG_ERR, message, ap); 1062 va_end(ap); 1063 } 1064 1065 exit(EXIT_FAILURE); 1066 } 1067 1068 /* Log using syslog, but only if enabled with the -l flag. */ 1069 void 1070 maybe_syslog(int priority, const char *message, ...) 1071 { 1072 va_list ap; 1073 1074 if (lflag) { 1075 va_start(ap, message); 1076 vsyslog(priority, message, ap); 1077 va_end(ap); 1078 } 1079 } 1080