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