diff --git a/appl/kx/common.c b/appl/kx/common.c index cb8ecbb9a..0d3a1b92c 100644 --- a/appl/kx/common.c +++ b/appl/kx/common.c @@ -85,56 +85,109 @@ childhandler (int sig) SIGRETURN(0); } -/* - * Allocate and listen on a local X server socket. - */ - -#define TMPX11 "/tmp/.X11-unix" +#ifndef X_UNIX_PATH +#define X_UNIX_PATH "/tmp/.X11-unix/X" +#endif char x_socket[MaxPathLen]; +/* + * Allocate and listen on a local X server socket and a TCP socket. + * Return the display number. + */ + int -get_local_xsocket (int *num) +get_xsockets (int *unix_socket, int *tcp_socket) { - int fd; - struct sockaddr_un addr; + int unixfd, tcpfd; + struct sockaddr_un unixaddr; + struct sockaddr_in tcpaddr; int dpy; int oldmask; + struct hostent *h; + struct in_addr local; + char *dir, *p; + + dir = strdup (X_UNIX_PATH); + p = strchr (dir, '/'); + if (p) + *p = '\0'; oldmask = umask(0); - mkdir (TMPX11, 01777); + mkdir (dir, 01777); umask (oldmask); + free (dir); + + h = gethostbyname ("localhost"); + if (h) + memcpy (&local, h->h_addr, h->h_length); + else + local.s_addr = inet_addr ("127.0.0.1"); - fd = socket (AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { - fprintf (stderr, "%s: socket: %s\n", prog, strerror(errno)); - return fd; - } - addr.sun_family = AF_UNIX; for(dpy = 4; dpy < 256; ++dpy) { - struct stat statbuf; + unixfd = socket (AF_UNIX, SOCK_STREAM, 0); + if (unixfd < 0) { + fprintf (stderr, "%s: socket: %s\n", prog, strerror(errno)); + return -1; + } + memset (&unixaddr, 0, sizeof(unixaddr)); + unixaddr.sun_family = AF_UNIX; + sprintf (unixaddr.sun_path, X_UNIX_PATH "%u", dpy); + if(bind(unixfd, + (struct sockaddr *)&unixaddr, + sizeof(unixaddr)) < 0) { + close (unixfd); + if (errno == EADDRINUSE || + errno == EACCES) /* Cray return EACCESS */ + continue; + else + return -1; + } - sprintf (addr.sun_path, TMPX11 "/X%u", dpy); - if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) - if (errno == EADDRINUSE) - continue; - else - return -1; - else - break; + if (tcp_socket) { + tcpfd = socket (AF_INET, SOCK_STREAM, 0); + if (tcpfd < 0) { + fprintf (stderr, "%s: socket: %s\n", prog, + strerror(errno)); + close (unixfd); + return -1; + } + memset (&tcpaddr, 0, sizeof(tcpaddr)); + tcpaddr.sin_family = AF_INET; + tcpaddr.sin_addr = local; + tcpaddr.sin_port = htons(6000 + dpy); + if (bind (tcpfd, (struct sockaddr *)&tcpaddr, + sizeof(tcpaddr)) < 0) { + close (unixfd); + close (tcpfd); + if (errno == EADDRINUSE) + continue; + else + return -1; + } + } + break; } if (dpy == 256) { fprintf (stderr, "%s: no free x-servers\n", prog); return -1; } - if (listen (fd, SOMAXCONN) < 0) { + if (listen (unixfd, SOMAXCONN) < 0) { fprintf (stderr, "%s: listen: %s\n", prog, strerror(errno)); return -1; } - strcpy(x_socket, addr.sun_path); - *num = dpy; - return fd; + if (tcp_socket) + if (listen (tcpfd, SOMAXCONN) < 0) { + fprintf (stderr, "%s: listen: %s\n", prog, + strerror(errno)); + return -1; + } + strcpy(x_socket, unixaddr.sun_path); + *unix_socket = unixfd; + if (tcp_socket) + *tcp_socket = tcpfd; + return dpy; } /* diff --git a/appl/kx/kx.c b/appl/kx/kx.c index 7a0b05eab..255c37045 100644 --- a/appl/kx/kx.c +++ b/appl/kx/kx.c @@ -41,7 +41,7 @@ connect_host (char *host, des_cblock *key, des_key_schedule schedule, memset (&thataddr, 0, sizeof(thataddr)); thataddr.sin_family = AF_INET; - thataddr.sin_port = k_getportbyname ("kx", "tcp", htons(2111)); + thataddr.sin_port = k_getportbyname ("kx", "tcp", htons(KX_PORT)); memcpy (&thataddr.sin_addr, hostent->h_addr, sizeof(thataddr.sin_addr)); s = socket (AF_INET, SOCK_STREAM, 0); @@ -261,11 +261,15 @@ doit (char *host, int passivep) fprintf (stderr, "%s: listen: %s\n", prog, strerror(errno)); return 1; } - if (krb_net_write (otherside, &newaddr.sin_port, - sizeof(newaddr.sin_port)) - != sizeof(newaddr.sin_port)) { - fprintf (stderr, "%s: write: %s\n", prog, strerror(errno)); - return 1; + { + char tmp[6]; + + sprintf (tmp, "%d", ntohs(newaddr.sin_port)); + if (krb_net_write (otherside, tmp, sizeof(tmp)) + != sizeof(tmp)) { + fprintf (stderr, "%s: write: %s\n", prog, strerror(errno)); + return 1; + } } /* close (otherside); */ fn = passive; @@ -280,8 +284,8 @@ doit (char *host, int passivep) fclose(stdout); } } else { - rendez_vous = get_local_xsocket (&display_num); /* XXX */ - if (rendez_vous < 0) + display_num = get_xsockets (&rendez_vous, NULL); + if (display_num < 0) return 1; fn = active; } diff --git a/appl/kx/kx.h b/appl/kx/kx.h index e01d50c3a..867bb5f16 100644 --- a/appl/kx/kx.h +++ b/appl/kx/kx.h @@ -11,21 +11,44 @@ #include #include #include +#ifdef HAVE_SYSLOG_H #include +#endif +#ifdef HAVE_SYS_TYPES_H #include +#endif +#ifdef HAVE_SYS_TIME_H #include +#endif #ifdef HAVE_SYS_RESOURCE_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif +#ifdef HAVE_SYS_WAIT_H #include +#endif +#ifdef HAVE_SYS_STAT_H #include +#endif +#ifdef HAVE_SYS_SOCKET_H #include +#endif +#ifdef HAVE_NETINET_IN_H #include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H #include +#endif +#ifdef HAVE_SYS_UN_H #include +#endif +#include +#include #include #include @@ -36,10 +59,6 @@ #define max(a,b) (((a)>(b))?(a):(b)) #endif -#ifndef SOMAXCONN -#define SOMAXCONN 5 -#endif - #ifndef LOG_DAEMON #define openlog(id,option,facility) openlog((id),(option)) #endif @@ -53,5 +72,7 @@ RETSIGTYPE childhandler (int); extern char x_socket[]; -int get_local_xsocket (int *num); +int get_xsockets (int *unix_socket, int *tcp_socket); int connect_local_xsocket (unsigned dnr); + +#define KX_PORT 2111 diff --git a/appl/kx/kxd.c b/appl/kx/kxd.c index 1d8e37f73..068decb2c 100644 --- a/appl/kx/kxd.c +++ b/appl/kx/kxd.c @@ -161,6 +161,10 @@ check_user_console () return 0; } +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK 0x7f000001 +#endif + static int create_and_write_cookie (char *xauthfile, u_char *cookie, @@ -170,9 +174,13 @@ create_and_write_cookie (char *xauthfile, char tmp[64]; FILE *f; char hostname[MaxHostNameLen]; + struct in_addr loopback; + struct hostent *h; - auth.family = FamilyLocal; k_gethostname (hostname, sizeof(hostname)); + loopback.s_addr = htonl(INADDR_LOOPBACK); + + auth.family = FamilyLocal; auth.address = hostname; auth.address_length = strlen(auth.address); sprintf (tmp, "%d", display_num); @@ -190,19 +198,61 @@ create_and_write_cookie (char *xauthfile, fclose(f); return 1; } + + h = gethostbyname (hostname); + if (h == NULL) { + fclose (f); + return 1; + } + + /* + * I would like to write a cookie for localhost:n here, but some + * stupid code in libX11 will not look for cookies of that type, + * so we are forced to use FamilyWild instead. + */ + + auth.family = FamilyWild; + auth.address_length = 0; + +#if 0 /* XXX */ + auth.address = (char *)&loopback; + auth.address_length = sizeof(loopback); +#endif + + if (XauWriteAuth(f, &auth) == 0) { + fclose (f); + return 1; + } + if(fclose(f)) return 1; return 0; } +/* + * Some simple controls on the address and corresponding socket + */ + static int -doit(int sock) +suspicious_address (int sock, struct sockaddr_in addr) +{ + char data[40]; + int len = sizeof(data); + + + return addr.sin_addr.s_addr != htonl(INADDR_LOOPBACK) + || getsockopt (sock, IPPROTO_IP, IP_OPTIONS, data, &len) < 0 + || len != 0; +} + +static int +doit(int sock, int tcpp) { u_char passivep; struct sockaddr_in thataddr; des_key_schedule schedule; des_cblock key; - int localx; + int localx, tcpx; u_int32_t tmp; if (recv_conn (sock, &key, schedule, &thataddr)) @@ -212,8 +262,8 @@ doit(int sock) if (passivep) { char tmp[16]; - localx = get_local_xsocket (&display_num); - if (localx < 0) + display_num = get_xsockets (&localx, tcpp ? &tcpx : NULL); + if (display_num < 0) return 1; sprintf (tmp, "%u", display_num); if (krb_net_write (sock, tmp, sizeof(tmp)) != sizeof(tmp)) @@ -225,9 +275,13 @@ doit(int sock) if(create_and_write_cookie (xauthfile, cookie, sizeof(cookie))) return 1; - if (krb_net_read (sock, &thataddr.sin_port, sizeof(thataddr.sin_port)) - != sizeof(thataddr.sin_port)) - return 1; + { + char tmp[6]; + + if(krb_net_read(sock, tmp, sizeof(tmp)) != sizeof(tmp)) + return -1; + thataddr.sin_port = htons(atoi(tmp)); + } for (;;) { pid_t child; @@ -238,6 +292,8 @@ doit(int sock) FD_ZERO(&fds); FD_SET(localx, &fds); FD_SET(sock, &fds); + if (tcpp) + FD_SET(tcpx, &fds); if(select(FD_SETSIZE, &fds, NULL, NULL, NULL) <=0) continue; if(FD_ISSET(sock, &fds)){ @@ -245,9 +301,19 @@ doit(int sock) */ cleanup(); exit(0); - }else if(FD_ISSET(localx, &fds)) + } else if(FD_ISSET(localx, &fds)) fd = accept (localx, NULL, &zero); - else + else if(tcpp && FD_ISSET(tcpx, &fds)) { + struct sockaddr_in peer; + int len = sizeof(peer); + + fd = accept (tcpx, (struct sockaddr *)&peer, &len); + /* XXX */ + if (fd >= 0 && suspicious_address (fd, peer)) { + close (fd); + continue; + } + } else continue; if (fd < 0) if (errno == EINTR) @@ -264,6 +330,8 @@ doit(int sock) return fatal(sock, msg); } else if (child == 0) { close (localx); + if (tcpp) + close (tcpx); return doit_conn (fd, &thataddr, &key, schedule); } else { close (fd); @@ -280,6 +348,13 @@ doit(int sock) } } +static void +usage () +{ + fprintf (stderr, "Usage: %s [-i] [-t]\n", prog); + exit (1); +} + /* * xkd - receive a forwarded X conncection */ @@ -287,9 +362,30 @@ doit(int sock) int main (int argc, char **argv) { + int c; + int no_inetd = 0; + int tcpp = 0; + prog = argv[0]; + while( (c = getopt (argc, argv, "it")) != EOF) { + switch (c) { + case 'i': + no_inetd = 1; + break; + case 't': + tcpp = 1; + break; + case '?': + default: + fprintf (stderr, "%s: unknown option '%c'\n", prog, c); + usage (); + } + } + + if (no_inetd) + mini_inetd (k_getportbyname("kx", "tcp", htons(KX_PORT))); openlog(prog, LOG_PID|LOG_CONS, LOG_DAEMON); signal (SIGCHLD, childhandler); - return doit(0); + return doit(STDIN_FILENO, tcpp); }