home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume39 / tcp_wrappers / part03 / socket.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-29  |  7.3 KB  |  261 lines

  1.  /*
  2.   * sock_host() determines the type of socket (datagram, stream), the name
  3.   * and address of the host at the other end of a socket, the local socket
  4.   * address and port, and the remote username if username lookups are done
  5.   * irrespective of client. All results are in static memory and will be
  6.   * overwritten upon the next call.
  7.   * 
  8.   * The return status is (-1) if the remote host pretends to have someone elses
  9.   * name, or if the remote host name is available but could not be verified;
  10.   * in either case the hostname will be ignored. The return status is zero in
  11.   * all other cases (the hostname is unavailable, or the host name double
  12.   * check succeeds).
  13.   * 
  14.   * Diagnostics are reported through syslog(3).
  15.   * 
  16.   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
  17.   */
  18.  
  19. #ifndef lint
  20. static char sccsid[] = "@(#) socket.c 1.7 93/09/27 18:59:20";
  21. #endif
  22.  
  23. /* System libraries. */
  24.  
  25. #include <sys/types.h>
  26. #include <sys/param.h>
  27. #include <sys/socket.h>
  28. #include <netinet/in.h>
  29. #include <netdb.h>
  30. #include <stdio.h>
  31. #include <syslog.h>
  32. #include <errno.h>
  33.  
  34. extern char *inet_ntoa();
  35. extern char *strncpy();
  36. extern char *strcpy();
  37.  
  38.  /*
  39.   * Some AIX versions advertise a too small MAXHOSTNAMELEN value (32).
  40.   * Result: long hostnames would be truncated, and connections would be
  41.   * dropped because of host name verification failures. Adrian van Bloois
  42.   * (A.vanBloois@info.nic.surfnet.nl) figured out what was the problem.
  43.   */
  44.  
  45. #if (MAXHOSTNAMELEN < 64)
  46. #undef MAXHOSTNAMELEN
  47. #endif
  48.  
  49. /* In case not defined in <sys/param.h>. */
  50.  
  51. #ifndef MAXHOSTNAMELEN
  52. #define MAXHOSTNAMELEN    256        /* storage for host name */
  53. #endif
  54.  
  55. /* Local stuff. */
  56.  
  57. #include "log_tcp.h"
  58.  
  59. /* Forward declarations. */
  60.  
  61. static int sock_match_hostname();
  62. static void sock_sink();
  63.  
  64. /* sock_host - determine endpoint info */
  65.  
  66. int     sock_host(client)
  67. struct client_info *client;
  68. {
  69.     static struct sockaddr rmt_sa;
  70.     static struct sockaddr our_sa;
  71.     int     len;
  72.     char    buf[BUFSIZ];
  73.  
  74.     /*
  75.      * Initialize the result with suitable defaults.
  76.      */
  77.  
  78.     init_client(client);
  79.  
  80.     /*
  81.      * Look up the remote host address. Hal R. Brand <BRAND@addvax.llnl.gov>
  82.      * suggested how to get the remote host info in case of UDP connections:
  83.      * peek at the first message without actually looking at its contents.
  84.      */
  85.  
  86.     len = sizeof(rmt_sa);
  87.     if (getpeername(client->fd, &rmt_sa, &len) < 0) {
  88.     len = sizeof(rmt_sa);
  89.     if (recvfrom(client->fd, buf, sizeof(buf), MSG_PEEK, &rmt_sa, &len) < 0) {
  90.         syslog(LOG_ERR, "error: can't get client address: %m");
  91.         return (0);                /* address and name unknown */
  92.     }
  93. #ifdef really_paranoid
  94.     memset(buf, 0 sizeof(buf));
  95. #endif
  96.     client->sink = sock_sink;
  97.     }
  98.     client->rmt_sin = (struct sockaddr_in *) & rmt_sa;
  99.  
  100.     /*
  101.      * Determine the local binding. Right now this information is used only
  102.      * for remote username lookups, but it may become useful to map the local
  103.      * port number to an internet service name, so that services handled by
  104.      * the same daemon program (same argv[0] value) can still be
  105.      * distinguished.
  106.      */
  107.  
  108.     len = sizeof(our_sa);
  109.     if (getsockname(client->fd, &our_sa, &len) < 0) {
  110.     syslog(LOG_ERR, "error: getsockname: %m");
  111.     } else {
  112.     client->our_sin = (struct sockaddr_in *) & our_sa;
  113.     }
  114.     return (sock_names(client));
  115. }
  116.  
  117. /* sock_names - map IP address info to readable address and name */
  118.  
  119. int     sock_names(client)
  120. struct client_info *client;
  121. {
  122.     static char addr_buf[MAXHOSTNAMELEN];
  123.     static char name_buf[MAXHOSTNAMELEN];
  124.     struct hostent *hp;
  125.     struct in_addr addr;
  126.  
  127.     /*
  128.      * Some stupid compilers can do struct assignment but cannot do structure
  129.      * initialization.
  130.      */
  131.  
  132.     addr = client->rmt_sin->sin_addr;
  133.  
  134.     /*
  135.      * Do username lookups if we do lookups irrespective of client. In a
  136.      * future release we should perhaps use asynchronous I/O so that the
  137.      * handshake with the rfc931 server can proceed while hostname lookups
  138.      * are going on.
  139.      */
  140.  
  141. #ifdef ALWAYS_RFC931
  142.     if (RFC931_POSSIBLE(client))
  143.     client->user = rfc931(client->rmt_sin, client->our_sin);
  144. #endif
  145.  
  146.     /*
  147.      * Map the address to human-readable form.
  148.      */
  149.  
  150. #define STRNCP(d,s,l) { strncpy((d),(s),(l)); ((d)[(l)-1] = 0); }
  151.  
  152.     STRNCP(addr_buf, inet_ntoa(addr), sizeof(addr_buf));
  153.     client->addr = addr_buf;
  154.  
  155.     /*
  156.      * Look up the remote host name. Verify that the host name does not
  157.      * belong to someone else. Ignore the hostname if verification fails or
  158.      * if verification is not possible.
  159.      */
  160.  
  161.     if ((hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET)) == 0)
  162.     return (0);                /* hostname unknown */
  163.     STRNCP(name_buf, hp->h_name, sizeof(name_buf));
  164.     if (sock_match_hostname(name_buf, addr)) {
  165.     client->name = name_buf;
  166.     return (0);                /* hostname verified ok */
  167.     } else {
  168.     return (-1);                /* bad or unverified name */
  169.     }
  170. }
  171.  
  172. /* sock_match_hostname - determine if host name matches IP address */
  173.  
  174. static int sock_match_hostname(remotehost, addr)
  175. char   *remotehost;
  176. struct in_addr addr;
  177. {
  178.     struct hostent *hp;
  179.     int     i;
  180.  
  181.     /*
  182.      * Verify that the client address is a member of the address list
  183.      * returned by gethostbyname(remotehost).
  184.      * 
  185.      * Verify also that gethostbyaddr() and gethostbyname() return the same
  186.      * hostname, or rshd and rlogind may still end up being spoofed.
  187.      * 
  188.      * On some sites, gethostbyname("localhost") returns "localhost.my.domain".
  189.      * This is a DNS artefact. We treat it as a special case. When we can't
  190.      * believe the address list from gethostbyname("localhost") we're in big
  191.      * trouble anyway.
  192.      */
  193.  
  194.     if ((hp = gethostbyname(remotehost)) == 0) {
  195.  
  196.     /*
  197.      * Unable to verify that the host name matches the address. This may
  198.      * be a transient problem or a botched name server setup.
  199.      */
  200.  
  201.     syslog(LOG_ERR,
  202.            "warning: can't verify hostname: gethostbyname(%s) failed",
  203.            remotehost);
  204.     return (FROM_BAD);
  205.  
  206.     } else if (strcasecmp(remotehost, hp->h_name)
  207.            && strcasecmp(remotehost, "localhost")) {
  208.  
  209.     /*
  210.      * The gethostbyaddr() and gethostbyname() calls did not return the
  211.      * same hostname. This could be a nameserver configuration problem.
  212.      * It could also be that someone is trying to spoof us.
  213.      */
  214.  
  215.     syslog(LOG_ERR, "warning: host name/name mismatch: %s != %s",
  216.            remotehost, hp->h_name);
  217.     return (FROM_BAD);
  218.  
  219.     } else {
  220.  
  221.     /*
  222.      * The client address should be a member of the address list returned
  223.      * by gethostbyname(). We should first verify that the h_addrtype
  224.      * field is AF_INET, but this program has already caused too much
  225.      * grief on systems with broken library code.
  226.      */
  227.  
  228.     for (i = 0; hp->h_addr_list[i]; i++) {
  229.         if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0)
  230.         return (FROM_GOOD);
  231.     }
  232.  
  233.     /*
  234.      * The host name does not map to the initial client address. Perhaps
  235.      * someone has messed up. Perhaps someone compromised a name server.
  236.      */
  237.  
  238.     syslog(LOG_ERR, "warning: host name/address mismatch: %s != %s",
  239.            inet_ntoa(addr), hp->h_name);
  240.     return (FROM_BAD);
  241.     }
  242. }
  243.  
  244. /* sock_sink - absorb unreceived IP datagram */
  245.  
  246. static void sock_sink(fd)
  247. int     fd;
  248.  
  249. {
  250.     char    buf[BUFSIZ];
  251.     struct sockaddr sa;
  252.     int     size = sizeof(sa);
  253.  
  254.     /*
  255.      * Eat up the not-yet received datagram. Some systems insist on a
  256.      * non-zero source address argument in the recvfrom() call below.
  257.      */
  258.  
  259.     (void) recvfrom(fd, buf, sizeof(buf), 0, &sa, &size);
  260. }
  261.