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