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.
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.
12 * Diagnostics are reported through syslog(3).
14 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
20 static char sccsid[] = "@(#) tli.c 1.15 97/03/21 19:27:25";
25 /* System libraries. */
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <sys/stream.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>
39 #include <netconfig.h>
43 extern char *nc_sperror();
44 extern char *sys_errlist[];
47 extern char *t_errlist[];
54 /* Forward declarations. */
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();
64 /* tli_host - look up endpoint addresses and install conversion methods */
66 void tli_host(struct request_info *request)
69 static struct sockaddr_storage client;
70 static struct sockaddr_storage server;
72 static struct sockaddr_in client;
73 static struct sockaddr_in server;
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.
82 tli_endpoints(request);
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"))) {
88 if ((request->config = tli_transport(request->fd)) != 0
89 && STR_EQ(request->config->nc_protofmly, "inet")) {
91 if (request->client->unit != 0) {
93 client = *(struct sockaddr_storage *) request->client->unit->addr.buf;
94 request->client->sin = (struct sockaddr *) &client;
96 client = *(struct sockaddr_in *) request->client->unit->addr.buf;
97 request->client->sin = &client;
100 if (request->server->unit != 0) {
102 server = *(struct sockaddr_storage *) request->server->unit->addr.buf;
103 request->server->sin = (struct sockaddr *) &server;
105 server = *(struct sockaddr_in *) request->server->unit->addr.buf;
106 request->server->sin = &server;
109 tli_cleanup(request);
110 sock_methods(request);
112 request->hostname = tli_hostname;
113 request->hostaddr = tli_hostaddr;
114 request->cleanup = tli_cleanup;
118 /* tli_cleanup - cleanup some dynamically-allocated data structures */
120 static void tli_cleanup(struct request_info *request)
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);
130 /* tli_endpoints - determine TLI client and server endpoint information */
132 static void tli_endpoints(struct request_info *request)
134 struct t_unitdata *server;
135 struct t_unitdata *client;
136 int fd = request->fd;
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.
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.
152 if ((client = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ADDR)) == 0) {
153 tcpd_warn("t_alloc: %s", tli_error());
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);
164 request->client->unit = client;
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.
171 if ((server = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ADDR)) == 0) {
172 tcpd_warn("t_alloc: %s", tli_error());
175 if (ioctl(fd, TI_GETMYNAME, &server->addr) < 0) {
176 tcpd_warn("TI_GETMYNAME: %m");
177 t_free((void *) server, T_UNITDATA);
180 request->server->unit = server;
183 /* tli_transport - find out TLI transport type */
185 static struct netconfig *tli_transport(int fd)
187 struct stat from_client;
188 struct stat from_config;
190 struct netconfig *config;
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.
198 if (fstat(fd, &from_client) != 0) {
199 tcpd_warn("fstat(fd %d): %m", fd);
202 if ((handlep = setnetconfig()) == 0) {
203 tcpd_warn("setnetconfig: %m");
206 while (config = getnetconfig(handlep)) {
207 if (stat(config->nc_device, &from_config) == 0) {
208 #ifdef NO_CLONE_DEVICE
210 * If the network devices are not cloned (as is the case for
211 * Solaris 8 Beta), we must compare the major device numbers.
213 if (major(from_config.st_rdev) == major(from_client.st_rdev))
215 if (minor(from_config.st_rdev) == major(from_client.st_rdev))
221 tcpd_warn("unable to identify transport protocol");
226 * Something else may clobber our getnetconfig() result, so we'd better
227 * acquire our private copy.
230 if ((config = getnetconfigent(config->nc_netid)) == 0) {
231 tcpd_warn("getnetconfigent(%s): %s", config->nc_netid, nc_sperror());
237 /* tli_hostaddr - map TLI transport address to printable address */
239 static void tli_hostaddr(struct host_info *host)
241 struct request_info *request = host->request;
242 struct netconfig *config = request->config;
243 struct t_unitdata *unit = host->unit;
246 if (config != 0 && unit != 0
247 && (uaddr = taddr2uaddr(config, &unit->addr)) != 0) {
248 STRN_CPY(host->addr, uaddr, sizeof(host->addr));
253 /* tli_hostname - map TLI transport address to hostname */
255 static void tli_hostname(struct host_info *host)
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;
262 if (config != 0 && unit != 0
263 && netdir_getbyaddr(config, &servlist, &unit->addr) == ND_OK) {
265 struct nd_hostserv *service = servlist->h_hostservs;
266 struct nd_addrlist *addr_list;
269 if (netdir_getbyname(config, service, &addr_list) != ND_OK) {
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.
277 tcpd_warn("can't verify hostname: netdir_getbyname(%.*s) failed",
278 STRING_LENGTH, service->h_host);
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.
290 char *uaddr = eval_hostaddr(host);
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);
300 netdir_free((void *) addr_list, ND_ADDRLIST);
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.
309 tcpd_warn("host name/address mismatch: %s != %.*s",
310 host->addr, STRING_LENGTH, service->h_host);
312 STRN_CPY(host->name, found ? service->h_host : paranoid,
314 netdir_free((void *) servlist, ND_HOSTSERVLIST);
318 /* tli_error - convert tli error number to text */
320 static char *tli_error()
324 if (t_errno != TSYSERR) {
325 if (t_errno < 0 || t_errno >= t_nerr) {
326 sprintf(buf, "Unknown TLI error %d", t_errno);
329 return (t_errlist[t_errno]);
332 if (errno < 0 || errno >= sys_nerr) {
333 sprintf(buf, "Unknown UNIX error %d", errno);
336 return (sys_errlist[errno]);
341 /* tli_sink - absorb unreceived datagram */
343 static void tli_sink(int fd)
345 struct t_unitdata *unit;
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
355 if ((unit = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ALL)) == 0) {
356 tcpd_warn("t_alloc: %s", tli_error());
359 (void) t_rcvudata(fd, unit, &flags);
360 t_free((void *) unit, T_UNITDATA);