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