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

  1.  /*
  2.   * tli_host() determines the type of transport (connected, connectionless),
  3.   * the name and address of the host at the other end of a network link. In
  4.   * case of an IP service, tli_host() also determines the local address and
  5.   * port, and the remote username if username lookups are done irrespective
  6.   * of client. All results are in static memory.
  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[] = "@(#) tli.c 1.7 93/09/27 18:59:25";
  21. #endif
  22.  
  23. #ifdef TLI
  24.  
  25. /* System libraries. */
  26.  
  27. #include <sys/types.h>
  28. #include <sys/param.h>
  29. #include <sys/stat.h>
  30. #include <sys/mkdev.h>
  31. #include <sys/tiuser.h>
  32. #include <sys/timod.h>
  33. #include <sys/socket.h>
  34. #include <netinet/in.h>
  35. #include <stdio.h>
  36. #include <syslog.h>
  37. #include <errno.h>
  38. #include <netconfig.h>
  39. #include <netdir.h>
  40.  
  41. extern char *strncpy();
  42.  
  43.  /* Some systems versions advertise a too small MAXHOSTNAMELEN value. */
  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. extern int errno;
  56. extern char *sys_errlist[];
  57. extern int sys_nerr;
  58. extern int t_errno;
  59. extern char *t_errlist[];
  60. extern int t_nerr;
  61.  
  62. /* Local stuff. */
  63.  
  64. #include "log_tcp.h"
  65.  
  66. /* Forward declarations. */
  67.  
  68. static struct t_unitdata *tli_remote_addr();
  69. static struct t_unitdata *tli_local_addr();
  70. static struct netconfig *tli_transport();
  71. static int tli_names();
  72. static int tli_match_hostname();
  73. static char *tli_error();
  74. static void tli_sink();
  75.  
  76. /* tli_host - determine endpoint info */
  77.  
  78. int     tli_host(client)
  79. struct client_info *client;
  80. {
  81.     struct netconfig *config;
  82.     struct t_unitdata *rmt_unit;
  83.     struct t_unitdata *our_unit;
  84.     static struct sockaddr_in rmt_sin;
  85.     static struct sockaddr_in our_sin;
  86.     int     ret = 0;            /* host name/addr unknown */
  87.  
  88.     /*
  89.      * Initialize the result with suitable defaults.
  90.      */
  91.  
  92.     init_client(client);
  93.  
  94.     /*
  95.      * Find out the client address, find out what type of transport is hidden
  96.      * underneath the TLI programmatic interface, map the transport address
  97.      * to a human-readable form, and determine the host name. Double check
  98.      * the hostname.
  99.      * 
  100.      * If we discover that we are using an IP transport, do DNS lookups and
  101.      * determine the local binding. Otherwise, use the transport-independent
  102.      * method and stick to generic network addresses. XXX hard-coded protocol
  103.      * family name.
  104.      */
  105.  
  106. #define SINCP(d,s) (((d) = *(struct sockaddr_in *) (s)), &(d))
  107.  
  108.     if ((rmt_unit = tli_remote_addr(client)) != 0) {
  109.     if ((config = tli_transport(client->fd)) != 0) {
  110.         if (strcasecmp(config->nc_protofmly, "inet") == 0) {
  111.         if ((our_unit = tli_local_addr(client)) != 0) {
  112.             client->our_sin = SINCP(our_sin, our_unit->addr.buf);
  113.             t_free((char *) our_unit, T_UNITDATA);
  114.         }
  115.         client->rmt_sin = SINCP(rmt_sin, rmt_unit->addr.buf);
  116.         ret = sock_names(client);
  117.         } else {
  118.         ret = tli_names(client, &(rmt_unit->addr), config);
  119.         }
  120.         freenetconfigent(config);
  121.     }
  122.     t_free((char *) rmt_unit, T_UNITDATA);
  123.     }
  124.     return (ret);
  125. }
  126.  
  127. /* tli_remote_addr - determine TLI client address */
  128.  
  129. static struct t_unitdata *tli_remote_addr(client)
  130. struct client_info *client;
  131. {
  132.     struct t_unitdata *unit;
  133.     int     flags;
  134.  
  135.     /*
  136.      * Allocate storage for the endpoint address. t_alloc() finds out for us
  137.      * how large the address can be. Address sizes depend on the underlying
  138.      * transport protocol.
  139.      * 
  140.      * Determine the transport-independent client address. With connectionless
  141.      * services, peek at the sender address of the pending datagram without
  142.      * popping it off the receive queue. This trick works because only the
  143.      * address member of the unitdata structure has been allocated.
  144.      */
  145.  
  146.     if ((unit = (struct t_unitdata *) t_alloc(client->fd, T_UNITDATA, T_ADDR)) == 0) {
  147.     syslog(LOG_ERR, "error: t_alloc: %s", tli_error());
  148.     } else {
  149.     if (ioctl(client->fd, TI_GETPEERNAME, &(unit->addr)) < 0) {
  150.         if (t_rcvudata(client->fd, unit, &flags) < 0) {
  151.         syslog(LOG_ERR, "error: can't get client address: %s", tli_error());
  152.         t_free((void *) unit, T_UNITDATA);
  153.         unit = 0;
  154.         } else {
  155.         client->sink = tli_sink;
  156.         }
  157.         /* beware: at this point, unit may be null */
  158.     }
  159.     }
  160.     return (unit);
  161. }
  162.  
  163. /* tli_local_addr - determine TLI local address */
  164.  
  165. struct t_unitdata *tli_local_addr(client)
  166. struct client_info *client;
  167. {
  168.     struct t_unitdata *unit;
  169.  
  170.     if ((unit = (struct t_unitdata *) t_alloc(client->fd, T_UNITDATA, T_ADDR)) == 0) {
  171.     syslog(LOG_ERR, "error: t_alloc: %s", tli_error());
  172.     } else {
  173.     if (ioctl(client->fd, TI_GETMYNAME, &(unit->addr)) < 0) {
  174.         syslog(LOG_ERR, "error: TI_GETMYNAME: %m");
  175.         t_free((void *) unit, T_UNITDATA);
  176.         unit = 0;
  177.     }
  178.     /* beware: at this point, unit may be null */
  179.     }
  180.     return (unit);
  181. }
  182.  
  183. /* tli_transport - find out TLI transport type */
  184.  
  185. static struct netconfig *tli_transport(fd)
  186. int     fd;
  187. {
  188.     struct stat from_client;
  189.     struct stat from_config;
  190.     void   *handlep;
  191.     struct netconfig *config;
  192.  
  193.     /*
  194.      * Assuming that the network device is a clone device, we must compare
  195.      * the major device number of stdin to the minor device number of the
  196.      * devices listed in the netconfig table.
  197.      */
  198.  
  199.     if (fstat(fd, &from_client) != 0) {
  200.     syslog(LOG_ERR, "error: fstat(fd %d): %m", fd);
  201.     return (0);
  202.     }
  203.     if ((handlep = setnetconfig()) == 0) {
  204.     syslog(LOG_ERR, "error: setnetconfig: %m");
  205.     return (0);
  206.     }
  207.     while (config = getnetconfig(handlep)) {
  208.     if (stat(config->nc_device, &from_config) == 0) {
  209.         if (minor(from_config.st_rdev) == major(from_client.st_rdev))
  210.         break;
  211.     }
  212.     }
  213.     if (config == 0) {
  214.     syslog(LOG_ERR, "error: unable to identify transport protocol");
  215.     return (0);
  216.     }
  217.  
  218.     /*
  219.      * Something else may clobber our getnetconfig() result, so we'd better
  220.      * acquire our private copy.
  221.      */
  222.  
  223.     if ((config = getnetconfigent(config->nc_netid)) == 0) {
  224.     syslog(LOG_ERR, "error: getnetconfigent(%s): %s",
  225.            config->nc_netid, nc_sperror());
  226.     return (0);
  227.     }
  228.     return (config);
  229. }
  230.  
  231. /* tli_names - map TLI transport address to readable address and name */
  232.  
  233. static int tli_names(client, taddr, config)
  234. struct client_info *client;
  235. struct netbuf *taddr;
  236. struct netconfig *config;
  237. {
  238.     struct nd_hostservlist *service;
  239.     static char host_name[MAXHOSTNAMELEN];
  240.     static char host_addr[MAXHOSTNAMELEN];
  241.     char   *uaddr;
  242.     int     ret = 0;            /* hostname unknown */
  243.  
  244.     /*
  245.      * Translate the transport address to (well, more-or-less human-readable)
  246.      * universal form and clean up. Some transports may not have a universal
  247.      * address representation and will lose. XXX uaddr form includes blanks?!
  248.      */
  249.  
  250. #define STRNCP(d,s,l) { strncpy((d),(s),(l)); (d)[(l)-1] = 0; }
  251.  
  252.     if ((uaddr = taddr2uaddr(config, taddr)) != 0) {
  253.     STRNCP(host_addr, uaddr, sizeof(host_addr));
  254.     client->addr = host_addr;
  255.     free(uaddr);
  256.     }
  257.  
  258.     /*
  259.      * Map the transport address to a human-readable hostname. Try to verify
  260.      * that the host name does not belong to someone else. If host name
  261.      * verification fails, ignore the host name.
  262.      */
  263.  
  264.     if (netdir_getbyaddr(config, &service, taddr) == ND_OK) {
  265.     if (tli_match_hostname(config, service->h_hostservs, client->addr)) {
  266.         STRNCP(host_name, service->h_hostservs->h_host, sizeof(host_name));
  267.         client->name = host_name;
  268.         ret = 0;                /* hostname ok */
  269.     } else {
  270.         ret = (-1);                /* bad or unverified name */
  271.     }
  272.     netdir_free((void *) service, ND_HOSTSERVLIST);
  273.     }
  274.     return (ret);
  275. }
  276.  
  277. /* tli_match_hostname - determine if host name matches transport address */
  278.  
  279. static int tli_match_hostname(config, service, uaddr)
  280. struct netconfig *config;
  281. struct nd_hostserv *service;
  282. char   *uaddr;
  283. {
  284.     struct nd_addrlist *addr_list;
  285.  
  286.     if (netdir_getbyname(config, service, &addr_list) != ND_OK) {
  287.  
  288.     /*
  289.      * Unable to verify that the name matches the address. This may be a
  290.      * transient problem or a botched name server setup. We decide to
  291.      * play safe.
  292.      */
  293.  
  294.     syslog(LOG_ERR,
  295.            "warning: can't verify hostname: netdir_getbyname(%s) failed",
  296.            service->h_host);
  297.     return (FROM_BAD);
  298.  
  299.     } else {
  300.  
  301.     /*
  302.      * Look up the host address in the address list we just got. The
  303.      * comparison is done on the textual representation, because the
  304.      * transport address is an opaque structure that may have holes with
  305.      * uninitialized garbage. This approach obviously loses when the
  306.      * address does not have a textual representation.
  307.      */
  308.  
  309.     char   *ua;
  310.     int     i;
  311.     int     found = 0;
  312.  
  313.     for (i = 0; found == 0 && i < addr_list->n_cnt; i++) {
  314.         if ((ua = taddr2uaddr(config, &(addr_list->n_addrs[i]))) != 0) {
  315.         found = !strcmp(ua, uaddr);
  316.         free(ua);
  317.         }
  318.     }
  319.     netdir_free((void *) addr_list, ND_ADDRLIST);
  320.  
  321.     /*
  322.      * When the host name does not map to the client address, assume
  323.      * someone has compromised a name server. More likely someone botched
  324.      * it, but that could be dangerous, too.
  325.      */
  326.  
  327.     if (found) {
  328.         return (FROM_GOOD);
  329.     } else {
  330.         syslog(LOG_ERR, "warning: host name/address mismatch: %s != %s",
  331.            uaddr, service->h_host);
  332.         return (FROM_BAD);
  333.     }
  334.     }
  335. }
  336.  
  337. /* tli_error - convert tli error number to text */
  338.  
  339. static char *tli_error()
  340. {
  341.     static char buf[40];
  342.  
  343.     if (t_errno != TSYSERR) {
  344.     if (t_errno < 0 || t_errno >= t_nerr) {
  345.         sprintf(buf, "Unknown TLI error %d", t_errno);
  346.         return (buf);
  347.     } else {
  348.         return (t_errlist[t_errno]);
  349.     }
  350.     } else {
  351.     if (errno < 0 || errno >= sys_nerr) {
  352.         sprintf(buf, "Unknown UNIX error %d", errno);
  353.         return (buf);
  354.     } else {
  355.         return (sys_errlist[errno]);
  356.     }
  357.     }
  358. }
  359.  
  360. /* tli_sink - absorb unreceived datagram */
  361.  
  362. static void tli_sink(fd)
  363. int     fd;
  364. {
  365.     struct t_unitdata *unit;
  366.     int     flags;
  367.  
  368.     /*
  369.      * Something went wrong. Absorb the datagram to keep inetd from looping.
  370.      * Allocate storage for address, control and data. If that fails, sleep
  371.      * for a couple of seconds in an attempt to keep inetd from looping too
  372.      * fast.
  373.      */
  374.  
  375.     if ((unit = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ALL)) == 0) {
  376.     syslog(LOG_ERR, "error: t_alloc: %s", tli_error());
  377.     sleep(5);
  378.     } else {
  379.     (void) t_rcvudata(fd, unit, &flags);
  380.     t_free((void *) unit, T_UNITDATA);
  381.     }
  382. }
  383.  
  384. #endif /* TLI */
  385.