xref: /freebsd/contrib/tcp_wrappers/tli.c (revision 899becbfcbf75008c560bae5e5fce0c205a5bc82)
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.
158053080cSYoshinobu Inoue   *
168053080cSYoshinobu Inoue   * $FreeBSD$
172aef6930SMark Murray   */
182aef6930SMark Murray 
192aef6930SMark Murray #ifndef lint
202aef6930SMark Murray static char sccsid[] = "@(#) tli.c 1.15 97/03/21 19:27:25";
212aef6930SMark Murray #endif
222aef6930SMark Murray 
232aef6930SMark Murray #ifdef TLI
242aef6930SMark Murray 
252aef6930SMark Murray /* System libraries. */
262aef6930SMark Murray 
272aef6930SMark Murray #include <sys/types.h>
282aef6930SMark Murray #include <sys/param.h>
292aef6930SMark Murray #include <sys/stream.h>
302aef6930SMark Murray #include <sys/stat.h>
312aef6930SMark Murray #include <sys/mkdev.h>
322aef6930SMark Murray #include <sys/tiuser.h>
332aef6930SMark Murray #include <sys/timod.h>
342aef6930SMark Murray #include <sys/socket.h>
352aef6930SMark Murray #include <netinet/in.h>
362aef6930SMark Murray #include <stdio.h>
372aef6930SMark Murray #include <syslog.h>
382aef6930SMark Murray #include <errno.h>
392aef6930SMark Murray #include <netconfig.h>
402aef6930SMark Murray #include <netdir.h>
412aef6930SMark Murray #include <string.h>
422aef6930SMark Murray 
432aef6930SMark Murray extern char *nc_sperror();
442aef6930SMark Murray extern char *sys_errlist[];
452aef6930SMark Murray extern int sys_nerr;
462aef6930SMark Murray extern int t_errno;
472aef6930SMark Murray extern char *t_errlist[];
482aef6930SMark Murray extern int t_nerr;
492aef6930SMark Murray 
502aef6930SMark Murray /* Local stuff. */
512aef6930SMark Murray 
522aef6930SMark Murray #include "tcpd.h"
532aef6930SMark Murray 
542aef6930SMark Murray /* Forward declarations. */
552aef6930SMark Murray 
562aef6930SMark Murray static void tli_endpoints();
572aef6930SMark Murray static struct netconfig *tli_transport();
582aef6930SMark Murray static void tli_hostname();
592aef6930SMark Murray static void tli_hostaddr();
602aef6930SMark Murray static void tli_cleanup();
612aef6930SMark Murray static char *tli_error();
622aef6930SMark Murray static void tli_sink();
632aef6930SMark Murray 
642aef6930SMark Murray /* tli_host - look up endpoint addresses and install conversion methods */
652aef6930SMark Murray 
tli_host(struct request_info * request)6614f102eaSEd Maste void    tli_host(struct request_info *request)
672aef6930SMark Murray {
688053080cSYoshinobu Inoue #ifdef INET6
698053080cSYoshinobu Inoue     static struct sockaddr_storage client;
708053080cSYoshinobu Inoue     static struct sockaddr_storage server;
718053080cSYoshinobu Inoue #else
722aef6930SMark Murray     static struct sockaddr_in client;
732aef6930SMark Murray     static struct sockaddr_in server;
748053080cSYoshinobu Inoue #endif
752aef6930SMark Murray 
762aef6930SMark Murray     /*
772aef6930SMark Murray      * If we discover that we are using an IP transport, pretend we never
782aef6930SMark Murray      * were here. Otherwise, use the transport-independent method and stick
792aef6930SMark Murray      * to generic network addresses. XXX hard-coded protocol family name.
802aef6930SMark Murray      */
812aef6930SMark Murray 
822aef6930SMark Murray     tli_endpoints(request);
838053080cSYoshinobu Inoue #ifdef INET6
848053080cSYoshinobu Inoue     if ((request->config = tli_transport(request->fd)) != 0
858053080cSYoshinobu Inoue 	&& (STR_EQ(request->config->nc_protofmly, "inet") ||
868053080cSYoshinobu Inoue 	    STR_EQ(request->config->nc_protofmly, "inet6"))) {
878053080cSYoshinobu Inoue #else
882aef6930SMark Murray     if ((request->config = tli_transport(request->fd)) != 0
892aef6930SMark Murray         && STR_EQ(request->config->nc_protofmly, "inet")) {
908053080cSYoshinobu Inoue #endif
912aef6930SMark Murray 	if (request->client->unit != 0) {
928053080cSYoshinobu Inoue #ifdef INET6
938053080cSYoshinobu Inoue 	    client = *(struct sockaddr_storage *) request->client->unit->addr.buf;
948053080cSYoshinobu Inoue 	    request->client->sin = (struct sockaddr *) &client;
958053080cSYoshinobu Inoue #else
962aef6930SMark Murray 	    client = *(struct sockaddr_in *) request->client->unit->addr.buf;
972aef6930SMark Murray 	    request->client->sin = &client;
988053080cSYoshinobu Inoue #endif
992aef6930SMark Murray 	}
1002aef6930SMark Murray 	if (request->server->unit != 0) {
1018053080cSYoshinobu Inoue #ifdef INET6
1028053080cSYoshinobu Inoue             server = *(struct sockaddr_storage *) request->server->unit->addr.buf;
1038053080cSYoshinobu Inoue             request->server->sin = (struct sockaddr *) &server;
1048053080cSYoshinobu Inoue #else
1052aef6930SMark Murray             server = *(struct sockaddr_in *) request->server->unit->addr.buf;
1062aef6930SMark Murray             request->server->sin = &server;
1078053080cSYoshinobu Inoue #endif
1082aef6930SMark Murray 	}
1092aef6930SMark Murray 	tli_cleanup(request);
1102aef6930SMark Murray 	sock_methods(request);
1112aef6930SMark Murray     } else {
1122aef6930SMark Murray 	request->hostname = tli_hostname;
1132aef6930SMark Murray 	request->hostaddr = tli_hostaddr;
1142aef6930SMark Murray 	request->cleanup = tli_cleanup;
1152aef6930SMark Murray     }
1162aef6930SMark Murray }
1172aef6930SMark Murray 
1182aef6930SMark Murray /* tli_cleanup - cleanup some dynamically-allocated data structures */
1192aef6930SMark Murray 
12014f102eaSEd Maste static void tli_cleanup(struct request_info *request)
1212aef6930SMark Murray {
1222aef6930SMark Murray     if (request->config != 0)
1232aef6930SMark Murray 	freenetconfigent(request->config);
1242aef6930SMark Murray     if (request->client->unit != 0)
1252aef6930SMark Murray 	t_free((char *) request->client->unit, T_UNITDATA);
1262aef6930SMark Murray     if (request->server->unit != 0)
1272aef6930SMark Murray 	t_free((char *) request->server->unit, T_UNITDATA);
1282aef6930SMark Murray }
1292aef6930SMark Murray 
1302aef6930SMark Murray /* tli_endpoints - determine TLI client and server endpoint information */
1312aef6930SMark Murray 
13214f102eaSEd Maste static void tli_endpoints(struct request_info *request)
1332aef6930SMark Murray {
1342aef6930SMark Murray     struct t_unitdata *server;
1352aef6930SMark Murray     struct t_unitdata *client;
1362aef6930SMark Murray     int     fd = request->fd;
1372aef6930SMark Murray     int     flags;
1382aef6930SMark Murray 
1392aef6930SMark Murray     /*
1402aef6930SMark Murray      * Determine the client endpoint address. With unconnected services, peek
1412aef6930SMark Murray      * at the sender address of the pending protocol data unit without
1422aef6930SMark Murray      * popping it off the receive queue. This trick works because only the
1432aef6930SMark Murray      * address member of the unitdata structure has been allocated.
1442aef6930SMark Murray      *
1452aef6930SMark Murray      * Beware of successful returns with zero-length netbufs (for example,
1462aef6930SMark Murray      * Solaris 2.3 with ticlts transport). The netdir(3) routines can't
1472aef6930SMark Murray      * handle that. Assume connection-less transport when TI_GETPEERNAME
1482aef6930SMark Murray      * produces no usable result, even when t_rcvudata() is unable to figure
1492aef6930SMark Murray      * out the peer address. Better to hang than to loop.
1502aef6930SMark Murray      */
1512aef6930SMark Murray 
1522aef6930SMark Murray     if ((client = (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_GETPEERNAME, &client->addr) < 0 || client->addr.len == 0) {
1572aef6930SMark Murray 	request->sink = tli_sink;
1582aef6930SMark Murray 	if (t_rcvudata(fd, client, &flags) < 0 || client->addr.len == 0) {
1592aef6930SMark Murray 	    tcpd_warn("can't get client address: %s", tli_error());
1602aef6930SMark Murray 	    t_free((void *) client, T_UNITDATA);
1612aef6930SMark Murray 	    return;
1622aef6930SMark Murray 	}
1632aef6930SMark Murray     }
1642aef6930SMark Murray     request->client->unit = client;
1652aef6930SMark Murray 
1662aef6930SMark Murray     /*
1672aef6930SMark Murray      * Look up the server endpoint address. This can be used for filtering on
1682aef6930SMark Murray      * server address or name, or to look up the client user.
1692aef6930SMark Murray      */
1702aef6930SMark Murray 
1712aef6930SMark Murray     if ((server = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ADDR)) == 0) {
1722aef6930SMark Murray 	tcpd_warn("t_alloc: %s", tli_error());
1732aef6930SMark Murray 	return;
1742aef6930SMark Murray     }
1752aef6930SMark Murray     if (ioctl(fd, TI_GETMYNAME, &server->addr) < 0) {
1762aef6930SMark Murray 	tcpd_warn("TI_GETMYNAME: %m");
1772aef6930SMark Murray 	t_free((void *) server, T_UNITDATA);
1782aef6930SMark Murray 	return;
1792aef6930SMark Murray     }
1802aef6930SMark Murray     request->server->unit = server;
1812aef6930SMark Murray }
1822aef6930SMark Murray 
1832aef6930SMark Murray /* tli_transport - find out TLI transport type */
1842aef6930SMark Murray 
185*899becbfSEd Maste static struct netconfig *tli_transport(int fd)
1862aef6930SMark Murray {
1872aef6930SMark Murray     struct stat from_client;
1882aef6930SMark Murray     struct stat from_config;
1892aef6930SMark Murray     void   *handlep;
1902aef6930SMark Murray     struct netconfig *config;
1912aef6930SMark Murray 
1922aef6930SMark Murray     /*
1932aef6930SMark Murray      * Assuming that the network device is a clone device, we must compare
1942aef6930SMark Murray      * the major device number of stdin to the minor device number of the
1952aef6930SMark Murray      * devices listed in the netconfig table.
1962aef6930SMark Murray      */
1972aef6930SMark Murray 
1982aef6930SMark Murray     if (fstat(fd, &from_client) != 0) {
1992aef6930SMark Murray 	tcpd_warn("fstat(fd %d): %m", fd);
2002aef6930SMark Murray 	return (0);
2012aef6930SMark Murray     }
2022aef6930SMark Murray     if ((handlep = setnetconfig()) == 0) {
2032aef6930SMark Murray 	tcpd_warn("setnetconfig: %m");
2042aef6930SMark Murray 	return (0);
2052aef6930SMark Murray     }
2062aef6930SMark Murray     while (config = getnetconfig(handlep)) {
2072aef6930SMark Murray 	if (stat(config->nc_device, &from_config) == 0) {
2088053080cSYoshinobu Inoue #ifdef NO_CLONE_DEVICE
2098053080cSYoshinobu Inoue 	/*
2108053080cSYoshinobu Inoue 	 * If the network devices are not cloned (as is the case for
2118053080cSYoshinobu Inoue 	 * Solaris 8 Beta), we must compare the major device numbers.
2128053080cSYoshinobu Inoue 	 */
2138053080cSYoshinobu Inoue 	    if (major(from_config.st_rdev) == major(from_client.st_rdev))
2148053080cSYoshinobu Inoue #else
2152aef6930SMark Murray 	    if (minor(from_config.st_rdev) == major(from_client.st_rdev))
2168053080cSYoshinobu Inoue #endif
2172aef6930SMark Murray 		break;
2182aef6930SMark Murray 	}
2192aef6930SMark Murray     }
2202aef6930SMark Murray     if (config == 0) {
2212aef6930SMark Murray 	tcpd_warn("unable to identify transport protocol");
2222aef6930SMark Murray 	return (0);
2232aef6930SMark Murray     }
2242aef6930SMark Murray 
2252aef6930SMark Murray     /*
2262aef6930SMark Murray      * Something else may clobber our getnetconfig() result, so we'd better
2272aef6930SMark Murray      * acquire our private copy.
2282aef6930SMark Murray      */
2292aef6930SMark Murray 
2302aef6930SMark Murray     if ((config = getnetconfigent(config->nc_netid)) == 0) {
2312aef6930SMark Murray 	tcpd_warn("getnetconfigent(%s): %s", config->nc_netid, nc_sperror());
2322aef6930SMark Murray 	return (0);
2332aef6930SMark Murray     }
2342aef6930SMark Murray     return (config);
2352aef6930SMark Murray }
2362aef6930SMark Murray 
2372aef6930SMark Murray /* tli_hostaddr - map TLI transport address to printable address */
2382aef6930SMark Murray 
23914f102eaSEd Maste static void tli_hostaddr(struct host_info *host)
2402aef6930SMark Murray {
2412aef6930SMark Murray     struct request_info *request = host->request;
2422aef6930SMark Murray     struct netconfig *config = request->config;
2432aef6930SMark Murray     struct t_unitdata *unit = host->unit;
2442aef6930SMark Murray     char   *uaddr;
2452aef6930SMark Murray 
2462aef6930SMark Murray     if (config != 0 && unit != 0
2472aef6930SMark Murray 	&& (uaddr = taddr2uaddr(config, &unit->addr)) != 0) {
2482aef6930SMark Murray 	STRN_CPY(host->addr, uaddr, sizeof(host->addr));
2492aef6930SMark Murray 	free(uaddr);
2502aef6930SMark Murray     }
2512aef6930SMark Murray }
2522aef6930SMark Murray 
2532aef6930SMark Murray /* tli_hostname - map TLI transport address to hostname */
2542aef6930SMark Murray 
25514f102eaSEd Maste static void tli_hostname(struct host_info *host)
2562aef6930SMark Murray {
2572aef6930SMark Murray     struct request_info *request = host->request;
2582aef6930SMark Murray     struct netconfig *config = request->config;
2592aef6930SMark Murray     struct t_unitdata *unit = host->unit;
2602aef6930SMark Murray     struct nd_hostservlist *servlist;
2612aef6930SMark Murray 
2622aef6930SMark Murray     if (config != 0 && unit != 0
2632aef6930SMark Murray 	&& netdir_getbyaddr(config, &servlist, &unit->addr) == ND_OK) {
2642aef6930SMark Murray 
2652aef6930SMark Murray 	struct nd_hostserv *service = servlist->h_hostservs;
2662aef6930SMark Murray 	struct nd_addrlist *addr_list;
2672aef6930SMark Murray 	int     found = 0;
2682aef6930SMark Murray 
2692aef6930SMark Murray 	if (netdir_getbyname(config, service, &addr_list) != ND_OK) {
2702aef6930SMark Murray 
2712aef6930SMark Murray 	    /*
2722aef6930SMark Murray 	     * Unable to verify that the name matches the address. This may
2732aef6930SMark Murray 	     * be a transient problem or a botched name server setup. We
2742aef6930SMark Murray 	     * decide to play safe.
2752aef6930SMark Murray 	     */
2762aef6930SMark Murray 
2772aef6930SMark Murray 	    tcpd_warn("can't verify hostname: netdir_getbyname(%.*s) failed",
2782aef6930SMark Murray 		      STRING_LENGTH, service->h_host);
2792aef6930SMark Murray 
2802aef6930SMark Murray 	} else {
2812aef6930SMark Murray 
2822aef6930SMark Murray 	    /*
2832aef6930SMark Murray 	     * Look up the host address in the address list we just got. The
2842aef6930SMark Murray 	     * comparison is done on the textual representation, because the
2852aef6930SMark Murray 	     * transport address is an opaque structure that may have holes
2862aef6930SMark Murray 	     * with uninitialized garbage. This approach obviously loses when
2872aef6930SMark Murray 	     * the address does not have a textual representation.
2882aef6930SMark Murray 	     */
2892aef6930SMark Murray 
2902aef6930SMark Murray 	    char   *uaddr = eval_hostaddr(host);
2912aef6930SMark Murray 	    char   *ua;
2922aef6930SMark Murray 	    int     i;
2932aef6930SMark Murray 
2942aef6930SMark Murray 	    for (i = 0; found == 0 && i < addr_list->n_cnt; i++) {
2952aef6930SMark Murray 		if ((ua = taddr2uaddr(config, &(addr_list->n_addrs[i]))) != 0) {
2962aef6930SMark Murray 		    found = !strcmp(ua, uaddr);
2972aef6930SMark Murray 		    free(ua);
2982aef6930SMark Murray 		}
2992aef6930SMark Murray 	    }
3002aef6930SMark Murray 	    netdir_free((void *) addr_list, ND_ADDRLIST);
3012aef6930SMark Murray 
3022aef6930SMark Murray 	    /*
3032aef6930SMark Murray 	     * When the host name does not map to the initial address, assume
3042aef6930SMark Murray 	     * someone has compromised a name server. More likely someone
3052aef6930SMark Murray 	     * botched it, but that could be dangerous, too.
3062aef6930SMark Murray 	     */
3072aef6930SMark Murray 
3082aef6930SMark Murray 	    if (found == 0)
3092aef6930SMark Murray 		tcpd_warn("host name/address mismatch: %s != %.*s",
3102aef6930SMark Murray 			  host->addr, STRING_LENGTH, service->h_host);
3112aef6930SMark Murray 	}
3122aef6930SMark Murray 	STRN_CPY(host->name, found ? service->h_host : paranoid,
3132aef6930SMark Murray 		 sizeof(host->name));
3142aef6930SMark Murray 	netdir_free((void *) servlist, ND_HOSTSERVLIST);
3152aef6930SMark Murray     }
3162aef6930SMark Murray }
3172aef6930SMark Murray 
3182aef6930SMark Murray /* tli_error - convert tli error number to text */
3192aef6930SMark Murray 
3202aef6930SMark Murray static char *tli_error()
3212aef6930SMark Murray {
3222aef6930SMark Murray     static char buf[40];
3232aef6930SMark Murray 
3242aef6930SMark Murray     if (t_errno != TSYSERR) {
3252aef6930SMark Murray 	if (t_errno < 0 || t_errno >= t_nerr) {
3262aef6930SMark Murray 	    sprintf(buf, "Unknown TLI error %d", t_errno);
3272aef6930SMark Murray 	    return (buf);
3282aef6930SMark Murray 	} else {
3292aef6930SMark Murray 	    return (t_errlist[t_errno]);
3302aef6930SMark Murray 	}
3312aef6930SMark Murray     } else {
3322aef6930SMark Murray 	if (errno < 0 || errno >= sys_nerr) {
3332aef6930SMark Murray 	    sprintf(buf, "Unknown UNIX error %d", errno);
3342aef6930SMark Murray 	    return (buf);
3352aef6930SMark Murray 	} else {
3362aef6930SMark Murray 	    return (sys_errlist[errno]);
3372aef6930SMark Murray 	}
3382aef6930SMark Murray     }
3392aef6930SMark Murray }
3402aef6930SMark Murray 
3412aef6930SMark Murray /* tli_sink - absorb unreceived datagram */
3422aef6930SMark Murray 
34314f102eaSEd Maste static void tli_sink(int fd)
3442aef6930SMark Murray {
3452aef6930SMark Murray     struct t_unitdata *unit;
3462aef6930SMark Murray     int     flags;
3472aef6930SMark Murray 
3482aef6930SMark Murray     /*
3492aef6930SMark Murray      * Something went wrong. Absorb the datagram to keep inetd from looping.
3502aef6930SMark Murray      * Allocate storage for address, control and data. If that fails, sleep
3512aef6930SMark Murray      * for a couple of seconds in an attempt to keep inetd from looping too
3522aef6930SMark Murray      * fast.
3532aef6930SMark Murray      */
3542aef6930SMark Murray 
3552aef6930SMark Murray     if ((unit = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ALL)) == 0) {
3562aef6930SMark Murray 	tcpd_warn("t_alloc: %s", tli_error());
3572aef6930SMark Murray 	sleep(5);
3582aef6930SMark Murray     } else {
3592aef6930SMark Murray 	(void) t_rcvudata(fd, unit, &flags);
3602aef6930SMark Murray 	t_free((void *) unit, T_UNITDATA);
3612aef6930SMark Murray     }
3622aef6930SMark Murray }
3632aef6930SMark Murray 
3642aef6930SMark Murray #endif /* TLI */
365