diff -up netkit-rsh-0.17/rlogind/rlogind.c.rh947213 netkit-rsh-0.17/rlogind/rlogind.c --- netkit-rsh-0.17/rlogind/rlogind.c.rh947213 2013-04-11 14:18:47.481715853 +0200 +++ netkit-rsh-0.17/rlogind/rlogind.c 2013-04-11 14:32:50.807780164 +0200 @@ -67,12 +67,13 @@ char rcsid[] = #include #include #include +#include +#include #include "pathnames.h" #include "logwtmp.h" #include "rlogind.h" -pid_t forkpty(int *, char *, struct termios *, struct winsize *); int logout(const char *); #ifndef TIOCPKT_WINDOW @@ -389,7 +390,7 @@ static void getstr(char *buf, int cnt, c } static void doit(int netfd) { - int master, pid, on = 1; + int master, slave, r, pid, on = 1; int authenticated = 0; char *hname; int hostok; @@ -421,12 +422,34 @@ static void doit(int netfd) { write(netfd, "rlogind: Host address mismatch.\r\n", 33); } - pid = forkpty(&master, line, NULL, &win); - if (pid < 0) { + /* We can no longer call forkpty here (a convenience routine that combines + openpty, fork, and login_tty) because, with forkpty, the slave end of + the pty is open only in the child process. The child process execs + /bin/login which now closes all open file descriptors before doing a + vhangup (see lkml.org/lkml/2012/6/5/145), and this resets packet mode + on the pty, undoing the effect of the ioctl(master, TIOCPKT, &on) call + made by the parent. + + Instead, we call openpty, fork, and login_tty individually, so that we + can keep a file descriptor to the slave open in the parent process, + thereby retaining packet mode even when the child closes file descriptors + to call vhangup. */ + r = openpty(&master, &slave, line, NULL, &win); + if (r < 0) { if (errno == ENOENT) fatal(netfd, "Out of ptys", 0); - fatal(netfd, "Forkpty", 1); + fatal(netfd, "Openpty", 1); + } + + signal(SIGHUP, SIG_IGN); + + pid = fork(); + if (pid < 0) { + fatal(netfd, "Fork", 1); } + if (pid == 0) { + close(master); + login_tty(slave); /* netfd should always be 0, but... */ if (netfd > 2) close(netfd); child(hname, termtype, lusername, authenticated, rusername);