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