#ifndef lint
static char sccsid[] = "@(#) tli.c 1.15 97/03/21 19:27:25";
#endif
#ifdef TLI
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stream.h>
#include <sys/stat.h>
#include <sys/mkdev.h>
#include <sys/tiuser.h>
#include <sys/timod.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <errno.h>
#include <netconfig.h>
#include <netdir.h>
#include <string.h>
extern char *nc_sperror();
extern int errno;
extern int t_errno;
extern char *t_errlist[];
extern int t_nerr;
#include "tcpd.h"
static void tli_endpoints();
static struct netconfig *tli_transport();
static void tli_hostname();
static void tli_hostaddr();
static void tli_cleanup();
static char *tli_error();
static void tli_sink();
void tli_host(request)
struct request_info *request;
{
static struct sockaddr_gen client;
static struct sockaddr_gen server;
tli_endpoints(request);
if ((request->config = tli_transport(request->fd)) != 0
&& (STR_EQ(request->config->nc_protofmly, "inet")
#ifdef HAVE_IPV6
|| STR_EQ(request->config->nc_protofmly, "inet6")
#endif
)) {
if (request->client->unit != 0) {
memcpy(&client, request->client->unit->addr.buf,
SGSOCKADDRSZ((struct sockaddr_gen*)
request->client->unit->addr.buf));
request->client->sin = &client;
sockgen_simplify(&client);
}
if (request->server->unit != 0) {
memcpy(&server, request->server->unit->addr.buf,
SGSOCKADDRSZ((struct sockaddr_gen*)
request->server->unit->addr.buf));
request->server->sin = &server;
sockgen_simplify(&server);
}
tli_cleanup(request);
sock_methods(request);
} else {
request->hostname = tli_hostname;
request->hostaddr = tli_hostaddr;
request->cleanup = tli_cleanup;
}
}
static void tli_cleanup(request)
struct request_info *request;
{
if (request->config != 0)
freenetconfigent(request->config);
if (request->client->unit != 0)
t_free((char *) request->client->unit, T_UNITDATA);
if (request->server->unit != 0)
t_free((char *) request->server->unit, T_UNITDATA);
}
static void tli_endpoints(request)
struct request_info *request;
{
struct t_unitdata *server;
struct t_unitdata *client;
int fd = request->fd;
int flags;
if ((client = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ADDR)) == 0) {
tcpd_warn("t_alloc: %s", tli_error());
return;
}
if (ioctl(fd, TI_GETPEERNAME, &client->addr) < 0 || client->addr.len == 0) {
request->sink = tli_sink;
if (t_rcvudata(fd, client, &flags) < 0 || client->addr.len == 0) {
tcpd_warn("can't get client address: %s", tli_error());
t_free((void *) client, T_UNITDATA);
return;
}
}
request->client->unit = client;
if ((server = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ADDR)) == 0) {
tcpd_warn("t_alloc: %s", tli_error());
return;
}
if (ioctl(fd, TI_GETMYNAME, &server->addr) < 0) {
tcpd_warn("TI_GETMYNAME: %m");
t_free((void *) server, T_UNITDATA);
return;
}
request->server->unit = server;
}
static struct netconfig *tli_transport(fd)
int fd;
{
struct stat from_client;
struct stat from_config;
void *handlep;
struct netconfig *config;
if (fstat(fd, &from_client) != 0) {
tcpd_warn("fstat(fd %d): %m", fd);
return (0);
}
if ((handlep = setnetconfig()) == 0) {
tcpd_warn("setnetconfig: %m");
return (0);
}
while (config = getnetconfig(handlep)) {
if (stat(config->nc_device, &from_config) == 0) {
if (minor(from_config.st_rdev) == major(from_client.st_rdev) ||
major(from_config.st_rdev) == major(from_client.st_rdev))
break;
}
}
if (config == 0) {
tcpd_warn("unable to identify transport protocol");
return (0);
}
if ((config = getnetconfigent(config->nc_netid)) == 0) {
tcpd_warn("getnetconfigent(%s): %s", config->nc_netid, nc_sperror());
return (0);
}
return (config);
}
static void tli_hostaddr(host)
struct host_info *host;
{
struct request_info *request = host->request;
struct netconfig *config = request->config;
struct t_unitdata *unit = host->unit;
char *uaddr;
if (config != 0 && unit != 0
&& (uaddr = taddr2uaddr(config, &unit->addr)) != 0) {
STRN_CPY(host->addr, uaddr, sizeof(host->addr));
free(uaddr);
}
}
static void tli_hostname(host)
struct host_info *host;
{
struct request_info *request = host->request;
struct netconfig *config = request->config;
struct t_unitdata *unit = host->unit;
struct nd_hostservlist *servlist;
if (config != 0 && unit != 0
&& netdir_getbyaddr(config, &servlist, &unit->addr) == ND_OK) {
struct nd_hostserv *service = servlist->h_hostservs;
struct nd_addrlist *addr_list;
int found = 0;
if (netdir_getbyname(config, service, &addr_list) != ND_OK) {
tcpd_warn("can't verify hostname: netdir_getbyname(%.*s) failed",
STRING_LENGTH, service->h_host);
} else {
char *uaddr = eval_hostaddr(host);
char *ua;
int i;
for (i = 0; found == 0 && i < addr_list->n_cnt; i++) {
if ((ua = taddr2uaddr(config, &(addr_list->n_addrs[i]))) != 0) {
found = !strcmp(ua, uaddr);
free(ua);
}
}
netdir_free((void *) addr_list, ND_ADDRLIST);
if (found == 0)
tcpd_warn("host name/address mismatch: %s != %.*s",
host->addr, STRING_LENGTH, service->h_host);
}
STRN_CPY(host->name, found ? service->h_host : paranoid,
sizeof(host->name));
netdir_free((void *) servlist, ND_HOSTSERVLIST);
}
}
static char *tli_error()
{
static char buf[40];
if (t_errno != TSYSERR) {
if (t_errno < 0 || t_errno >= t_nerr) {
snprintf(buf, sizeof (buf), "Unknown TLI error %d", t_errno);
return (buf);
} else {
return (t_errlist[t_errno]);
}
} else {
STRN_CPY(buf, strerror(errno), sizeof (buf));
return (buf);
}
}
static void tli_sink(fd)
int fd;
{
struct t_unitdata *unit;
int flags;
if ((unit = (struct t_unitdata *) t_alloc(fd, T_UNITDATA, T_ALL)) == 0) {
tcpd_warn("t_alloc: %s", tli_error());
sleep(5);
} else {
(void) t_rcvudata(fd, unit, &flags);
t_free((void *) unit, T_UNITDATA);
}
}
#endif