diff --git a/appl/kx/Makefile.in b/appl/kx/Makefile.in new file mode 100644 index 000000000..7a84dfa71 --- /dev/null +++ b/appl/kx/Makefile.in @@ -0,0 +1,77 @@ +SHELL = /bin/sh + +srcdir = @srcdir@ +VPATH = @srcdir@ + +CC = @CC@ +AR = ar +DEFS = @DEFS@ +CFLAGS = @CFLAGS@ +INSTALL = @INSTALL@ +LIBS = @LIBS@ +MKDIRHIER = @top_srcdir@/mkdirhier-sh + +prefix = @prefix@ +exec_prefix = $(prefix) +libdir = $(exec_prefix)/lib +libexecdir = $(exec_prefix)/libexec +bindir = $(exec_prefix)/bin + +PROG_BIN = kx +PROG_LIBEXEC = kxd +PROGS = $(PROG_BIN) $(PROG_LIBEXEC) + +SOURCES_KX = kx.c +SOURCES_KXD = kxd.c + +OBJECTS_KX = kx.o +OBJECTS_KXD = kxd.o + +OBJECTS = $(OBJECTS_KX) $(OBJECTS_KXD) +SOURCES = $(SOURCES_KX) $(SOURCES_KXD) + +all: $(PROGS) + +Wall: + make CFLAGS="-g -Wall -Wmissing-prototypes -Wmissing-declarations -D__USE_FIXED_PROTOTYPES__" + +.c.o: + $(CC) -c $(CPPFLAGS) $(DEFS) -I../.. -I../../include -I$(srcdir) -I$(srcdir)/../../include $(CFLAGS) $< + +install: all + $(MKDIRHIER) $(bindir) + for x in $(PROG_BIN); do $(INSTALL) $$x $(bindir); done + for x in $(PROG_LIBEXEC); do $(INSTALL) $$x $(libexecdir); done + +uninstall: + +TAGS: $(SOURCES) + etags $(SOURCES) + +check: + +clean: + rm -f *.a *.o $(PROGS) + +mostlyclean: clean + +distclean: clean + rm -f Makefile *.tab.c *~ + rm -rf CVS + +realclean: distclean + rm -f TAGS + +dist: $(DISTFILES) + for file in $(DISTFILES); do \ + ln $$file ../`cat ../.fname`/lib \ + || cp -p $$file ../`cat ../.fname`/lib; \ + done + +kx: $(OBJECTS_KX) + $(CC) $(LDFLAGS) -o $@ $(OBJECTS_KX) -L../../lib/krb -lkrb -L../../lib/des -ldes $(LIBS) + +kxd: $(OBJECTS_KXD) + $(CC) $(LDFLAGS) -o $@ $(OBJECTS_KXD) -L../../lib/krb -lkrb -L../../lib/des -ldes $(LIBS) + +$(OBJECTS): ../../config.h diff --git a/appl/kx/kx.c b/appl/kx/kx.c new file mode 100644 index 000000000..2dbfff8ae --- /dev/null +++ b/appl/kx/kx.c @@ -0,0 +1,254 @@ +#include "kx.h" + +RCSID("$Id$"); + +static char *prog; + +static void +usage() +{ + fprintf (stderr, "Usage: %s local-display-number host|display\n", + prog); + exit (1); +} + +static int +doit_host (char *host, unsigned dnr, int fd) +{ + CREDENTIALS cred; + KTEXT_ST text; + MSG_DAT msg; + int status; + des_key_schedule schedule; + struct sockaddr_in thisaddr, thataddr; + int addrlen; + void *ret; + struct hostent *hostent; + int s; + struct sockaddr_un unixaddr; + des_cblock iv1, iv2; + int num1 = 0, num2 = 0; + + /* + * Establish authenticated connection + */ + + 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, k_strerror(errno)); + return 1; + } + if (connect (s, (struct sockaddr *)&thataddr, sizeof(thataddr)) < 0) { + fprintf (stderr, "%s: connect(%s) failed: %s\n", prog, host, + k_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, k_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; + } + /* + * Send parameters. + */ + + { + u_char b = dnr; + char buf[128]; + int ret; + + if (write (s, &b, sizeof(b)) != sizeof(b)) { + fprintf (stderr, "%s: write: %s\n", prog, k_strerror (errno)); + return 1; + } + if (read (s, &b, sizeof(b)) != sizeof(b)) { + fprintf (stderr, "%s: read: %s\n", prog, k_strerror (errno)); + return 1; + } + if (b) { + fprintf (stderr, "%s: Error from '%s': ", prog, host); + ret = read (s, buf, sizeof(buf)); + if(ret < 0) { + fprintf (stderr, "%s: read: %s\n", prog, k_strerror (errno)); + return 1; + } + fprintf (stderr, "%s\n", buf); + return 1; + } + } + + memcpy (&iv1, &cred.session, sizeof(iv1)); + memcpy (&iv2, &cred.session, sizeof(iv2)); + for (;;) { + fd_set fdset; + int ret; + char buf[BUFSIZ]; + + FD_ZERO(&fdset); + FD_SET(s, &fdset); + FD_SET(fd, &fdset); + + ret = select (256, &fdset, NULL, NULL, NULL); /* XXX */ + if (ret < 0 && errno != EINTR) { + fprintf (stderr, "%s: select: %s\n", prog, k_strerror (errno)); + return 1; + } + if (FD_ISSET(s, &fdset)) { + ret = read (s, buf, sizeof(buf)); + if (ret == 0) + return 0; + if (ret < 0) { + fprintf (stderr, "%s: read: %s\n", prog, k_strerror (errno)); + return 1; + } +#ifndef NOENCRYPTION + des_cfb64_encrypt (buf, buf, ret, schedule, &iv1, + &num1, DES_DECRYPT); +#endif + ret = krb_net_write (fd, buf, ret); + if (ret < 0) { + fprintf (stderr, "%s: write: %s\n", prog, k_strerror (errno)); + return 1; + } + } + if (FD_ISSET(fd, &fdset)) { + ret = read (fd, buf, sizeof(buf)); + if (ret == 0) + return 0; + if (ret < 0) { + fprintf (stderr, "%s: read: %s\n", prog, k_strerror (errno)); + return 1; + } +#ifndef NOENCRYPTION + des_cfb64_encrypt (buf, buf, ret, schedule, &iv2, + &num2, DES_ENCRYPT); +#endif + ret = krb_net_write (s, buf, ret); + if (ret < 0) { + fprintf (stderr, "%s: write: %s\n", prog, k_strerror (errno)); + return 1; + } + } + } +} + +/* + * Listen for calls to the remote X-server. + */ + +static int +doit (unsigned localnr, char *host, unsigned remotenr) +{ + int fd; + struct sockaddr_un addr; + int dnr; + + fd = socket (AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + fprintf (stderr, "%s: socket failed: %s\n", prog, k_strerror(errno)); + return 1; + } + addr.sun_family = AF_UNIX; + sprintf (addr.sun_path, "/tmp/.X11-unix/X%u", localnr); + unlink (addr.sun_path); + if(bind (fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + fprintf (stderr, "%s: bind failed: %s\n", prog, + k_strerror(errno)); + return 1; + } + if (listen (fd, 5) < 0) { + fprintf (stderr, "%s: listen failed: %s\n", prog, + k_strerror(errno)); + return 1; + } + for (;;) { + int newfd; + struct sockaddr_un that; + int len; + pid_t pid; + + len = sizeof (that); + newfd = accept (fd, (struct sockaddr *)&that, &len); + if (newfd < 0) + if (errno == EINTR) + continue; + else { + fprintf (stderr, "%s: accept: %s\n", prog, k_strerror (errno)); + return 1; + } + fprintf (stderr, "%s: New connection\n", prog); + pid = fork (); + if (pid < 0) { + fprintf (stderr, "%s: fork: %s\n", prog, k_strerror (errno)); + return 1; + } else if (pid == 0) { + close (fd); + return doit_host (host, remotenr, newfd); + } else { + close (newfd); + } + } +} + +static +RETSIGTYPE +childhandler () +{ + pid_t pid; + int status; + + do { + pid = waitpid (-1, &status, WNOHANG|WUNTRACED); + } while(pid); + signal (SIGCHLD, childhandler); +} + +/* + * fx - forward x connection. + */ + +int +main(argc, argv) + int argc; + char **argv; +{ + int dnr; + char *p; + + prog = argv[0]; + if (argc != 3) + usage (); + + p = strchr (argv[2], ':'); + if (p) { + *p = '\0'; + dnr = atoi (p+1); + } else + dnr = 0; + + signal (SIGCHLD, childhandler); + + return doit (atoi(argv[1]), argv[2], dnr); +} diff --git a/appl/kx/kx.h b/appl/kx/kx.h new file mode 100644 index 000000000..47a09f110 --- /dev/null +++ b/appl/kx/kx.h @@ -0,0 +1,26 @@ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif +#include +#include +#include +#include +#include +#include + +#include diff --git a/appl/kx/kxd.c b/appl/kx/kxd.c new file mode 100644 index 000000000..7a33d7c0b --- /dev/null +++ b/appl/kx/kxd.c @@ -0,0 +1,145 @@ +#include "kx.h" + +RCSID("$Id$"); + +static int +fatal (int fd, char *s) +{ + u_char err = 1; + + write (fd, &err, sizeof(err)); + write (fd, s, strlen(s)+1); + return err; +} + +static int +doit(int sock) +{ + int status; + KTEXT_ST ticket; + AUTH_DAT auth; + char instance[INST_SZ + 1]; + des_key_schedule schedule; + struct sockaddr_in thisaddr, thataddr; + int addrlen; + int len; + char buf[BUFSIZ]; + void *data; + struct passwd *passwd; + char version[KRB_SENDAUTH_VLEN]; + int fd; + struct stat sb; + struct sockaddr_un addr; + char *username; + des_cblock iv1, iv2; + int num1 = 0, num2 = 0; + unsigned dnr; + + addrlen = sizeof(thisaddr); + if (getsockname (sock, (struct sockaddr *)&thisaddr, &addrlen) < 0 || + addrlen != sizeof(thisaddr)) { + return 1; + } + addrlen = sizeof(thataddr); + if (getpeername (sock, (struct sockaddr *)&thataddr, &addrlen) < 0 || + addrlen != sizeof(thataddr)) { + return 1; + } + + k_getsockinst (sock, instance); + status = krb_recvauth (KOPT_DO_MUTUAL, sock, &ticket, "rcmd", instance, + &thataddr, &thisaddr, &auth, "", schedule, + version); + if (status != KSUCCESS || + strncmp(version, "KXSERV.0", KRB_SENDAUTH_VLEN) != 0) { + return 1; + } + { + u_char b; + + if (read (sock, &b, sizeof(b)) != sizeof(b)) + return 1; + dnr = b; + } + + if (stat ("/dev/console", &sb) < 0) + return fatal (fd, "Cannot stat /dev/console"); + passwd = getpwuid (sb.st_uid); + if (passwd == NULL) + return fatal (fd, "Cannot find uid"); + username = strdup (passwd->pw_name); + if (kuserok(&auth, username) != 0) + return fatal (fd, "Permission denied"); + free (username); + if (setgid (passwd->pw_gid) || + initgroups(passwd->pw_name, passwd->pw_gid) || + setuid(passwd->pw_uid)) { + return fatal (fd, "Cannot set uid"); + } + fd = socket (AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + return fatal (fd, "Cannot create socket"); + addr.sun_family = AF_UNIX; + sprintf (addr.sun_path, "/tmp/.X11-unix/X%u", dnr); + if (connect (fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + return fatal (fd, "Cannot connect"); + memcpy (&iv1, &auth.session, sizeof(iv1)); + memcpy (&iv2, &auth.session, sizeof(iv2)); + { + u_char b = 0; + + if (write (sock, &b, sizeof(b)) != sizeof(b)) + return 1; + } + for (;;) { + fd_set fdset; + int ret; + char buf[BUFSIZ]; + + FD_ZERO(&fdset); + FD_SET(sock, &fdset); + FD_SET(fd, &fdset); + + ret = select (fd+1, &fdset, NULL, NULL, NULL); + if (ret < 0 && errno != EINTR) + return 1; + if (FD_ISSET(sock, &fdset)) { + ret = read (sock, buf, sizeof(buf)); + if (ret == 0) + return 0; + if (ret < 0) + return 1; +#ifndef NOENCRYPTION + des_cfb64_encrypt (buf, buf, ret, schedule, + &iv1, &num1, DES_DECRYPT); +#endif + ret = krb_net_write (fd, buf, ret); + if (ret < 0) + return 1; + } + if (FD_ISSET(fd, &fdset)) { + ret = read (fd, buf, sizeof(buf)); + if (ret == 0) + return 0; + if (ret < 0) + return 1; +#ifndef NOENCRYPTION + des_cfb64_encrypt (buf, buf, ret, schedule, + &iv2, &num2, DES_ENCRYPT); +#endif + ret = krb_net_write (STDOUT_FILENO, buf, ret); + if (ret < 0) + return 1; + } + } +} + +/* + * xkd - receive a forwarded X conncection + */ + +int +main (int argc, char **argv) +{ + return doit(0); +}