1: /* 2: * tli_host() determines the type of transport (connected, connectionless), 3: * the transport address of a client host, and the transport address of a 4: * server endpoint. In addition, it provides methods to map a transport 5: * address to a printable host name or address. Socket address results are 6: * in static memory; tli structures are allocated from the heap. 7: * 8: * The result from the hostname lookup method is STRING_PARANOID when a host 9: * pretends to have someone elses name, or when a host name is available but 10: * could not be verified. 11: * 12: * Diagnostics are reported through syslog(3). 13: * 14: * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 15: */ 16: 17: #if !defined(lint) && defined(DOSCCS) 18: static char sccsid[] = "@(#) tli.c 1.14.1 96/03/23 22:26:03"; 19: #endif 20: 21: #ifdef TLI 22: 23: /* System libraries. */ 24: 25: #include <sys/types.h> 26: #include <sys/param.h> 27: #include <sys/stream.h> 28: #include <sys/stat.h> 29: #include <sys/mkdev.h> 30: #include <sys/tiuser.h> 31: #include <sys/timod.h> 32: #include <sys/socket.h> 33: #include <netinet/in.h> 34: #include <stdio.h> 35: #include <syslog.h> 36: #include <errno.h> 37: #include <netconfig.h> 38: #include <netdir.h> 39: #include <string.h> 40: 41: extern char *nc_sperror(); 42: extern int errno; 43: extern int t_errno; 44: extern char *t_errlist[]; 45: extern int t_nerr; 46: 47: /* Local stuff. */ 48: 49: #include "tcpd.h" 50: 51: /* Forward declarations. */ 52: 53: static void tli_endpoints(); 54: static struct netconfig *tli_transport(); 55: static void tli_hostname(); 56: static void tli_hostaddr(); 57: static void tli_cleanup(); 58: static char *tli_error(); 59: static void tli_sink(); 60: 61: /* tli_host - look up endpoint addresses and install conversion methods */ 62: 63: void tli_host(request) 64: struct request_info *request; 65: { 66: static struct sockaddr_in client; 67: static struct sockaddr_in server; 68: 69: /* 70: * If we discover that we are using an IP transport, pretend we never 71: * were here. Otherwise, use the transport-independent method and stick 72: * to generic network addresses. XXX hard-coded protocol family name. 73: */ 74: 75: tli_endpoints(request); 76: if ((request->config = tli_transport(request->fd)) != 0 77: && STR_EQ(request->config->nc_protofmly, "inet")) { 78: if (request->client->unit != 0) { 79: client = *(struct sockaddr_in *) request->client->unit->addr.buf; 80: request->client->sin = &client; 81: } 82: if (request->server->unit != 0) { 83: server = *(struct sockaddr_in *) request->server->unit->addr.buf; 84: request->server->sin = &server; 85: } 86: tli_cleanup(request); 87: sock_methods(request); 88: } else { 89: request->hostname = tli_hostname; 90: request->hostaddr = tli_hostaddr; 91: request->cleanup = tli_cleanup; 92: } 93: } 94: 95: /* tli_cleanup - cleanup some dynamically-allocated data structures */ 96: 97: static void tli_cleanup(request) 98: struct request_info *request; 99: { 100: if (request->config != 0) 101: freenetconfigent(request->config); 102: if (request->client->unit != 0) 103: t_free((char *) request->client->unit, T_UNITDATA); 104: if (request->server->unit != 0) 105: t_free((char *) request->server->unit, T_UNITDATA); 106: } 107: 108: /* tli_endpoints - determine TLI client and server endpoint information */ 109: 110: static void tli_endpoints(request) 111: struct request_info *request; 112: { 113: struct t_unitdata *server; 114: struct t_unitdata *client; 115: int fd = request->fd; 116: int flags; 117: 118: /* 119: * Determine the client endpoint address. With unconnected services, peek 120: * at the sender address of the pending protocol data unit without 121: * popping it off the receive queue. This trick works because only the 122: * address member of the unitdata structure has been allocated. 123: * 124: * Beware of successful returns with zero-length netbufs (for example, 125: * Solaris 2.3 with ticlts transport). The netdir(3) routines can't 126: * handle that. Assume connection-less transport when TI_GETPEERNAME 127: * produces no usable result, even when t_rcvudata() is unable to figure 128: * out the peer address. Better to hang than to loop. 129: */ 130: 131: if ((client = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ADDR)) == 0) { 132: tcpd_warn("t_alloc: %s", tli_error()); 133: return; 134: } 135: if (ioctl(fd, TI_GETPEERNAME, &client->addr) < 0 || client->addr.len == 0) { 136: request->sink = tli_sink; 137: if (t_rcvudata(fd, client, &flags) < 0 || client->addr.len == 0) { 138: tcpd_warn("can't get client address: %s", tli_error()); 139: t_free((void *) client, T_UNITDATA); 140: return; 141: } 142: } 143: request->client->unit = client; 144: 145: /* 146: * Look up the server endpoint address. This can be used for filtering on 147: * server address or name, or to look up the client user. 148: */ 149: 150: if ((server = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ADDR)) == 0) { 151: tcpd_warn("t_alloc: %s", tli_error()); 152: return; 153: } 154: if (ioctl(fd, TI_GETMYNAME, &server->addr) < 0) { 155: tcpd_warn("TI_GETMYNAME: %m"); 156: t_free((void *) server, T_UNITDATA); 157: return; 158: } 159: request->server->unit = server; 160: } 161: 162: /* tli_transport - find out TLI transport type */ 163: 164: static struct netconfig *tli_transport(fd) 165: int fd; 166: { 167: struct stat from_client; 168: struct stat from_config; 169: void *handlep; 170: struct netconfig *config; 171: 172: /* 173: * Assuming that the network device is a clone device, we must compare 174: * the major device number of stdin to the minor device number of the 175: * devices listed in the netconfig table. 176: */ 177: 178: if (fstat(fd, &from_client) != 0) { 179: tcpd_warn("fstat(fd %d): %m", fd); 180: return (0); 181: } 182: if ((handlep = setnetconfig()) == 0) { 183: tcpd_warn("setnetconfig: %m"); 184: return (0); 185: } 186: while (config = getnetconfig(handlep)) { 187: if (stat(config->nc_device, &from_config) == 0) { 188: if (minor(from_config.st_rdev) == major(from_client.st_rdev)) 189: break; 190: } 191: } 192: if (config == 0) { 193: tcpd_warn("unable to identify transport protocol"); 194: return (0); 195: } 196: 197: /* 198: * Something else may clobber our getnetconfig() result, so we'd better 199: * acquire our private copy. 200: */ 201: 202: if ((config = getnetconfigent(config->nc_netid)) == 0) { 203: tcpd_warn("getnetconfigent(%s): %s", config->nc_netid, nc_sperror()); 204: return (0); 205: } 206: return (config); 207: } 208: 209: /* tli_hostaddr - map TLI transport address to printable address */ 210: 211: static void tli_hostaddr(host) 212: struct host_info *host; 213: { 214: struct request_info *request = host->request; 215: struct netconfig *config = request->config; 216: struct t_unitdata *unit = host->unit; 217: char *uaddr; 218: 219: if (config != 0 && unit != 0 220: && (uaddr = taddr2uaddr(config, &unit->addr)) != 0) { 221: STRN_CPY(host->addr, uaddr, sizeof(host->addr)); 222: free(uaddr); 223: } 224: } 225: 226: /* tli_hostname - map TLI transport address to hostname */ 227: 228: static void tli_hostname(host) 229: struct host_info *host; 230: { 231: struct request_info *request = host->request; 232: struct netconfig *config = request->config; 233: struct t_unitdata *unit = host->unit; 234: struct nd_hostservlist *servlist; 235: 236: if (config != 0 && unit != 0 237: && netdir_getbyaddr(config, &servlist, &unit->addr) == ND_OK) { 238: 239: struct nd_hostserv *service = servlist->h_hostservs; 240: struct nd_addrlist *addr_list; 241: int found = 0; 242: 243: if (netdir_getbyname(config, service, &addr_list) != ND_OK) { 244: 245: /* 246: * Unable to verify that the name matches the address. This may 247: * be a transient problem or a botched name server setup. We 248: * decide to play safe. 249: */ 250: 251: tcpd_warn("can't verify hostname: netdir_getbyname(%s) failed", 252: service->h_host); 253: 254: } else { 255: 256: /* 257: * Look up the host address in the address list we just got. The 258: * comparison is done on the textual representation, because the 259: * transport address is an opaque structure that may have holes 260: * with uninitialized garbage. This approach obviously loses when 261: * the address does not have a textual representation. 262: */ 263: 264: char *uaddr = eval_hostaddr(host); 265: char *ua; 266: int i; 267: 268: for (i = 0; found == 0 && i < addr_list->n_cnt; i++) { 269: if ((ua = taddr2uaddr(config, &(addr_list->n_addrs[i]))) != 0) { 270: found = !strcmp(ua, uaddr); 271: free(ua); 272: } 273: } 274: netdir_free((void *) addr_list, ND_ADDRLIST); 275: 276: /* 277: * When the host name does not map to the initial address, assume 278: * someone has compromised a name server. More likely someone 279: * botched it, but that could be dangerous, too. 280: */ 281: 282: if (found == 0) 283: tcpd_warn("host name/address mismatch: %s != %s", 284: host->addr, service->h_host); 285: } 286: STRN_CPY(host->name, found ? service->h_host : paranoid, 287: sizeof(host->name)); 288: netdir_free((void *) servlist, ND_HOSTSERVLIST); 289: } 290: } 291: 292: /* tli_error - convert tli error number to text */ 293: 294: static char *tli_error() 295: { 296: static char buf[40]; 297: 298: if (t_errno != TSYSERR) { 299: if (t_errno < 0 || t_errno >= t_nerr) { 300: sprintf(buf, "Unknown TLI error %d", t_errno); 301: return (buf); 302: } else { 303: return (t_errlist[t_errno]); 304: } 305: } else 306: return(strerror(errno)); 307: } 308: 309: /* tli_sink - absorb unreceived datagram */ 310: 311: static void tli_sink(fd) 312: int fd; 313: { 314: struct t_unitdata *unit; 315: int flags; 316: 317: /* 318: * Something went wrong. Absorb the datagram to keep inetd from looping. 319: * Allocate storage for address, control and data. If that fails, sleep 320: * for a couple of seconds in an attempt to keep inetd from looping too 321: * fast. 322: */ 323: 324: if ((unit = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ALL)) == 0) { 325: tcpd_warn("t_alloc: %s", tli_error()); 326: sleep(5); 327: } else { 328: (void) t_rcvudata(fd, unit, &flags); 329: t_free((void *) unit, T_UNITDATA); 330: } 331: } 332: 333: #endif /* TLI */