1: /* 2: ** identd.c A TCP/IP link identification protocol server 3: ** 4: ** This program is in the public domain and may be used freely by anyone 5: ** who wants to. 6: ** 7: ** Last update: 7 Oct 1993 8: ** 9: ** Please send bug fixes/bug reports to: Peter Eriksson <pen@lysator.liu.se> 10: */ 11: 12: #if !defined(__STDC__) 13: #define void int 14: #endif 15: 16: #if defined(IRIX) || defined(SVR4) || defined(NeXT) || (defined(sco) && sco >= 42) || defined(_AIX4) || defined(__FreeBSD__) || defined(ultrix) 17: # define SIGRETURN_TYPE void 18: # define SIGRETURN_TYPE_IS_VOID 19: #else 20: # define SIGRETURN_TYPE int 21: #endif 22: 23: #ifdef SVR4 24: # define STRNET 25: #endif 26: 27: #ifdef NeXT31 28: # include <libc.h> 29: #endif 30: 31: #ifdef sco 32: # define USE_SIGALARM 33: #endif 34: 35: #include <stdio.h> 36: #include <ctype.h> 37: #include <errno.h> 38: #include <netdb.h> 39: #include <signal.h> 40: #include <fcntl.h> 41: 42: #include <sys/types.h> 43: #include <sys/param.h> 44: #include <sys/ioctl.h> 45: #include <sys/socket.h> 46: #ifndef _AUX_SOURCE 47: # include <sys/file.h> 48: #endif 49: #include <sys/time.h> 50: #include <sys/wait.h> 51: 52: #include <pwd.h> 53: #include <grp.h> 54: 55: #include <netinet/in.h> 56: 57: #ifndef HPUX7 58: # include <arpa/inet.h> 59: #endif 60: 61: #ifdef _AIX32 62: # include <sys/select.h> 63: #endif 64: 65: #if defined(MIPS) || defined(BSD43) 66: extern int errno; 67: #endif 68: 69: #if defined(SOLARIS) || defined(__FreeBSD__) 70: # include <unistd.h> 71: # include <stdlib.h> 72: # include <string.h> 73: #endif 74: 75: #include "identd.h" 76: #include "error.h" 77: #include "paths.h" 78: #include "crypto.h" 79: 80: /* Antique unixes do not have these things defined... */ 81: #ifndef FD_SETSIZE 82: # define FD_SETSIZE 256 83: #endif 84: 85: #ifndef FD_SET 86: # ifndef NFDBITS 87: # define NFDBITS (sizeof(int) * NBBY) /* bits per mask */ 88: # endif 89: # define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 90: #endif 91: 92: #ifndef FD_ZERO 93: # define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 94: #endif 95: 96: 97: extern void *calloc(); 98: extern void *malloc(); 99: 100: 101: char *path_unix = NULL; 102: char *path_kmem = NULL; 103: 104: int verbose_flag = 0; 105: int debug_flag = 0; 106: int syslog_flag = 0; 107: int multi_flag = 0; 108: int other_flag = 0; 109: int unknown_flag = 0; 110: int noident_flag = 0; 111: int crypto_flag = 0; 112: 113: int lport = 0; 114: int fport = 0; 115: 116: char *charset_name = NULL; 117: char *indirect_host = NULL; 118: char *indirect_password = NULL; 119: 120: #ifdef ALLOW_FORMAT 121: int format_flag = 0; 122: char *format = "%u"; 123: #endif 124: 125: static int child_pid; 126: 127: #ifdef LOG_DAEMON 128: static int syslog_facility = LOG_DAEMON; 129: #endif 130: 131: /* 132: ** The structure passing convention for GCC is incompatible with 133: ** Suns own C compiler, so we define our own inet_ntoa() function. 134: ** (This should only affect GCC version 1 I think, a well, this works 135: ** for version 2 also so why bother.. :-) 136: */ 137: #if defined(__GNUC__) && defined(__sparc__) && !defined(NeXT) 138: 139: #ifdef inet_ntoa 140: #undef inet_ntoa 141: #endif 142: 143: char *inet_ntoa(ad) 144: struct in_addr ad; 145: { 146: unsigned long int s_ad; 147: int a, b, c, d; 148: static char addr[20]; 149: 150: s_ad = ad.s_addr; 151: d = s_ad % 256; 152: s_ad /= 256; 153: c = s_ad % 256; 154: s_ad /= 256; 155: b = s_ad % 256; 156: a = s_ad / 256; 157: sprintf(addr, "%d.%d.%d.%d", a, b, c, d); 158: 159: return addr; 160: } 161: #endif 162: 163: static int comparemem(vp1, vp2, len) 164: void *vp1; 165: void *vp2; 166: int len; 167: { 168: unsigned char *p1 = (unsigned char *) vp1; 169: unsigned char *p2 = (unsigned char *) vp2; 170: int c; 171: 172: while (len-- > 0) 173: if ((c = (int) *p1++ - (int) *p2++) != 0) 174: return c; 175: 176: return 0; 177: } 178: 179: /* 180: ** Return the name of the connecting host, or the IP number as a string. 181: */ 182: char *gethost(addr) 183: struct in_addr *addr; 184: { 185: int i; 186: struct hostent *hp; 187: 188: 189: hp = gethostbyaddr((char *) addr, sizeof(struct in_addr), AF_INET); 190: if (hp) 191: { 192: /* Found a IP -> Name match, now try the reverse for security reasons */ 193: hp = gethostbyname(hp->h_name); 194: if (hp) 195: #ifdef h_addr 196: for (i = 0; hp->h_addr_list[i]; i++) 197: if (comparemem(hp->h_addr_list[i], 198: (unsigned char *) addr, 199: sizeof(struct in_addr)) == 0) 200: return (char *) hp->h_name; 201: #else 202: if (comparemem(hp->h_addr, addr, sizeof(struct in_addr)) == 0) 203: return hp->h_name; 204: #endif 205: } 206: 207: return inet_ntoa(*addr); 208: } 209: 210: #ifdef USE_SIGALARM 211: /* 212: ** Exit cleanly after our time's up. 213: */ 214: static SIGRETURN_TYPE 215: alarm_handler(int s) 216: { 217: if (syslog_flag) 218: syslog(LOG_DEBUG, "SIGALRM triggered, exiting"); 219: 220: exit(0); 221: } 222: #endif 223: 224: 225: #if !defined(hpux) && !defined(__hpux) && !defined(SVR4) && \ 226: !defined(_CRAY) && !defined(sco) && !defined(LINUX) 227: /* 228: ** This is used to clean up zombie child processes 229: ** if the -w or -b options are used. 230: */ 231: static SIGRETURN_TYPE 232: child_handler() 233: { 234: #if defined(NeXT) || (defined(__sgi) && defined(__SVR3)) 235: union wait status; 236: #else 237: int status; 238: #endif 239: 240: while (wait3(&status, WNOHANG, NULL) > 0) 241: ; 242: 243: #ifndef SIGRETURN_TYPE_IS_VOID 244: return 0; 245: #endif 246: } 247: #endif 248: 249: 250: char *clearmem(vbp, len) 251: void *vbp; 252: int len; 253: { 254: char *bp = (char *) vbp; 255: char *cp; 256: 257: cp = bp; 258: while (len-- > 0) 259: *cp++ = 0; 260: 261: return bp; 262: } 263: 264: 265: /* 266: ** Main entry point into this daemon 267: */ 268: int main(argc,argv) 269: int argc; 270: char *argv[]; 271: { 272: int i, len; 273: struct sockaddr_in sin; 274: struct in_addr laddr, faddr; 275: #ifndef USE_SIGALARM 276: struct timeval tv; 277: #endif 278: int one = 1; 279: 280: int background_flag = 0; 281: int timeout = 0; 282: char *portno = "113"; 283: char *bind_address = NULL; 284: int set_uid = 0; 285: int set_gid = 0; 286: int inhibit_default_config = 0; 287: int opt_count = 0; /* Count of option flags */ 288: 289: #ifdef __convex__ 290: argc--; /* get rid of extra argument passed by inetd */ 291: #endif 292: 293: 294: if (isatty(0)) 295: background_flag = 1; 296: 297: /* 298: ** Prescan the arguments for "-f<config-file>" switches 299: */ 300: inhibit_default_config = 0; 301: for (i = 1; i < argc && argv[i][0] == '-'; i++) 302: if (argv[i][1] == 'f') 303: inhibit_default_config = 1; 304: 305: /* 306: ** Parse the default config file - if it exists 307: */ 308: if (!inhibit_default_config) 309: parse_config(NULL, 1); 310: 311: /* 312: ** Parse the command line arguments 313: */ 314: for (i = 1; i < argc && argv[i][0] == '-'; i++) { 315: opt_count++; 316: switch (argv[i][1]) 317: { 318: case 'b': /* Start as standalone daemon */ 319: background_flag = 1; 320: break; 321: 322: case 'w': /* Start from Inetd, wait mode */ 323: background_flag = 2; 324: break; 325: 326: case 'i': /* Start from Inetd, nowait mode */ 327: background_flag = 0; 328: break; 329: 330: case 't': 331: timeout = atoi(argv[i]+2); 332: break; 333: 334: case 'p': 335: portno = argv[i]+2; 336: break; 337: 338: case 'a': 339: bind_address = argv[i]+2; 340: break; 341: 342: case 'u': 343: if (isdigit(argv[i][2])) 344: set_uid = atoi(argv[i]+2); 345: else 346: { 347: struct passwd *pwd; 348: 349: pwd = getpwnam(argv[i]+2); 350: if (!pwd) 351: ERROR1("no such user (%s) for -u option", argv[i]+2); 352: else 353: { 354: set_uid = pwd->pw_uid; 355: set_gid = pwd->pw_gid; 356: } 357: } 358: break; 359: 360: case 'g': 361: if (isdigit(argv[i][2])) 362: set_gid = atoi(argv[i]+2); 363: else 364: { 365: struct group *grp; 366: 367: grp = getgrnam(argv[i]+2); 368: if (!grp) 369: ERROR1("no such group (%s) for -g option", argv[i]+2); 370: else 371: set_gid = grp->gr_gid; 372: } 373: break; 374: 375: case 'c': 376: charset_name = argv[i]+2; 377: break; 378: 379: case 'r': 380: indirect_host = argv[i]+2; 381: break; 382: 383: case 'l': /* Use the Syslog daemon for logging */ 384: syslog_flag++; 385: break; 386: 387: case 'o': 388: other_flag = 1; 389: break; 390: 391: case 'e': 392: unknown_flag = 1; 393: break; 394: 395: case 'V': /* Give version of this daemon */ 396: printf("[in.identd, version %s]\r\n", version); 397: exit(0); 398: break; 399: 400: case 'v': /* Be verbose */ 401: verbose_flag++; 402: break; 403: 404: case 'd': /* Enable debugging */ 405: debug_flag++; 406: break; 407: 408: case 'm': /* Enable multiline queries */ 409: multi_flag++; 410: break; 411: 412: case 'N': /* Enable users ".noident" files */ 413: noident_flag++; 414: break; 415: 416: #ifdef INCLUDE_CRYPT 417: case 'C': /* Enable encryption. */ 418: { 419: FILE *keyfile; 420: 421: if (argv[i][2]) 422: keyfile = fopen(argv[i]+2, "r"); 423: else 424: keyfile = fopen(PATH_DESKEY, "r"); 425: 426: if (keyfile == NULL) 427: { 428: ERROR("cannot open key file for option -C"); 429: } 430: else 431: { 432: char buf[1024]; 433: 434: if (fgets(buf, 1024, keyfile) == NULL) 435: { 436: ERROR("cannot read key file for option -C"); 437: } 438: else 439: { 440: init_encryption(buf); 441: crypto_flag++; 442: } 443: fclose(keyfile); 444: } 445: } 446: break; 447: #endif 448: 449: #ifdef ALLOW_FORMAT 450: case 'n': /* Compatibility flag - just send the user number */ 451: format_flag = 1; 452: format = "%U"; 453: break; 454: 455: case 'F': /* Output format */ 456: format_flag = 1; 457: format = argv[i]+2; 458: break; 459: #endif 460: 461: default: 462: ERROR1("Bad option %s", argv[i]); 463: break; 464: } 465: } 466: 467: #if defined(_AUX_SOURCE) || defined (SUNOS35) 468: /* A/UX 2.0* & SunOS 3.5 calls us with an argument XXXXXXXX.YYYY 469: ** where XXXXXXXXX is the hexadecimal version of the callers 470: ** IP number, and YYYY is the port/socket or something. 471: ** It seems to be impossible to pass arguments to a daemon started 472: ** by inetd. 473: ** 474: ** Just in case it is started from something else, then we only 475: ** skip the argument if no option flags have been seen. 476: */ 477: if (opt_count == 0) 478: argc--; 479: #endif 480: 481: /* 482: ** Path to kernel namelist file specified on command line 483: */ 484: if (i < argc) 485: path_unix = argv[i++]; 486: 487: /* 488: ** Path to kernel memory device specified on command line 489: */ 490: if (i < argc) 491: path_kmem = argv[i++]; 492: 493: 494: if (i < argc) 495: ERROR1("Too many arguments: ignored from %s", argv[i]); 496: 497: 498: /* 499: ** We used to call k_open here. But then the file descriptor 500: ** kd->fd open on /dev/kmem is shared by all child processes. 501: ** From the fork(2) man page: 502: ** o The child process has its own copy of the parent's descriptors. These 503: ** descriptors reference the same underlying objects. For instance, file 504: ** pointers in file objects are shared between the child and the parent 505: ** so that an lseek(2) on a descriptor in the child process can affect a 506: ** subsequent read(2) or write(2) by the parent. 507: ** Thus with concurrent (simultaneous) identd client processes, 508: ** they step on each other's toes when they use kvm_read. 509: ** 510: ** Calling k_open here was a mistake for another reason too: we 511: ** did not yet honor -u and -g options. Presumably we are 512: ** running as root (unless the in.identd file is setuid), and 513: ** then we can open kmem regardless of -u and -g values. 514: ** 515: ** 516: ** Open the kernel memory device and read the nlist table 517: ** 518: ** if (k_open() < 0) 519: ** ERROR("main: k_open"); 520: */ 521: 522: /* 523: ** Do the special handling needed for the "-b" flag 524: */ 525: if (background_flag == 1) 526: { 527: struct sockaddr_in addr; 528: struct servent *sp; 529: int fd; 530: 531: 532: if (!debug_flag) 533: { 534: if (fork()) 535: exit(0); 536: 537: close(0); 538: close(1); 539: close(2); 540: 541: if (fork()) 542: exit(0); 543: } 544: 545: fd = socket(AF_INET, SOCK_STREAM, 0); 546: if (fd == -1) 547: ERROR("main: socket"); 548: 549: if (fd != 0) 550: dup2(fd, 0); 551: 552: clearmem(&addr, sizeof(addr)); 553: 554: addr.sin_family = AF_INET; 555: if (bind_address == NULL) 556: addr.sin_addr.s_addr = htonl(INADDR_ANY); 557: else 558: { 559: if (isdigit(bind_address[0])) 560: addr.sin_addr.s_addr = inet_addr(bind_address); 561: else 562: { 563: struct hostent *hp; 564: 565: hp = gethostbyname(bind_address); 566: if (!hp) 567: ERROR1("no such address (%s) for -a switch", bind_address); 568: 569: /* This is ugly, should use memcpy() or bcopy() but... */ 570: addr.sin_addr.s_addr = * (unsigned long *) (hp->h_addr); 571: } 572: } 573: 574: if (isdigit(portno[0])) 575: addr.sin_port = htons(atoi(portno)); 576: else 577: { 578: sp = getservbyname(portno, "tcp"); 579: if (sp == NULL) 580: ERROR1("main: getservbyname: %s", portno); 581: addr.sin_port = sp->s_port; 582: } 583: 584: #ifdef SO_REUSEADDR 585: setsockopt(0, SOL_SOCKET, SO_REUSEADDR, (void *) &one, sizeof(one)); 586: #endif 587: 588: if (bind(0, (struct sockaddr *) &addr, sizeof(addr)) < 0) 589: ERROR("main: bind"); 590: } 591: 592: if (background_flag) 593: { 594: if (listen(0, 3) < 0) 595: ERROR("main: listen"); 596: } 597: 598: if (set_gid) 599: { 600: if (setgid(set_gid) == -1) 601: ERROR("main: setgid"); 602: /* Call me paranoid... PSz */ 603: if (getgid() != set_gid) 604: ERROR2("main: setgid failed: wanted %d, got GID %d", set_gid, getgid()); 605: if (getegid() != set_gid) 606: ERROR2("main: setgid failed: wanted %d, got EGID %d", set_gid, getegid()); 607: } 608: 609: if (set_uid) 610: { 611: if (setuid(set_uid) == -1) 612: ERROR("main: setuid"); 613: /* Call me paranoid... PSz */ 614: if (getuid() != set_uid) 615: ERROR2("main: setuid failed: wanted %d, got UID %d", set_uid, getuid()); 616: if (geteuid() != set_uid) 617: ERROR2("main: setuid failed: wanted %d, got EUID %d", set_uid, geteuid()); 618: } 619: 620: /* 621: ** Do some special handling if the "-b" or "-w" flags are used 622: */ 623: if (background_flag) 624: { 625: int nfds, fd; 626: fd_set read_set; 627: struct sockaddr sad; 628: int sadlen; 629: 630: 631: /* 632: ** Set up the SIGCHLD signal child termination handler so 633: ** that we can avoid zombie processes hanging around and 634: ** handle childs terminating before being able to complete the 635: ** handshake. 636: */ 637: #if (defined(SVR4) || defined(hpux) || defined(__hpux) || defined(IRIX) || \ 638: defined(_CRAY) || defined(_AUX_SOURCE)) || defined(sco) || defined(LINUX) 639: signal(SIGCHLD, SIG_IGN); 640: #else 641: signal(SIGCHLD, (SIGRETURN_TYPE (*)()) child_handler); 642: #endif 643: 644: /* 645: ** Loop and dispatch client handling processes 646: */ 647: do 648: { 649: #ifdef USE_SIGALARM 650: /* 651: ** Terminate if we've been idle for 'timeout' seconds 652: */ 653: if (background_flag == 2 && timeout) 654: { 655: signal(SIGALRM, alarm_handler); 656: alarm(timeout); 657: } 658: #endif 659: 660: /* 661: ** Wait for a connection request to occur. 662: ** Ignore EINTR (Interrupted System Call). 663: */ 664: do 665: { 666: FD_ZERO(&read_set); 667: FD_SET(0, &read_set); 668: 669: #ifndef USE_SIGALARM 670: if (timeout) 671: { 672: tv.tv_sec = timeout; 673: tv.tv_usec = 0; 674: #ifdef __hpux 675: nfds = select(FD_SETSIZE, 676: (int *) &read_set, NULL, NULL, &tv); 677: #else 678: nfds = select(FD_SETSIZE, &read_set, NULL, NULL, &tv); 679: #endif 680: } 681: else 682: #endif 683: 684: #ifdef __hpux 685: nfds = select(FD_SETSIZE, (int *) &read_set, NULL, NULL, NULL); 686: #else 687: nfds = select(FD_SETSIZE, &read_set, NULL, NULL, NULL); 688: #endif 689: } while (nfds < 0 && errno == EINTR); 690: 691: /* 692: ** An error occured in select? Just die 693: */ 694: if (nfds < 0) 695: ERROR("main: select"); 696: 697: /* 698: ** Timeout limit reached. Exit nicely 699: */ 700: if (nfds == 0) 701: exit(0); 702: 703: #ifdef USE_SIGALARM 704: /* 705: ** Disable the alarm timeout 706: */ 707: alarm(0); 708: #endif 709: 710: /* 711: ** Accept the new client 712: */ 713: sadlen = sizeof(sad); 714: errno = 0; 715: fd = accept(0, &sad, &sadlen); 716: if (fd == -1) 717: ERROR1("main: accept. errno = %d", errno); 718: 719: /* 720: ** And fork, then close the fd if we are the parent. 721: */ 722: child_pid = fork(); 723: } while (child_pid && (close(fd), 1)); 724: 725: /* 726: ** We are now in child, the parent has returned to "do" above. 727: */ 728: if (dup2(fd, 0) == -1) 729: ERROR("main: dup2: failed fd 0"); 730: 731: if (dup2(fd, 1) == -1) 732: ERROR("main: dup2: failed fd 1"); 733: 734: if (dup2(fd, 2) == -1) 735: ERROR("main: dup2: failed fd 2"); 736: } 737: 738: /* 739: ** Get foreign internet address 740: */ 741: len = sizeof(sin); 742: if (getpeername(0, (struct sockaddr *) &sin, &len) == -1) 743: { 744: /* 745: ** A user has tried to start us from the command line or 746: ** the network link died, in which case this message won't 747: ** reach to other end anyway, so lets give the poor user some 748: ** errors. 749: */ 750: perror("in.identd: getpeername()"); 751: exit(1); 752: } 753: 754: faddr = sin.sin_addr; 755: 756: 757: /* 758: ** Open the connection to the Syslog daemon if requested 759: */ 760: if (syslog_flag) 761: { 762: #ifdef LOG_DAEMON 763: openlog("identd", LOG_PID, syslog_facility); 764: #else 765: openlog("identd", LOG_PID); 766: #endif 767: 768: #ifndef STRONG_LOG 769: syslog(LOG_INFO, "Connection from %s", gethost(&faddr)); 770: #endif 771: } 772: 773: 774: /* 775: ** Get local internet address 776: */ 777: len = sizeof(sin); 778: #ifdef ATTSVR4 779: if (t_getsockname(0, (struct sockaddr *) &sin, &len) == -1) 780: #else 781: if (getsockname(0, (struct sockaddr *) &sin, &len) == -1) 782: #endif 783: { 784: /* 785: ** We can just die here, because if this fails then the 786: ** network has died and we haven't got anyone to return 787: ** errors to. 788: */ 789: exit(1); 790: } 791: laddr = sin.sin_addr; 792: 793: 794: /* 795: ** Get the local/foreign port pair from the luser 796: */ 797: parse(stdin, &laddr, &faddr); 798: 799: exit(0); 800: }