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 */
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 */