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