source: trunk/third/tcp_wrappers/tli.c @ 11717

Revision 11717, 9.4 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r11716, which included commits to RCS files with non-trunk default branches.
Line 
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
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{
68    static struct sockaddr_in client;
69    static struct sockaddr_in server;
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);
78    if ((request->config = tli_transport(request->fd)) != 0
79        && STR_EQ(request->config->nc_protofmly, "inet")) {
80        if (request->client->unit != 0) {
81            client = *(struct sockaddr_in *) request->client->unit->addr.buf;
82            request->client->sin = &client;
83        }
84        if (request->server->unit != 0) {
85            server = *(struct sockaddr_in *) request->server->unit->addr.buf;
86            request->server->sin = &server;
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) {
190            if (minor(from_config.st_rdev) == major(from_client.st_rdev))
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 */
Note: See TracBrowser for help on using the repository browser.