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