home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-A.06 / NETKIT-A / NetKit-A-0.06 / pidentd-2.2 / src / identd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-29  |  12.8 KB  |  669 lines

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