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 66*14f102eaSEd 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 120*14f102eaSEd 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 132*14f102eaSEd 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 1852aef6930SMark Murray static struct netconfig *tli_transport(fd) 1862aef6930SMark Murray int fd; 1872aef6930SMark Murray { 1882aef6930SMark Murray struct stat from_client; 1892aef6930SMark Murray struct stat from_config; 1902aef6930SMark Murray void *handlep; 1912aef6930SMark Murray struct netconfig *config; 1922aef6930SMark Murray 1932aef6930SMark Murray /* 1942aef6930SMark Murray * Assuming that the network device is a clone device, we must compare 1952aef6930SMark Murray * the major device number of stdin to the minor device number of the 1962aef6930SMark Murray * devices listed in the netconfig table. 1972aef6930SMark Murray */ 1982aef6930SMark Murray 1992aef6930SMark Murray if (fstat(fd, &from_client) != 0) { 2002aef6930SMark Murray tcpd_warn("fstat(fd %d): %m", fd); 2012aef6930SMark Murray return (0); 2022aef6930SMark Murray } 2032aef6930SMark Murray if ((handlep = setnetconfig()) == 0) { 2042aef6930SMark Murray tcpd_warn("setnetconfig: %m"); 2052aef6930SMark Murray return (0); 2062aef6930SMark Murray } 2072aef6930SMark Murray while (config = getnetconfig(handlep)) { 2082aef6930SMark Murray if (stat(config->nc_device, &from_config) == 0) { 2098053080cSYoshinobu Inoue #ifdef NO_CLONE_DEVICE 2108053080cSYoshinobu Inoue /* 2118053080cSYoshinobu Inoue * If the network devices are not cloned (as is the case for 2128053080cSYoshinobu Inoue * Solaris 8 Beta), we must compare the major device numbers. 2138053080cSYoshinobu Inoue */ 2148053080cSYoshinobu Inoue if (major(from_config.st_rdev) == major(from_client.st_rdev)) 2158053080cSYoshinobu Inoue #else 2162aef6930SMark Murray if (minor(from_config.st_rdev) == major(from_client.st_rdev)) 2178053080cSYoshinobu Inoue #endif 2182aef6930SMark Murray break; 2192aef6930SMark Murray } 2202aef6930SMark Murray } 2212aef6930SMark Murray if (config == 0) { 2222aef6930SMark Murray tcpd_warn("unable to identify transport protocol"); 2232aef6930SMark Murray return (0); 2242aef6930SMark Murray } 2252aef6930SMark Murray 2262aef6930SMark Murray /* 2272aef6930SMark Murray * Something else may clobber our getnetconfig() result, so we'd better 2282aef6930SMark Murray * acquire our private copy. 2292aef6930SMark Murray */ 2302aef6930SMark Murray 2312aef6930SMark Murray if ((config = getnetconfigent(config->nc_netid)) == 0) { 2322aef6930SMark Murray tcpd_warn("getnetconfigent(%s): %s", config->nc_netid, nc_sperror()); 2332aef6930SMark Murray return (0); 2342aef6930SMark Murray } 2352aef6930SMark Murray return (config); 2362aef6930SMark Murray } 2372aef6930SMark Murray 2382aef6930SMark Murray /* tli_hostaddr - map TLI transport address to printable address */ 2392aef6930SMark Murray 240*14f102eaSEd Maste static void tli_hostaddr(struct host_info *host) 2412aef6930SMark Murray { 2422aef6930SMark Murray struct request_info *request = host->request; 2432aef6930SMark Murray struct netconfig *config = request->config; 2442aef6930SMark Murray struct t_unitdata *unit = host->unit; 2452aef6930SMark Murray char *uaddr; 2462aef6930SMark Murray 2472aef6930SMark Murray if (config != 0 && unit != 0 2482aef6930SMark Murray && (uaddr = taddr2uaddr(config, &unit->addr)) != 0) { 2492aef6930SMark Murray STRN_CPY(host->addr, uaddr, sizeof(host->addr)); 2502aef6930SMark Murray free(uaddr); 2512aef6930SMark Murray } 2522aef6930SMark Murray } 2532aef6930SMark Murray 2542aef6930SMark Murray /* tli_hostname - map TLI transport address to hostname */ 2552aef6930SMark Murray 256*14f102eaSEd Maste static void tli_hostname(struct host_info *host) 2572aef6930SMark Murray { 2582aef6930SMark Murray struct request_info *request = host->request; 2592aef6930SMark Murray struct netconfig *config = request->config; 2602aef6930SMark Murray struct t_unitdata *unit = host->unit; 2612aef6930SMark Murray struct nd_hostservlist *servlist; 2622aef6930SMark Murray 2632aef6930SMark Murray if (config != 0 && unit != 0 2642aef6930SMark Murray && netdir_getbyaddr(config, &servlist, &unit->addr) == ND_OK) { 2652aef6930SMark Murray 2662aef6930SMark Murray struct nd_hostserv *service = servlist->h_hostservs; 2672aef6930SMark Murray struct nd_addrlist *addr_list; 2682aef6930SMark Murray int found = 0; 2692aef6930SMark Murray 2702aef6930SMark Murray if (netdir_getbyname(config, service, &addr_list) != ND_OK) { 2712aef6930SMark Murray 2722aef6930SMark Murray /* 2732aef6930SMark Murray * Unable to verify that the name matches the address. This may 2742aef6930SMark Murray * be a transient problem or a botched name server setup. We 2752aef6930SMark Murray * decide to play safe. 2762aef6930SMark Murray */ 2772aef6930SMark Murray 2782aef6930SMark Murray tcpd_warn("can't verify hostname: netdir_getbyname(%.*s) failed", 2792aef6930SMark Murray STRING_LENGTH, service->h_host); 2802aef6930SMark Murray 2812aef6930SMark Murray } else { 2822aef6930SMark Murray 2832aef6930SMark Murray /* 2842aef6930SMark Murray * Look up the host address in the address list we just got. The 2852aef6930SMark Murray * comparison is done on the textual representation, because the 2862aef6930SMark Murray * transport address is an opaque structure that may have holes 2872aef6930SMark Murray * with uninitialized garbage. This approach obviously loses when 2882aef6930SMark Murray * the address does not have a textual representation. 2892aef6930SMark Murray */ 2902aef6930SMark Murray 2912aef6930SMark Murray char *uaddr = eval_hostaddr(host); 2922aef6930SMark Murray char *ua; 2932aef6930SMark Murray int i; 2942aef6930SMark Murray 2952aef6930SMark Murray for (i = 0; found == 0 && i < addr_list->n_cnt; i++) { 2962aef6930SMark Murray if ((ua = taddr2uaddr(config, &(addr_list->n_addrs[i]))) != 0) { 2972aef6930SMark Murray found = !strcmp(ua, uaddr); 2982aef6930SMark Murray free(ua); 2992aef6930SMark Murray } 3002aef6930SMark Murray } 3012aef6930SMark Murray netdir_free((void *) addr_list, ND_ADDRLIST); 3022aef6930SMark Murray 3032aef6930SMark Murray /* 3042aef6930SMark Murray * When the host name does not map to the initial address, assume 3052aef6930SMark Murray * someone has compromised a name server. More likely someone 3062aef6930SMark Murray * botched it, but that could be dangerous, too. 3072aef6930SMark Murray */ 3082aef6930SMark Murray 3092aef6930SMark Murray if (found == 0) 3102aef6930SMark Murray tcpd_warn("host name/address mismatch: %s != %.*s", 3112aef6930SMark Murray host->addr, STRING_LENGTH, service->h_host); 3122aef6930SMark Murray } 3132aef6930SMark Murray STRN_CPY(host->name, found ? service->h_host : paranoid, 3142aef6930SMark Murray sizeof(host->name)); 3152aef6930SMark Murray netdir_free((void *) servlist, ND_HOSTSERVLIST); 3162aef6930SMark Murray } 3172aef6930SMark Murray } 3182aef6930SMark Murray 3192aef6930SMark Murray /* tli_error - convert tli error number to text */ 3202aef6930SMark Murray 3212aef6930SMark Murray static char *tli_error() 3222aef6930SMark Murray { 3232aef6930SMark Murray static char buf[40]; 3242aef6930SMark Murray 3252aef6930SMark Murray if (t_errno != TSYSERR) { 3262aef6930SMark Murray if (t_errno < 0 || t_errno >= t_nerr) { 3272aef6930SMark Murray sprintf(buf, "Unknown TLI error %d", t_errno); 3282aef6930SMark Murray return (buf); 3292aef6930SMark Murray } else { 3302aef6930SMark Murray return (t_errlist[t_errno]); 3312aef6930SMark Murray } 3322aef6930SMark Murray } else { 3332aef6930SMark Murray if (errno < 0 || errno >= sys_nerr) { 3342aef6930SMark Murray sprintf(buf, "Unknown UNIX error %d", errno); 3352aef6930SMark Murray return (buf); 3362aef6930SMark Murray } else { 3372aef6930SMark Murray return (sys_errlist[errno]); 3382aef6930SMark Murray } 3392aef6930SMark Murray } 3402aef6930SMark Murray } 3412aef6930SMark Murray 3422aef6930SMark Murray /* tli_sink - absorb unreceived datagram */ 3432aef6930SMark Murray 344*14f102eaSEd Maste static void tli_sink(int fd) 3452aef6930SMark Murray { 3462aef6930SMark Murray struct t_unitdata *unit; 3472aef6930SMark Murray int flags; 3482aef6930SMark Murray 3492aef6930SMark Murray /* 3502aef6930SMark Murray * Something went wrong. Absorb the datagram to keep inetd from looping. 3512aef6930SMark Murray * Allocate storage for address, control and data. If that fails, sleep 3522aef6930SMark Murray * for a couple of seconds in an attempt to keep inetd from looping too 3532aef6930SMark Murray * fast. 3542aef6930SMark Murray */ 3552aef6930SMark Murray 3562aef6930SMark Murray if ((unit = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ALL)) == 0) { 3572aef6930SMark Murray tcpd_warn("t_alloc: %s", tli_error()); 3582aef6930SMark Murray sleep(5); 3592aef6930SMark Murray } else { 3602aef6930SMark Murray (void) t_rcvudata(fd, unit, &flags); 3612aef6930SMark Murray t_free((void *) unit, T_UNITDATA); 3622aef6930SMark Murray } 3632aef6930SMark Murray } 3642aef6930SMark Murray 3652aef6930SMark Murray #endif /* TLI */ 366