
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@524 ec53bebd-3082-4978-b11e-865c3cabbd6b
228 lines
5.4 KiB
C
228 lines
5.4 KiB
C
#include "kx.h"
|
|
|
|
RCSID("$Id$");
|
|
|
|
char *prog;
|
|
|
|
static void
|
|
usage()
|
|
{
|
|
fprintf (stderr, "Usage: %s host\n",
|
|
prog);
|
|
exit (1);
|
|
}
|
|
|
|
/*
|
|
* Establish authenticated connection
|
|
*/
|
|
|
|
static int
|
|
connect_host (char *host, des_cblock *key, des_key_schedule schedule)
|
|
{
|
|
CREDENTIALS cred;
|
|
KTEXT_ST text;
|
|
MSG_DAT msg;
|
|
int status;
|
|
struct sockaddr_in thisaddr, thataddr;
|
|
int addrlen;
|
|
struct hostent *hostent;
|
|
int s;
|
|
u_char b;
|
|
|
|
hostent = gethostbyname (host);
|
|
if (hostent == NULL) {
|
|
fprintf (stderr, "%s: gethostbyname '%s' failed: ", prog, host);
|
|
return -1;
|
|
}
|
|
|
|
memset (&thataddr, 0, sizeof(thataddr));
|
|
thataddr.sin_family = AF_INET;
|
|
thataddr.sin_port = k_getportbyname ("kx", "tcp", htons(2111));
|
|
memcpy (&thataddr.sin_addr, hostent->h_addr, sizeof(thataddr.sin_addr));
|
|
|
|
s = socket (AF_INET, SOCK_STREAM, 0);
|
|
if (s < 0) {
|
|
fprintf (stderr, "%s: socket failed: %s\n", prog, strerror(errno));
|
|
return -1;
|
|
}
|
|
if (connect (s, (struct sockaddr *)&thataddr, sizeof(thataddr)) < 0) {
|
|
fprintf (stderr, "%s: connect(%s) failed: %s\n", prog, host,
|
|
strerror(errno));
|
|
return -1;
|
|
}
|
|
addrlen = sizeof(thisaddr);
|
|
if (getsockname (s, (struct sockaddr *)&thisaddr, &addrlen) < 0 ||
|
|
addrlen != sizeof(thisaddr)) {
|
|
fprintf (stderr, "%s: getsockname(%s) failed: %s\n",
|
|
prog, host, strerror(errno));
|
|
return -1;
|
|
}
|
|
status = krb_sendauth (KOPT_DO_MUTUAL, s, &text, "rcmd",
|
|
host, krb_realmofhost (host),
|
|
getpid(), &msg, &cred, schedule,
|
|
&thisaddr, &thataddr, "KXSERV.0");
|
|
if (status != KSUCCESS) {
|
|
fprintf (stderr, "%s: %s: %s\n", prog, host,
|
|
krb_get_err_text(status));
|
|
return -1;
|
|
}
|
|
if (read (s, &b, sizeof(b)) != sizeof(b)) {
|
|
fprintf (stderr, "%s: read: %s\n", prog,
|
|
strerror(errno));
|
|
return -1;
|
|
}
|
|
if (b) {
|
|
char buf[BUFSIZ];
|
|
|
|
read (s, buf, sizeof(buf));
|
|
buf[BUFSIZ - 1] = '\0';
|
|
|
|
fprintf (stderr, "%s: %s: %s\n", prog, host, buf);
|
|
return -1;
|
|
}
|
|
|
|
memcpy(key, &cred.session, sizeof(des_cblock));
|
|
return s;
|
|
}
|
|
|
|
static int
|
|
active (int fd, char *host, des_cblock *iv, des_key_schedule schedule)
|
|
{
|
|
int kxd;
|
|
u_char zero = 0;
|
|
|
|
kxd = connect_host (host, iv, schedule);
|
|
if (kxd < 0)
|
|
return 1;
|
|
if (write (kxd, &zero, sizeof(zero)) != sizeof(zero)) {
|
|
fprintf (stderr, "%s: write: %s\n", prog,
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
return copy_encrypted (fd, kxd, iv, schedule);
|
|
}
|
|
|
|
static int
|
|
passive (int fd, char *host, des_cblock *iv, des_key_schedule schedule)
|
|
{
|
|
int xserver;
|
|
|
|
xserver = connect_local_xsocket (0);
|
|
if (xserver < 0)
|
|
return 1;
|
|
return copy_encrypted (xserver, fd, iv, schedule);
|
|
}
|
|
|
|
/*
|
|
* Connect to the given host.
|
|
* Iff passivep, give it a port number to call you back and then wait.
|
|
* Else, listen on a local display and then connect to the remote host
|
|
* when a local client gets connected.
|
|
*/
|
|
|
|
static int
|
|
doit (char *host, int passivep)
|
|
{
|
|
int otherside;
|
|
des_key_schedule schedule;
|
|
des_cblock key;
|
|
int rendez_vous;
|
|
int (*fn)(int fd, char *host, des_cblock *iv,
|
|
des_key_schedule schedule);
|
|
|
|
if (passivep) {
|
|
struct sockaddr_in newaddr;
|
|
int addrlen;
|
|
u_char b = passivep;
|
|
int otherside;
|
|
|
|
otherside = connect_host (host, &key, schedule);
|
|
if (otherside < 0)
|
|
return 1;
|
|
|
|
rendez_vous = socket (AF_INET, SOCK_STREAM, 0);
|
|
if (rendez_vous < 0) {
|
|
fprintf (stderr, "%s: socket failed: %s\n", prog,
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
memset (&newaddr, 0, sizeof(newaddr));
|
|
if (bind (rendez_vous, (struct sockaddr *)&newaddr,
|
|
sizeof(newaddr)) < 0) {
|
|
fprintf (stderr, "%s: bind: %s\n", prog, strerror(errno));
|
|
return 1;
|
|
}
|
|
addrlen = sizeof(newaddr);
|
|
if (getsockname (rendez_vous, (struct sockaddr *)&newaddr,
|
|
&addrlen) < 0) {
|
|
fprintf (stderr, "%s: getsockname: %s\n", prog,
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
if (listen (rendez_vous, SOMAXCONN) < 0) {
|
|
fprintf (stderr, "%s: listen: %s\n", prog, strerror(errno));
|
|
return 1;
|
|
}
|
|
if (write (otherside, &b, sizeof(b)) != sizeof(b) ||
|
|
write (otherside, &newaddr.sin_port, sizeof(newaddr.sin_port))
|
|
!= sizeof(newaddr.sin_port)) {
|
|
fprintf (stderr, "%s: write: %s\n", prog, strerror(errno));
|
|
return 1;
|
|
}
|
|
close (otherside);
|
|
fn = passive;
|
|
} else {
|
|
rendez_vous = get_local_xsocket (1); /* XXX */
|
|
if (rendez_vous < 0)
|
|
return 1;
|
|
fn = active;
|
|
}
|
|
for (;;) {
|
|
pid_t child;
|
|
int fd;
|
|
int zero = 0;
|
|
|
|
fd = accept (rendez_vous, NULL, &zero);
|
|
if (fd < 0)
|
|
if (errno == EINTR)
|
|
continue;
|
|
else {
|
|
fprintf (stderr, "%s: accept: %s\n", prog,
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
child = fork ();
|
|
if (child < 0) {
|
|
fprintf (stderr, "%s: fork: %s\n", prog,
|
|
strerror(errno));
|
|
continue;
|
|
} else if (child == 0) {
|
|
close (rendez_vous);
|
|
return (*fn)(fd, host, &key, schedule);
|
|
} else {
|
|
close (fd);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* kx - forward x connection over a kerberos-encrypted channel.
|
|
*
|
|
* passive mode if $DISPLAY begins with :
|
|
*/
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
int passivep;
|
|
char *disp;
|
|
|
|
prog = argv[0];
|
|
if (argc != 2)
|
|
usage ();
|
|
disp = getenv("DISPLAY");
|
|
passivep = disp != NULL && *disp == ':';
|
|
signal (SIGCHLD, childhandler);
|
|
return doit (argv[1], passivep);
|
|
}
|