]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcp_wrappers/tli.c
tpcdump: Update to 4.99.4
[FreeBSD/FreeBSD.git] / contrib / tcp_wrappers / tli.c
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$
17   */
18
19 #ifndef lint
20 static 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
43 extern char *nc_sperror();
44 extern char *sys_errlist[];
45 extern int sys_nerr;
46 extern int t_errno;
47 extern char *t_errlist[];
48 extern int t_nerr;
49
50 /* Local stuff. */
51
52 #include "tcpd.h"
53
54 /* Forward declarations. */
55
56 static void tli_endpoints();
57 static struct netconfig *tli_transport();
58 static void tli_hostname();
59 static void tli_hostaddr();
60 static void tli_cleanup();
61 static char *tli_error();
62 static void tli_sink();
63
64 /* tli_host - look up endpoint addresses and install conversion methods */
65
66 void    tli_host(struct request_info *request)
67 {
68 #ifdef INET6
69     static struct sockaddr_storage client;
70     static struct sockaddr_storage server;
71 #else
72     static struct sockaddr_in client;
73     static struct sockaddr_in server;
74 #endif
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 #ifdef INET6
84     if ((request->config = tli_transport(request->fd)) != 0
85         && (STR_EQ(request->config->nc_protofmly, "inet") ||
86             STR_EQ(request->config->nc_protofmly, "inet6"))) {
87 #else
88     if ((request->config = tli_transport(request->fd)) != 0
89         && STR_EQ(request->config->nc_protofmly, "inet")) {
90 #endif
91         if (request->client->unit != 0) {
92 #ifdef INET6
93             client = *(struct sockaddr_storage *) request->client->unit->addr.buf;
94             request->client->sin = (struct sockaddr *) &client;
95 #else
96             client = *(struct sockaddr_in *) request->client->unit->addr.buf;
97             request->client->sin = &client;
98 #endif
99         }
100         if (request->server->unit != 0) {
101 #ifdef INET6
102             server = *(struct sockaddr_storage *) request->server->unit->addr.buf;
103             request->server->sin = (struct sockaddr *) &server;
104 #else
105             server = *(struct sockaddr_in *) request->server->unit->addr.buf;
106             request->server->sin = &server;
107 #endif
108         }
109         tli_cleanup(request);
110         sock_methods(request);
111     } else {
112         request->hostname = tli_hostname;
113         request->hostaddr = tli_hostaddr;
114         request->cleanup = tli_cleanup;
115     }
116 }
117
118 /* tli_cleanup - cleanup some dynamically-allocated data structures */
119
120 static void tli_cleanup(struct request_info *request)
121 {
122     if (request->config != 0)
123         freenetconfigent(request->config);
124     if (request->client->unit != 0)
125         t_free((char *) request->client->unit, T_UNITDATA);
126     if (request->server->unit != 0)
127         t_free((char *) request->server->unit, T_UNITDATA);
128 }
129
130 /* tli_endpoints - determine TLI client and server endpoint information */
131
132 static void tli_endpoints(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(int fd)
186 {
187     struct stat from_client;
188     struct stat from_config;
189     void   *handlep;
190     struct netconfig *config;
191
192     /*
193      * Assuming that the network device is a clone device, we must compare
194      * the major device number of stdin to the minor device number of the
195      * devices listed in the netconfig table.
196      */
197
198     if (fstat(fd, &from_client) != 0) {
199         tcpd_warn("fstat(fd %d): %m", fd);
200         return (0);
201     }
202     if ((handlep = setnetconfig()) == 0) {
203         tcpd_warn("setnetconfig: %m");
204         return (0);
205     }
206     while (config = getnetconfig(handlep)) {
207         if (stat(config->nc_device, &from_config) == 0) {
208 #ifdef NO_CLONE_DEVICE
209         /*
210          * If the network devices are not cloned (as is the case for
211          * Solaris 8 Beta), we must compare the major device numbers.
212          */
213             if (major(from_config.st_rdev) == major(from_client.st_rdev))
214 #else
215             if (minor(from_config.st_rdev) == major(from_client.st_rdev))
216 #endif
217                 break;
218         }
219     }
220     if (config == 0) {
221         tcpd_warn("unable to identify transport protocol");
222         return (0);
223     }
224
225     /*
226      * Something else may clobber our getnetconfig() result, so we'd better
227      * acquire our private copy.
228      */
229
230     if ((config = getnetconfigent(config->nc_netid)) == 0) {
231         tcpd_warn("getnetconfigent(%s): %s", config->nc_netid, nc_sperror());
232         return (0);
233     }
234     return (config);
235 }
236
237 /* tli_hostaddr - map TLI transport address to printable address */
238
239 static void tli_hostaddr(struct host_info *host)
240 {
241     struct request_info *request = host->request;
242     struct netconfig *config = request->config;
243     struct t_unitdata *unit = host->unit;
244     char   *uaddr;
245
246     if (config != 0 && unit != 0
247         && (uaddr = taddr2uaddr(config, &unit->addr)) != 0) {
248         STRN_CPY(host->addr, uaddr, sizeof(host->addr));
249         free(uaddr);
250     }
251 }
252
253 /* tli_hostname - map TLI transport address to hostname */
254
255 static void tli_hostname(struct host_info *host)
256 {
257     struct request_info *request = host->request;
258     struct netconfig *config = request->config;
259     struct t_unitdata *unit = host->unit;
260     struct nd_hostservlist *servlist;
261
262     if (config != 0 && unit != 0
263         && netdir_getbyaddr(config, &servlist, &unit->addr) == ND_OK) {
264
265         struct nd_hostserv *service = servlist->h_hostservs;
266         struct nd_addrlist *addr_list;
267         int     found = 0;
268
269         if (netdir_getbyname(config, service, &addr_list) != ND_OK) {
270
271             /*
272              * Unable to verify that the name matches the address. This may
273              * be a transient problem or a botched name server setup. We
274              * decide to play safe.
275              */
276
277             tcpd_warn("can't verify hostname: netdir_getbyname(%.*s) failed",
278                       STRING_LENGTH, service->h_host);
279
280         } else {
281
282             /*
283              * Look up the host address in the address list we just got. The
284              * comparison is done on the textual representation, because the
285              * transport address is an opaque structure that may have holes
286              * with uninitialized garbage. This approach obviously loses when
287              * the address does not have a textual representation.
288              */
289
290             char   *uaddr = eval_hostaddr(host);
291             char   *ua;
292             int     i;
293
294             for (i = 0; found == 0 && i < addr_list->n_cnt; i++) {
295                 if ((ua = taddr2uaddr(config, &(addr_list->n_addrs[i]))) != 0) {
296                     found = !strcmp(ua, uaddr);
297                     free(ua);
298                 }
299             }
300             netdir_free((void *) addr_list, ND_ADDRLIST);
301
302             /*
303              * When the host name does not map to the initial address, assume
304              * someone has compromised a name server. More likely someone
305              * botched it, but that could be dangerous, too.
306              */
307
308             if (found == 0)
309                 tcpd_warn("host name/address mismatch: %s != %.*s",
310                           host->addr, STRING_LENGTH, service->h_host);
311         }
312         STRN_CPY(host->name, found ? service->h_host : paranoid,
313                  sizeof(host->name));
314         netdir_free((void *) servlist, ND_HOSTSERVLIST);
315     }
316 }
317
318 /* tli_error - convert tli error number to text */
319
320 static char *tli_error()
321 {
322     static char buf[40];
323
324     if (t_errno != TSYSERR) {
325         if (t_errno < 0 || t_errno >= t_nerr) {
326             sprintf(buf, "Unknown TLI error %d", t_errno);
327             return (buf);
328         } else {
329             return (t_errlist[t_errno]);
330         }
331     } else {
332         if (errno < 0 || errno >= sys_nerr) {
333             sprintf(buf, "Unknown UNIX error %d", errno);
334             return (buf);
335         } else {
336             return (sys_errlist[errno]);
337         }
338     }
339 }
340
341 /* tli_sink - absorb unreceived datagram */
342
343 static void tli_sink(int fd)
344 {
345     struct t_unitdata *unit;
346     int     flags;
347
348     /*
349      * Something went wrong. Absorb the datagram to keep inetd from looping.
350      * Allocate storage for address, control and data. If that fails, sleep
351      * for a couple of seconds in an attempt to keep inetd from looping too
352      * fast.
353      */
354
355     if ((unit = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ALL)) == 0) {
356         tcpd_warn("t_alloc: %s", tli_error());
357         sleep(5);
358     } else {
359         (void) t_rcvudata(fd, unit, &flags);
360         t_free((void *) unit, T_UNITDATA);
361     }
362 }
363
364 #endif /* TLI */