dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libwrap / tli.c
blob1110b4199e4956bdf3289f5c2c116d005aac1ddb
1 /*
2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /*
7 * tli_host() determines the type of transport (connected, connectionless),
8 * the transport address of a client host, and the transport address of a
9 * server endpoint. In addition, it provides methods to map a transport
10 * address to a printable host name or address. Socket address results are
11 * in static memory; tli structures are allocated from the heap.
13 * The result from the hostname lookup method is STRING_PARANOID when a host
14 * pretends to have someone elses name, or when a host name is available but
15 * could not be verified.
17 * Diagnostics are reported through syslog(3).
19 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
22 static char sccsid[] = "@(#) tli.c 1.15 97/03/21 19:27:25";
24 #ifdef TLI
26 /* System libraries. */
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 <stdlib.h>
39 #include <unistd.h>
40 #include <syslog.h>
41 #include <errno.h>
42 #include <netconfig.h>
43 #include <netdir.h>
44 #include <string.h>
46 extern char *nc_sperror();
47 extern int errno;
48 extern int t_errno;
49 extern char *t_errlist[];
50 extern int t_nerr;
52 /* Local stuff. */
54 #include "tcpd.h"
56 /* Forward declarations. */
58 static void tli_endpoints();
59 static struct netconfig *tli_transport();
60 static void tli_hostname();
61 static void tli_hostaddr();
62 static void tli_cleanup();
63 static char *tli_error();
64 static void tli_sink();
66 /* tli_host - look up endpoint addresses and install conversion methods */
68 void tli_host(request)
69 struct request_info *request;
71 static struct sockaddr_gen client;
72 static struct sockaddr_gen server;
75 * If we discover that we are using an IP transport, pretend we never
76 * were here. Otherwise, use the transport-independent method and stick
77 * to generic network addresses. XXX hard-coded protocol family name.
80 tli_endpoints(request);
81 if ((request->config = tli_transport(request->fd)) != 0
82 && (STR_EQ(request->config->nc_protofmly, "inet")
83 #ifdef HAVE_IPV6
84 || STR_EQ(request->config->nc_protofmly, "inet6")
85 #endif
86 )) {
87 if (request->client->unit != 0) {
88 memcpy(&client, request->client->unit->addr.buf,
89 SGSOCKADDRSZ((struct sockaddr_gen*)
90 request->client->unit->addr.buf));
91 request->client->sin = &client;
92 sockgen_simplify(&client);
94 if (request->server->unit != 0) {
95 memcpy(&server, request->server->unit->addr.buf,
96 SGSOCKADDRSZ((struct sockaddr_gen*)
97 request->server->unit->addr.buf));
98 request->server->sin = &server;
99 sockgen_simplify(&server);
101 tli_cleanup(request);
102 sock_methods(request);
103 } else {
104 request->hostname = tli_hostname;
105 request->hostaddr = tli_hostaddr;
106 request->cleanup = tli_cleanup;
110 /* tli_cleanup - cleanup some dynamically-allocated data structures */
112 static void tli_cleanup(request)
113 struct request_info *request;
115 if (request->config != 0)
116 freenetconfigent(request->config);
117 if (request->client->unit != 0)
118 t_free((char *) request->client->unit, T_UNITDATA);
119 if (request->server->unit != 0)
120 t_free((char *) request->server->unit, T_UNITDATA);
123 /* tli_endpoints - determine TLI client and server endpoint information */
125 static void tli_endpoints(request)
126 struct request_info *request;
128 struct t_unitdata *server;
129 struct t_unitdata *client;
130 int fd = request->fd;
131 int flags;
134 * Determine the client endpoint address. With unconnected services, peek
135 * at the sender address of the pending protocol data unit without
136 * popping it off the receive queue. This trick works because only the
137 * address member of the unitdata structure has been allocated.
139 * Beware of successful returns with zero-length netbufs (for example,
140 * Solaris 2.3 with ticlts transport). The netdir(3) routines can't
141 * handle that. Assume connection-less transport when TI_GETPEERNAME
142 * produces no usable result, even when t_rcvudata() is unable to figure
143 * out the peer address. Better to hang than to loop.
146 if ((client = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ADDR)) == 0) {
147 tcpd_warn("t_alloc: %s", tli_error());
148 return;
150 if (ioctl(fd, TI_GETPEERNAME, &client->addr) < 0 || client->addr.len == 0) {
151 request->sink = tli_sink;
152 if (t_rcvudata(fd, client, &flags) < 0 || client->addr.len == 0) {
153 tcpd_warn("can't get client address: %s", tli_error());
154 t_free((void *) client, T_UNITDATA);
155 return;
158 request->client->unit = client;
161 * Look up the server endpoint address. This can be used for filtering on
162 * server address or name, or to look up the client user.
165 if ((server = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ADDR)) == 0) {
166 tcpd_warn("t_alloc: %s", tli_error());
167 return;
169 if (ioctl(fd, TI_GETMYNAME, &server->addr) < 0) {
170 tcpd_warn("TI_GETMYNAME: %m");
171 t_free((void *) server, T_UNITDATA);
172 return;
174 request->server->unit = server;
177 /* tli_transport - find out TLI transport type */
179 static struct netconfig *tli_transport(fd)
180 int fd;
182 struct stat from_client;
183 struct stat from_config;
184 void *handlep;
185 struct netconfig *config;
188 * Assuming that the network device is a clone device, we must compare
189 * the major device number of stdin to the minor device number of the
190 * devices listed in the netconfig table.
193 if (fstat(fd, &from_client) != 0) {
194 tcpd_warn("fstat(fd %d): %m", fd);
195 return (0);
197 if ((handlep = setnetconfig()) == 0) {
198 tcpd_warn("setnetconfig: %m");
199 return (0);
201 while (config = getnetconfig(handlep)) {
202 if (stat(config->nc_device, &from_config) == 0) {
203 if (minor(from_config.st_rdev) == major(from_client.st_rdev) ||
204 /* XXX: Solaris 8 no longer has clone devices for IP */
205 major(from_config.st_rdev) == major(from_client.st_rdev))
206 break;
209 if (config == 0) {
210 tcpd_warn("unable to identify transport protocol");
211 return (0);
215 * Something else may clobber our getnetconfig() result, so we'd better
216 * acquire our private copy.
219 if ((config = getnetconfigent(config->nc_netid)) == 0) {
220 tcpd_warn("getnetconfigent(%s): %s", config->nc_netid, nc_sperror());
221 return (0);
223 return (config);
226 /* tli_hostaddr - map TLI transport address to printable address */
228 static void tli_hostaddr(host)
229 struct host_info *host;
231 struct request_info *request = host->request;
232 struct netconfig *config = request->config;
233 struct t_unitdata *unit = host->unit;
234 char *uaddr;
236 if (config != 0 && unit != 0
237 && (uaddr = taddr2uaddr(config, &unit->addr)) != 0) {
238 STRN_CPY(host->addr, uaddr, sizeof(host->addr));
239 free(uaddr);
243 /* tli_hostname - map TLI transport address to hostname */
245 static void tli_hostname(host)
246 struct host_info *host;
248 struct request_info *request = host->request;
249 struct netconfig *config = request->config;
250 struct t_unitdata *unit = host->unit;
251 struct nd_hostservlist *servlist;
253 if (config != 0 && unit != 0
254 && netdir_getbyaddr(config, &servlist, &unit->addr) == ND_OK) {
256 struct nd_hostserv *service = servlist->h_hostservs;
257 struct nd_addrlist *addr_list;
258 int found = 0;
260 if (netdir_getbyname(config, service, &addr_list) != ND_OK) {
263 * Unable to verify that the name matches the address. This may
264 * be a transient problem or a botched name server setup. We
265 * decide to play safe.
268 tcpd_warn("can't verify hostname: netdir_getbyname(%.*s) failed",
269 STRING_LENGTH, service->h_host);
271 } else {
274 * Look up the host address in the address list we just got. The
275 * comparison is done on the textual representation, because the
276 * transport address is an opaque structure that may have holes
277 * with uninitialized garbage. This approach obviously loses when
278 * the address does not have a textual representation.
281 char *uaddr = eval_hostaddr(host);
282 char *ua;
283 int i;
285 for (i = 0; found == 0 && i < addr_list->n_cnt; i++) {
286 if ((ua = taddr2uaddr(config, &(addr_list->n_addrs[i]))) != 0) {
287 found = !strcmp(ua, uaddr);
288 free(ua);
291 netdir_free((void *) addr_list, ND_ADDRLIST);
294 * When the host name does not map to the initial address, assume
295 * someone has compromised a name server. More likely someone
296 * botched it, but that could be dangerous, too.
299 if (found == 0)
300 tcpd_warn("host name/address mismatch: %s != %.*s",
301 host->addr, STRING_LENGTH, service->h_host);
303 STRN_CPY(host->name, found ? service->h_host : paranoid,
304 sizeof(host->name));
305 netdir_free((void *) servlist, ND_HOSTSERVLIST);
309 /* tli_error - convert tli error number to text */
311 static char *tli_error()
313 static char buf[40];
315 if (t_errno != TSYSERR) {
316 if (t_errno < 0 || t_errno >= t_nerr) {
317 snprintf(buf, sizeof (buf), "Unknown TLI error %d", t_errno);
318 return (buf);
319 } else {
320 return (t_errlist[t_errno]);
322 } else {
323 STRN_CPY(buf, strerror(errno), sizeof (buf));
324 return (buf);
328 /* tli_sink - absorb unreceived datagram */
330 static void tli_sink(fd)
331 int fd;
333 struct t_unitdata *unit;
334 int flags;
337 * Something went wrong. Absorb the datagram to keep inetd from looping.
338 * Allocate storage for address, control and data. If that fails, sleep
339 * for a couple of seconds in an attempt to keep inetd from looping too
340 * fast.
343 if ((unit = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ALL)) == 0) {
344 tcpd_warn("t_alloc: %s", tli_error());
345 sleep(5);
346 } else {
347 (void) t_rcvudata(fd, unit, &flags);
348 t_free((void *) unit, T_UNITDATA);
352 #endif /* TLI */