home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume36 / log_tcp / part02 / fromhost.c next >
Encoding:
C/C++ Source or Header  |  1993-03-07  |  8.0 KB  |  310 lines

  1.  /*
  2.   * fromhost() determines the type of connection (datagram, stream), the name
  3.   * and address of the host at the other end of standard input, and the
  4.   * remote user name (if RFC 931 lookups are enabled). A host name of "stdin"
  5.   * is returned if the program is run from a tty. The value "unknown" is
  6.   * returned as a placeholder for information that could not be looked up.
  7.   * All results are in static memory.
  8.   * 
  9.   * The return status is (-1) if the remote host pretends to have someone elses
  10.   * host name, otherwise a zero status is returned.
  11.   * 
  12.   * Diagnostics are reported through syslog(3).
  13.   * 
  14.   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
  15.   */
  16.  
  17. #ifndef lint
  18. static char sccsid[] = "@(#) fromhost.c 1.7 93/03/07 22:47:34";
  19. #endif
  20.  
  21. /* System libraries. */
  22.  
  23. #include <sys/types.h>
  24. #include <sys/param.h>
  25. #include <sys/socket.h>
  26. #include <netinet/in.h>
  27. #include <netdb.h>
  28. #include <stdio.h>
  29. #include <syslog.h>
  30. #include <errno.h>
  31.  
  32. extern char *inet_ntoa();
  33. extern char *strncpy();
  34. extern char *strcpy();
  35.  
  36. /* In case not defined in <sys/param.h>. */
  37.  
  38. #ifndef MAXHOSTNAMELEN
  39. #define MAXHOSTNAMELEN    1024        /* string with host name */
  40. #endif
  41.  
  42. /* Local stuff. */
  43.  
  44. #include "log_tcp.h"
  45.  
  46. /* Forward declarations. */
  47.  
  48. static int matchname();
  49.  
  50. /* The following are to be used in assignment context, not in comparisons. */
  51.  
  52. #define    GOOD    1
  53. #define    BAD    0
  54.  
  55. /* Initially, we know nothing about the origin of the connection. */
  56.  
  57. static struct from_host from_unknown = {
  58.     0,                    /* connected/unconnected */
  59.     FROM_UNKNOWN,            /* remote host name */
  60.     FROM_UNKNOWN,            /* remote host address */
  61.     "",                    /* remote user name */
  62. };
  63.  
  64.  /*
  65.   * With early SunOS 5 versions, recvfrom() does not completely fill in the
  66.   * source address structure when doing a non-destructive read. The following
  67.   * code works around the problem. It does no harm on "normal" systems.
  68.   */
  69.  
  70. #ifdef RECVFROM_BUG
  71.  
  72. static int fix_recvfrom(sock, buf, buflen, flags, from, fromlen)
  73. int     sock;
  74. char   *buf;
  75. int     buflen;
  76. int     flags;
  77. struct sockaddr *from;
  78. int     *fromlen;
  79. {
  80.     int     ret;
  81.  
  82.     /* Assume that both ends of a socket belong to the same address family. */
  83.  
  84.     if ((ret = recvfrom(sock, buf, buflen, flags, from, fromlen)) >= 0) {
  85.     if (from->sa_family == 0) {
  86.         struct sockaddr my_addr;
  87.         int     my_addr_len = sizeof(my_addr);
  88.  
  89.         if (getsockname(0, &my_addr, &my_addr_len)) {
  90.         syslog(LOG_ERR, "getsockname: %m");
  91.         } else {
  92.         from->sa_family = my_addr.sa_family;
  93.         }
  94.     }
  95.     }
  96.     return (ret);
  97. }
  98.  
  99. #define recvfrom fix_recvfrom
  100. #endif
  101.  
  102.  /*
  103.   * The Apollo SR10.3 and some SYSV4 getpeername(2) versions do not return an
  104.   * error in case of a datagram-oriented socket. Instead, they claim that all
  105.   * UDP requests come from address 0.0.0.0. The following code works around
  106.   * the problem. It does no harm on "normal" systems.
  107.   */
  108.  
  109. #ifdef GETPEERNAME_BUG
  110.  
  111. static int fix_getpeername(sock, sa, len)
  112. int     sock;
  113. struct sockaddr *sa;
  114. int    *len;
  115. {
  116.     int     ret;
  117.     struct sockaddr_in *sin = (struct sockaddr_in *) sa;
  118.  
  119.     if ((ret = getpeername(sock, sa, len)) >= 0
  120.     && sa->sa_family == AF_INET
  121.     && sin->sin_addr.s_addr == 0) {
  122.     errno = ENOTCONN;
  123.     return (-1);
  124.     } else {
  125.     return (ret);
  126.     }
  127. }
  128.  
  129. #define    getpeername    fix_getpeername
  130. #endif
  131.  
  132. /* fromhost - find out what is at the other end of standard input */
  133.  
  134. int     fromhost(f)
  135. struct from_host *f;
  136. {
  137.     static struct sockaddr sa;
  138.     struct sockaddr_in *sin = (struct sockaddr_in *) (&sa);
  139.     struct hostent *hp;
  140.     int     length = sizeof(sa);
  141.     char    buf[BUFSIZ];
  142.     static char addr_buf[FROM_ADDRLEN];
  143.     static char name_buf[MAXHOSTNAMELEN];
  144.  
  145.     /*
  146.      * There are so many results and so many early returns that it seems
  147.      * safest to first initialize all results to UNKNOWN.
  148.      */
  149.  
  150.     *f = from_unknown;
  151.  
  152.     /*
  153.      * Look up the remote host address. Hal R. Brand <BRAND@addvax.llnl.gov>
  154.      * suggested how to get the remote host info in case of UDP connections:
  155.      * peek at the first message without actually looking at its contents.
  156.      */
  157.  
  158.     if (getpeername(0, &sa, &length) >= 0) {    /* assume TCP request */
  159.     f->sock_type = FROM_CONNECTED;
  160.     } else {
  161.     switch (errno) {
  162.     default:
  163.         if (isatty(0))            /* stdin is not a socket */
  164.         f->name = "stdin";
  165.         else
  166.         syslog(LOG_ERR, "getpeername: %m");    /* other, punt */
  167.         return (0);
  168.     case ENOTCONN:                /* assume UDP request */
  169.         length = sizeof(sa);
  170.         if (recvfrom(0, buf, sizeof(buf), MSG_PEEK, &sa, &length) < 0) {
  171.         syslog(LOG_ERR, "recvfrom: %m");
  172.         return (0);
  173.         }
  174. #ifdef really_paranoid
  175.         memset(buf, 0 sizeof(buf));
  176. #endif
  177.         f->sock_type = FROM_UNCONNECTED;
  178.         break;
  179.     }
  180.     }
  181.  
  182.     /*
  183.      * At present, we can only deal with the AF_INET address family. Some
  184.      * implementations of System V religion never fill in the address family
  185.      * field in case of UDP connections. If that happens, you may want to
  186.      * take the chance and assume that we're dealing with TCP/IP anyway.
  187.      */
  188.  
  189. #ifdef ADDRESS_FAMILY_BUG
  190.     if (sa.sa_family == 0)
  191.     sa.sa_family = AF_INET;
  192. #endif
  193.     if (sa.sa_family != AF_INET) {
  194.     syslog(LOG_ERR, "unexpected address family %ld", (long) sa.sa_family);
  195.     return (0);
  196.     }
  197.     /* Save the host address. A later inet_ntoa() call may clobber it. */
  198.  
  199.     f->sin = sin;
  200.     f->addr = strcpy(addr_buf, inet_ntoa(sin->sin_addr));
  201.  
  202.     /* Look up the remote user name. Does not work for UDP services. */
  203.  
  204. #if defined(RFC931) && !defined(USER_AT_HOST) && !defined(RFC931_OPTION)
  205.     if (f->sock_type == FROM_CONNECTED)
  206.     f->user = rfc931_name(sin);
  207. #endif
  208.  
  209.     /* Look up the remote host name. */
  210.  
  211.     if ((hp = gethostbyaddr((char *) &sin->sin_addr,
  212.                 sizeof(sin->sin_addr),
  213.                 AF_INET)) == 0) {
  214.     return (0);
  215.     }
  216.     /* Save the host name. A later gethostbyxxx() call may clobber it. */
  217.  
  218.     f->name = strncpy(name_buf, hp->h_name, sizeof(name_buf) - 1);
  219.     name_buf[sizeof(name_buf) - 1] = 0;
  220.  
  221.     /*
  222.      * Verify that the host name does not belong to someone else. If host
  223.      * name verification fails, pretend that the host name lookup failed.
  224.      */
  225.  
  226.     if (matchname(f->name, sin->sin_addr)) {
  227.     return (0);
  228.     } else {
  229.     f->name = FROM_UNKNOWN;
  230.     return (-1);                /* verification failed */
  231.     }
  232. }
  233.  
  234. /* matchname - determine if host name matches IP address */
  235.  
  236. static int matchname(remotehost, addr)
  237. char   *remotehost;
  238. struct in_addr addr;
  239. {
  240.     struct hostent *hp;
  241.     int     i;
  242.  
  243.     if ((hp = gethostbyname(remotehost)) == 0) {
  244.  
  245.     /*
  246.      * Unable to verify that the host name matches the address. This may
  247.      * be a transient problem or a botched name server setup. We decide
  248.      * to play safe.
  249.      */
  250.  
  251.     syslog(LOG_ERR, "gethostbyname(%s): lookup failure", remotehost);
  252.     return (BAD);
  253.  
  254.     } else {
  255.  
  256.     /*
  257.      * Make sure that gethostbyname() returns the "correct" host name.
  258.      * Unfortunately, gethostbyname("localhost") sometimes yields
  259.      * "localhost.domain". Since the latter host name comes from the
  260.      * local DNS, we just have to trust it (all bets are off if the local
  261.      * DNS is perverted). We always check the address list, though.
  262.      */
  263.  
  264.     if (strcasecmp(remotehost, hp->h_name)
  265.         && strcasecmp(remotehost, "localhost")) {
  266.         syslog(LOG_ERR, "host name/name mismatch: %s != %s",
  267.            remotehost, hp->h_name);
  268.         return (BAD);
  269.     }
  270.     /* Look up the host address in the address list we just got. */
  271.  
  272.     for (i = 0; hp->h_addr_list[i]; i++) {
  273.         if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0)
  274.         return (GOOD);
  275.     }
  276.  
  277.     /*
  278.      * The host name does not map to the original host address. Perhaps
  279.      * someone has compromised a name server. More likely someone botched
  280.      * it, but that could be dangerous, too.
  281.      */
  282.  
  283.     syslog(LOG_ERR, "host name/address mismatch: %s != %s",
  284.            inet_ntoa(addr), hp->h_name);
  285.     return (BAD);
  286.     }
  287. }
  288.  
  289. #ifdef TEST
  290.  
  291. /* Code for stand-alone testing. */
  292.  
  293. main(argc, argv)
  294. int     argc;
  295. char  **argv;
  296. {
  297.     struct from_host from;
  298.  
  299. #ifdef LOG_MAIL
  300.     (void) openlog(argv[0], LOG_PID, FACILITY);
  301. #else
  302.     (void) openlog(argv[0], LOG_PID);
  303. #endif
  304.     (void) fromhost(&from);
  305.     printf("%s\n", hosts_info(&from));
  306.     return (0);
  307. }
  308.  
  309. #endif
  310.