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