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.
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.
12 * Diagnostics are reported through syslog(3).
14 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
16 * $FreeBSD: src/contrib/tcp_wrappers/tli.c,v 1.2 2000/02/03 10:27:00 shin Exp $
17 * $DragonFly: src/contrib/tcp_wrappers/tli.c,v 1.3 2005/04/29 01:00:27 joerg Exp $
21 static char sccsid
[] = "@(#) tli.c 1.15 97/03/21 19:27:25";
26 /* System libraries. */
28 #include <sys/types.h>
29 #include <sys/param.h>
30 #include <sys/stream.h>
32 #include <sys/mkdev.h>
33 #include <sys/tiuser.h>
34 #include <sys/timod.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
40 #include <netconfig.h>
44 extern char *nc_sperror();
45 extern char *sys_errlist
[];
48 extern char *t_errlist
[];
55 /* Forward declarations. */
57 static void tli_endpoints();
58 static struct netconfig
*tli_transport();
59 static void tli_hostname();
60 static void tli_hostaddr();
61 static void tli_cleanup();
62 static char *tli_error();
63 static void tli_sink();
65 /* tli_host - look up endpoint addresses and install conversion methods */
67 void tli_host(request
)
68 struct request_info
*request
;
71 static struct sockaddr_storage client
;
72 static struct sockaddr_storage server
;
74 static struct sockaddr_in client
;
75 static struct sockaddr_in server
;
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.
84 tli_endpoints(request
);
86 if ((request
->config
= tli_transport(request
->fd
)) != 0
87 && (STR_EQ(request
->config
->nc_protofmly
, "inet") ||
88 STR_EQ(request
->config
->nc_protofmly
, "inet6"))) {
90 if ((request
->config
= tli_transport(request
->fd
)) != 0
91 && STR_EQ(request
->config
->nc_protofmly
, "inet")) {
93 if (request
->client
->unit
!= 0) {
95 client
= *(struct sockaddr_storage
*) request
->client
->unit
->addr
.buf
;
96 request
->client
->sin
= (struct sockaddr
*) &client
;
98 client
= *(struct sockaddr_in
*) request
->client
->unit
->addr
.buf
;
99 request
->client
->sin
= &client
;
102 if (request
->server
->unit
!= 0) {
104 server
= *(struct sockaddr_storage
*) request
->server
->unit
->addr
.buf
;
105 request
->server
->sin
= (struct sockaddr
*) &server
;
107 server
= *(struct sockaddr_in
*) request
->server
->unit
->addr
.buf
;
108 request
->server
->sin
= &server
;
111 tli_cleanup(request
);
112 sock_methods(request
);
114 request
->hostname
= tli_hostname
;
115 request
->hostaddr
= tli_hostaddr
;
116 request
->cleanup
= tli_cleanup
;
120 /* tli_cleanup - cleanup some dynamically-allocated data structures */
122 static void tli_cleanup(request
)
123 struct request_info
*request
;
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
);
133 /* tli_endpoints - determine TLI client and server endpoint information */
135 static void tli_endpoints(request
)
136 struct request_info
*request
;
138 struct t_unitdata
*server
;
139 struct t_unitdata
*client
;
140 int fd
= request
->fd
;
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.
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.
156 if ((client
= (struct t_unitdata
*) t_alloc(fd
, T_UNITDATA
, T_ADDR
)) == 0) {
157 tcpd_warn("t_alloc: %s", tli_error());
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
);
168 request
->client
->unit
= client
;
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.
175 if ((server
= (struct t_unitdata
*) t_alloc(fd
, T_UNITDATA
, T_ADDR
)) == 0) {
176 tcpd_warn("t_alloc: %s", tli_error());
179 if (ioctl(fd
, TI_GETMYNAME
, &server
->addr
) < 0) {
180 tcpd_warn("TI_GETMYNAME: %m");
181 t_free((void *) server
, T_UNITDATA
);
184 request
->server
->unit
= server
;
187 /* tli_transport - find out TLI transport type */
189 static struct netconfig
*tli_transport(fd
)
192 struct stat from_client
;
193 struct stat from_config
;
195 struct netconfig
*config
;
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.
203 if (fstat(fd
, &from_client
) != 0) {
204 tcpd_warn("fstat(fd %d): %m", fd
);
207 if ((handlep
= setnetconfig()) == 0) {
208 tcpd_warn("setnetconfig: %m");
211 while (config
= getnetconfig(handlep
)) {
212 if (stat(config
->nc_device
, &from_config
) == 0) {
213 #ifdef NO_CLONE_DEVICE
215 * If the network devices are not cloned (as is the case for
216 * Solaris 8 Beta), we must compare the major device numbers.
218 if (major(from_config
.st_rdev
) == major(from_client
.st_rdev
))
220 if (minor(from_config
.st_rdev
) == major(from_client
.st_rdev
))
226 tcpd_warn("unable to identify transport protocol");
231 * Something else may clobber our getnetconfig() result, so we'd better
232 * acquire our private copy.
235 if ((config
= getnetconfigent(config
->nc_netid
)) == 0) {
236 tcpd_warn("getnetconfigent(%s): %s", config
->nc_netid
, nc_sperror());
242 /* tli_hostaddr - map TLI transport address to printable address */
244 static void tli_hostaddr(host
)
245 struct host_info
*host
;
247 struct request_info
*request
= host
->request
;
248 struct netconfig
*config
= request
->config
;
249 struct t_unitdata
*unit
= host
->unit
;
252 if (config
!= 0 && unit
!= 0
253 && (uaddr
= taddr2uaddr(config
, &unit
->addr
)) != 0) {
254 STRN_CPY(host
->addr
, uaddr
, sizeof(host
->addr
));
259 /* tli_hostname - map TLI transport address to hostname */
261 static void tli_hostname(host
)
262 struct host_info
*host
;
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
;
269 if (config
!= 0 && unit
!= 0
270 && netdir_getbyaddr(config
, &servlist
, &unit
->addr
) == ND_OK
) {
272 struct nd_hostserv
*service
= servlist
->h_hostservs
;
273 struct nd_addrlist
*addr_list
;
276 if (netdir_getbyname(config
, service
, &addr_list
) != ND_OK
) {
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.
284 tcpd_warn("can't verify hostname: netdir_getbyname(%.*s) failed",
285 STRING_LENGTH
, service
->h_host
);
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.
297 char *uaddr
= eval_hostaddr(host
);
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
);
307 netdir_free((void *) addr_list
, ND_ADDRLIST
);
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.
316 tcpd_warn("host name/address mismatch: %s != %.*s",
317 host
->addr
, STRING_LENGTH
, service
->h_host
);
319 STRN_CPY(host
->name
, found
? service
->h_host
: paranoid
,
321 netdir_free((void *) servlist
, ND_HOSTSERVLIST
);
325 /* tli_error - convert tli error number to text */
327 static char *tli_error()
331 if (t_errno
!= TSYSERR
) {
332 if (t_errno
< 0 || t_errno
>= t_nerr
) {
333 sprintf(buf
, "Unknown TLI error %d", t_errno
);
336 return (t_errlist
[t_errno
]);
339 if (errno
< 0 || errno
>= sys_nerr
) {
340 sprintf(buf
, "Unknown UNIX error %d", errno
);
343 return (sys_errlist
[errno
]);
348 /* tli_sink - absorb unreceived datagram */
350 static void tli_sink(fd
)
353 struct t_unitdata
*unit
;
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
363 if ((unit
= (struct t_unitdata
*) t_alloc(fd
, T_UNITDATA
, T_ALL
)) == 0) {
364 tcpd_warn("t_alloc: %s", tli_error());
367 (void) t_rcvudata(fd
, unit
, &flags
);
368 t_free((void *) unit
, T_UNITDATA
);