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