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