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