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