xref: /freebsd/contrib/tcp_wrappers/tli.c (revision 2aef693010b252e8cff0ce46a6ebf15b74c82219)
12aef6930SMark Murray  /*
22aef6930SMark Murray   * tli_host() determines the type of transport (connected, connectionless),
32aef6930SMark Murray   * the transport address of a client host, and the transport address of a
42aef6930SMark Murray   * server endpoint. In addition, it provides methods to map a transport
52aef6930SMark Murray   * address to a printable host name or address. Socket address results are
62aef6930SMark Murray   * in static memory; tli structures are allocated from the heap.
72aef6930SMark Murray   *
82aef6930SMark Murray   * The result from the hostname lookup method is STRING_PARANOID when a host
92aef6930SMark Murray   * pretends to have someone elses name, or when a host name is available but
102aef6930SMark Murray   * could not be verified.
112aef6930SMark Murray   *
122aef6930SMark Murray   * Diagnostics are reported through syslog(3).
132aef6930SMark Murray   *
142aef6930SMark Murray   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
152aef6930SMark Murray   */
162aef6930SMark Murray 
172aef6930SMark Murray #ifndef lint
182aef6930SMark Murray static char sccsid[] = "@(#) tli.c 1.15 97/03/21 19:27:25";
192aef6930SMark Murray #endif
202aef6930SMark Murray 
212aef6930SMark Murray #ifdef TLI
222aef6930SMark Murray 
232aef6930SMark Murray /* System libraries. */
242aef6930SMark Murray 
252aef6930SMark Murray #include <sys/types.h>
262aef6930SMark Murray #include <sys/param.h>
272aef6930SMark Murray #include <sys/stream.h>
282aef6930SMark Murray #include <sys/stat.h>
292aef6930SMark Murray #include <sys/mkdev.h>
302aef6930SMark Murray #include <sys/tiuser.h>
312aef6930SMark Murray #include <sys/timod.h>
322aef6930SMark Murray #include <sys/socket.h>
332aef6930SMark Murray #include <netinet/in.h>
342aef6930SMark Murray #include <stdio.h>
352aef6930SMark Murray #include <syslog.h>
362aef6930SMark Murray #include <errno.h>
372aef6930SMark Murray #include <netconfig.h>
382aef6930SMark Murray #include <netdir.h>
392aef6930SMark Murray #include <string.h>
402aef6930SMark Murray 
412aef6930SMark Murray extern char *nc_sperror();
422aef6930SMark Murray extern int errno;
432aef6930SMark Murray extern char *sys_errlist[];
442aef6930SMark Murray extern int sys_nerr;
452aef6930SMark Murray extern int t_errno;
462aef6930SMark Murray extern char *t_errlist[];
472aef6930SMark Murray extern int t_nerr;
482aef6930SMark Murray 
492aef6930SMark Murray /* Local stuff. */
502aef6930SMark Murray 
512aef6930SMark Murray #include "tcpd.h"
522aef6930SMark Murray 
532aef6930SMark Murray /* Forward declarations. */
542aef6930SMark Murray 
552aef6930SMark Murray static void tli_endpoints();
562aef6930SMark Murray static struct netconfig *tli_transport();
572aef6930SMark Murray static void tli_hostname();
582aef6930SMark Murray static void tli_hostaddr();
592aef6930SMark Murray static void tli_cleanup();
602aef6930SMark Murray static char *tli_error();
612aef6930SMark Murray static void tli_sink();
622aef6930SMark Murray 
632aef6930SMark Murray /* tli_host - look up endpoint addresses and install conversion methods */
642aef6930SMark Murray 
652aef6930SMark Murray void    tli_host(request)
662aef6930SMark Murray struct request_info *request;
672aef6930SMark Murray {
682aef6930SMark Murray     static struct sockaddr_in client;
692aef6930SMark Murray     static struct sockaddr_in server;
702aef6930SMark Murray 
712aef6930SMark Murray     /*
722aef6930SMark Murray      * If we discover that we are using an IP transport, pretend we never
732aef6930SMark Murray      * were here. Otherwise, use the transport-independent method and stick
742aef6930SMark Murray      * to generic network addresses. XXX hard-coded protocol family name.
752aef6930SMark Murray      */
762aef6930SMark Murray 
772aef6930SMark Murray     tli_endpoints(request);
782aef6930SMark Murray     if ((request->config = tli_transport(request->fd)) != 0
792aef6930SMark Murray 	&& STR_EQ(request->config->nc_protofmly, "inet")) {
802aef6930SMark Murray 	if (request->client->unit != 0) {
812aef6930SMark Murray 	    client = *(struct sockaddr_in *) request->client->unit->addr.buf;
822aef6930SMark Murray 	    request->client->sin = &client;
832aef6930SMark Murray 	}
842aef6930SMark Murray 	if (request->server->unit != 0) {
852aef6930SMark Murray 	    server = *(struct sockaddr_in *) request->server->unit->addr.buf;
862aef6930SMark Murray 	    request->server->sin = &server;
872aef6930SMark Murray 	}
882aef6930SMark Murray 	tli_cleanup(request);
892aef6930SMark Murray 	sock_methods(request);
902aef6930SMark Murray     } else {
912aef6930SMark Murray 	request->hostname = tli_hostname;
922aef6930SMark Murray 	request->hostaddr = tli_hostaddr;
932aef6930SMark Murray 	request->cleanup = tli_cleanup;
942aef6930SMark Murray     }
952aef6930SMark Murray }
962aef6930SMark Murray 
972aef6930SMark Murray /* tli_cleanup - cleanup some dynamically-allocated data structures */
982aef6930SMark Murray 
992aef6930SMark Murray static void tli_cleanup(request)
1002aef6930SMark Murray struct request_info *request;
1012aef6930SMark Murray {
1022aef6930SMark Murray     if (request->config != 0)
1032aef6930SMark Murray 	freenetconfigent(request->config);
1042aef6930SMark Murray     if (request->client->unit != 0)
1052aef6930SMark Murray 	t_free((char *) request->client->unit, T_UNITDATA);
1062aef6930SMark Murray     if (request->server->unit != 0)
1072aef6930SMark Murray 	t_free((char *) request->server->unit, T_UNITDATA);
1082aef6930SMark Murray }
1092aef6930SMark Murray 
1102aef6930SMark Murray /* tli_endpoints - determine TLI client and server endpoint information */
1112aef6930SMark Murray 
1122aef6930SMark Murray static void tli_endpoints(request)
1132aef6930SMark Murray struct request_info *request;
1142aef6930SMark Murray {
1152aef6930SMark Murray     struct t_unitdata *server;
1162aef6930SMark Murray     struct t_unitdata *client;
1172aef6930SMark Murray     int     fd = request->fd;
1182aef6930SMark Murray     int     flags;
1192aef6930SMark Murray 
1202aef6930SMark Murray     /*
1212aef6930SMark Murray      * Determine the client endpoint address. With unconnected services, peek
1222aef6930SMark Murray      * at the sender address of the pending protocol data unit without
1232aef6930SMark Murray      * popping it off the receive queue. This trick works because only the
1242aef6930SMark Murray      * address member of the unitdata structure has been allocated.
1252aef6930SMark Murray      *
1262aef6930SMark Murray      * Beware of successful returns with zero-length netbufs (for example,
1272aef6930SMark Murray      * Solaris 2.3 with ticlts transport). The netdir(3) routines can't
1282aef6930SMark Murray      * handle that. Assume connection-less transport when TI_GETPEERNAME
1292aef6930SMark Murray      * produces no usable result, even when t_rcvudata() is unable to figure
1302aef6930SMark Murray      * out the peer address. Better to hang than to loop.
1312aef6930SMark Murray      */
1322aef6930SMark Murray 
1332aef6930SMark Murray     if ((client = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ADDR)) == 0) {
1342aef6930SMark Murray 	tcpd_warn("t_alloc: %s", tli_error());
1352aef6930SMark Murray 	return;
1362aef6930SMark Murray     }
1372aef6930SMark Murray     if (ioctl(fd, TI_GETPEERNAME, &client->addr) < 0 || client->addr.len == 0) {
1382aef6930SMark Murray 	request->sink = tli_sink;
1392aef6930SMark Murray 	if (t_rcvudata(fd, client, &flags) < 0 || client->addr.len == 0) {
1402aef6930SMark Murray 	    tcpd_warn("can't get client address: %s", tli_error());
1412aef6930SMark Murray 	    t_free((void *) client, T_UNITDATA);
1422aef6930SMark Murray 	    return;
1432aef6930SMark Murray 	}
1442aef6930SMark Murray     }
1452aef6930SMark Murray     request->client->unit = client;
1462aef6930SMark Murray 
1472aef6930SMark Murray     /*
1482aef6930SMark Murray      * Look up the server endpoint address. This can be used for filtering on
1492aef6930SMark Murray      * server address or name, or to look up the client user.
1502aef6930SMark Murray      */
1512aef6930SMark Murray 
1522aef6930SMark Murray     if ((server = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ADDR)) == 0) {
1532aef6930SMark Murray 	tcpd_warn("t_alloc: %s", tli_error());
1542aef6930SMark Murray 	return;
1552aef6930SMark Murray     }
1562aef6930SMark Murray     if (ioctl(fd, TI_GETMYNAME, &server->addr) < 0) {
1572aef6930SMark Murray 	tcpd_warn("TI_GETMYNAME: %m");
1582aef6930SMark Murray 	t_free((void *) server, T_UNITDATA);
1592aef6930SMark Murray 	return;
1602aef6930SMark Murray     }
1612aef6930SMark Murray     request->server->unit = server;
1622aef6930SMark Murray }
1632aef6930SMark Murray 
1642aef6930SMark Murray /* tli_transport - find out TLI transport type */
1652aef6930SMark Murray 
1662aef6930SMark Murray static struct netconfig *tli_transport(fd)
1672aef6930SMark Murray int     fd;
1682aef6930SMark Murray {
1692aef6930SMark Murray     struct stat from_client;
1702aef6930SMark Murray     struct stat from_config;
1712aef6930SMark Murray     void   *handlep;
1722aef6930SMark Murray     struct netconfig *config;
1732aef6930SMark Murray 
1742aef6930SMark Murray     /*
1752aef6930SMark Murray      * Assuming that the network device is a clone device, we must compare
1762aef6930SMark Murray      * the major device number of stdin to the minor device number of the
1772aef6930SMark Murray      * devices listed in the netconfig table.
1782aef6930SMark Murray      */
1792aef6930SMark Murray 
1802aef6930SMark Murray     if (fstat(fd, &from_client) != 0) {
1812aef6930SMark Murray 	tcpd_warn("fstat(fd %d): %m", fd);
1822aef6930SMark Murray 	return (0);
1832aef6930SMark Murray     }
1842aef6930SMark Murray     if ((handlep = setnetconfig()) == 0) {
1852aef6930SMark Murray 	tcpd_warn("setnetconfig: %m");
1862aef6930SMark Murray 	return (0);
1872aef6930SMark Murray     }
1882aef6930SMark Murray     while (config = getnetconfig(handlep)) {
1892aef6930SMark Murray 	if (stat(config->nc_device, &from_config) == 0) {
1902aef6930SMark Murray 	    if (minor(from_config.st_rdev) == major(from_client.st_rdev))
1912aef6930SMark Murray 		break;
1922aef6930SMark Murray 	}
1932aef6930SMark Murray     }
1942aef6930SMark Murray     if (config == 0) {
1952aef6930SMark Murray 	tcpd_warn("unable to identify transport protocol");
1962aef6930SMark Murray 	return (0);
1972aef6930SMark Murray     }
1982aef6930SMark Murray 
1992aef6930SMark Murray     /*
2002aef6930SMark Murray      * Something else may clobber our getnetconfig() result, so we'd better
2012aef6930SMark Murray      * acquire our private copy.
2022aef6930SMark Murray      */
2032aef6930SMark Murray 
2042aef6930SMark Murray     if ((config = getnetconfigent(config->nc_netid)) == 0) {
2052aef6930SMark Murray 	tcpd_warn("getnetconfigent(%s): %s", config->nc_netid, nc_sperror());
2062aef6930SMark Murray 	return (0);
2072aef6930SMark Murray     }
2082aef6930SMark Murray     return (config);
2092aef6930SMark Murray }
2102aef6930SMark Murray 
2112aef6930SMark Murray /* tli_hostaddr - map TLI transport address to printable address */
2122aef6930SMark Murray 
2132aef6930SMark Murray static void tli_hostaddr(host)
2142aef6930SMark Murray struct host_info *host;
2152aef6930SMark Murray {
2162aef6930SMark Murray     struct request_info *request = host->request;
2172aef6930SMark Murray     struct netconfig *config = request->config;
2182aef6930SMark Murray     struct t_unitdata *unit = host->unit;
2192aef6930SMark Murray     char   *uaddr;
2202aef6930SMark Murray 
2212aef6930SMark Murray     if (config != 0 && unit != 0
2222aef6930SMark Murray 	&& (uaddr = taddr2uaddr(config, &unit->addr)) != 0) {
2232aef6930SMark Murray 	STRN_CPY(host->addr, uaddr, sizeof(host->addr));
2242aef6930SMark Murray 	free(uaddr);
2252aef6930SMark Murray     }
2262aef6930SMark Murray }
2272aef6930SMark Murray 
2282aef6930SMark Murray /* tli_hostname - map TLI transport address to hostname */
2292aef6930SMark Murray 
2302aef6930SMark Murray static void tli_hostname(host)
2312aef6930SMark Murray struct host_info *host;
2322aef6930SMark Murray {
2332aef6930SMark Murray     struct request_info *request = host->request;
2342aef6930SMark Murray     struct netconfig *config = request->config;
2352aef6930SMark Murray     struct t_unitdata *unit = host->unit;
2362aef6930SMark Murray     struct nd_hostservlist *servlist;
2372aef6930SMark Murray 
2382aef6930SMark Murray     if (config != 0 && unit != 0
2392aef6930SMark Murray 	&& netdir_getbyaddr(config, &servlist, &unit->addr) == ND_OK) {
2402aef6930SMark Murray 
2412aef6930SMark Murray 	struct nd_hostserv *service = servlist->h_hostservs;
2422aef6930SMark Murray 	struct nd_addrlist *addr_list;
2432aef6930SMark Murray 	int     found = 0;
2442aef6930SMark Murray 
2452aef6930SMark Murray 	if (netdir_getbyname(config, service, &addr_list) != ND_OK) {
2462aef6930SMark Murray 
2472aef6930SMark Murray 	    /*
2482aef6930SMark Murray 	     * Unable to verify that the name matches the address. This may
2492aef6930SMark Murray 	     * be a transient problem or a botched name server setup. We
2502aef6930SMark Murray 	     * decide to play safe.
2512aef6930SMark Murray 	     */
2522aef6930SMark Murray 
2532aef6930SMark Murray 	    tcpd_warn("can't verify hostname: netdir_getbyname(%.*s) failed",
2542aef6930SMark Murray 		      STRING_LENGTH, service->h_host);
2552aef6930SMark Murray 
2562aef6930SMark Murray 	} else {
2572aef6930SMark Murray 
2582aef6930SMark Murray 	    /*
2592aef6930SMark Murray 	     * Look up the host address in the address list we just got. The
2602aef6930SMark Murray 	     * comparison is done on the textual representation, because the
2612aef6930SMark Murray 	     * transport address is an opaque structure that may have holes
2622aef6930SMark Murray 	     * with uninitialized garbage. This approach obviously loses when
2632aef6930SMark Murray 	     * the address does not have a textual representation.
2642aef6930SMark Murray 	     */
2652aef6930SMark Murray 
2662aef6930SMark Murray 	    char   *uaddr = eval_hostaddr(host);
2672aef6930SMark Murray 	    char   *ua;
2682aef6930SMark Murray 	    int     i;
2692aef6930SMark Murray 
2702aef6930SMark Murray 	    for (i = 0; found == 0 && i < addr_list->n_cnt; i++) {
2712aef6930SMark Murray 		if ((ua = taddr2uaddr(config, &(addr_list->n_addrs[i]))) != 0) {
2722aef6930SMark Murray 		    found = !strcmp(ua, uaddr);
2732aef6930SMark Murray 		    free(ua);
2742aef6930SMark Murray 		}
2752aef6930SMark Murray 	    }
2762aef6930SMark Murray 	    netdir_free((void *) addr_list, ND_ADDRLIST);
2772aef6930SMark Murray 
2782aef6930SMark Murray 	    /*
2792aef6930SMark Murray 	     * When the host name does not map to the initial address, assume
2802aef6930SMark Murray 	     * someone has compromised a name server. More likely someone
2812aef6930SMark Murray 	     * botched it, but that could be dangerous, too.
2822aef6930SMark Murray 	     */
2832aef6930SMark Murray 
2842aef6930SMark Murray 	    if (found == 0)
2852aef6930SMark Murray 		tcpd_warn("host name/address mismatch: %s != %.*s",
2862aef6930SMark Murray 			  host->addr, STRING_LENGTH, service->h_host);
2872aef6930SMark Murray 	}
2882aef6930SMark Murray 	STRN_CPY(host->name, found ? service->h_host : paranoid,
2892aef6930SMark Murray 		 sizeof(host->name));
2902aef6930SMark Murray 	netdir_free((void *) servlist, ND_HOSTSERVLIST);
2912aef6930SMark Murray     }
2922aef6930SMark Murray }
2932aef6930SMark Murray 
2942aef6930SMark Murray /* tli_error - convert tli error number to text */
2952aef6930SMark Murray 
2962aef6930SMark Murray static char *tli_error()
2972aef6930SMark Murray {
2982aef6930SMark Murray     static char buf[40];
2992aef6930SMark Murray 
3002aef6930SMark Murray     if (t_errno != TSYSERR) {
3012aef6930SMark Murray 	if (t_errno < 0 || t_errno >= t_nerr) {
3022aef6930SMark Murray 	    sprintf(buf, "Unknown TLI error %d", t_errno);
3032aef6930SMark Murray 	    return (buf);
3042aef6930SMark Murray 	} else {
3052aef6930SMark Murray 	    return (t_errlist[t_errno]);
3062aef6930SMark Murray 	}
3072aef6930SMark Murray     } else {
3082aef6930SMark Murray 	if (errno < 0 || errno >= sys_nerr) {
3092aef6930SMark Murray 	    sprintf(buf, "Unknown UNIX error %d", errno);
3102aef6930SMark Murray 	    return (buf);
3112aef6930SMark Murray 	} else {
3122aef6930SMark Murray 	    return (sys_errlist[errno]);
3132aef6930SMark Murray 	}
3142aef6930SMark Murray     }
3152aef6930SMark Murray }
3162aef6930SMark Murray 
3172aef6930SMark Murray /* tli_sink - absorb unreceived datagram */
3182aef6930SMark Murray 
3192aef6930SMark Murray static void tli_sink(fd)
3202aef6930SMark Murray int     fd;
3212aef6930SMark Murray {
3222aef6930SMark Murray     struct t_unitdata *unit;
3232aef6930SMark Murray     int     flags;
3242aef6930SMark Murray 
3252aef6930SMark Murray     /*
3262aef6930SMark Murray      * Something went wrong. Absorb the datagram to keep inetd from looping.
3272aef6930SMark Murray      * Allocate storage for address, control and data. If that fails, sleep
3282aef6930SMark Murray      * for a couple of seconds in an attempt to keep inetd from looping too
3292aef6930SMark Murray      * fast.
3302aef6930SMark Murray      */
3312aef6930SMark Murray 
3322aef6930SMark Murray     if ((unit = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ALL)) == 0) {
3332aef6930SMark Murray 	tcpd_warn("t_alloc: %s", tli_error());
3342aef6930SMark Murray 	sleep(5);
3352aef6930SMark Murray     } else {
3362aef6930SMark Murray 	(void) t_rcvudata(fd, unit, &flags);
3372aef6930SMark Murray 	t_free((void *) unit, T_UNITDATA);
3382aef6930SMark Murray     }
3392aef6930SMark Murray }
3402aef6930SMark Murray 
3412aef6930SMark Murray #endif /* TLI */
342