brian@cimage.com (Brian Kelley) (12/05/90)
I called DEC tech support last week to check on the rlogin problem. I first reported the problem well over 4 weeks ago. The software support person I spoke with said that he first took a report on the problem a LONG time ago (when Ultrix 4.0 came out). When I placed my original call, I was told that Ultrix engineers considered it "critical" and were working on the problem. The support person mentioned that he had heard that if you run your rlogin in the background (rlogin host &) and bring it into the foreground, it will work. I was slightly skeptical, since this implied that the problem might be in rlogin itself rather than something in the kernel. I was quite surprised when it worked. It made me wonder just where the problem was. I dug down into my tahoe 4.3 sources and found I had rlogin source. I compiled it, made it setuid to root, and it worked. Am I missing something? Am I just imagining that it's this simple? How many DEC engineers does it take screw in a lightbulb? Here's the tahoe source and Makefile (or if you have it around, you can use your own). Brian --- brian@cimage.com ----------------------------------Cut Here------------------------------------ #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: README Makefile rlogin.c # Wrapped by brian@cimage.com on Tue Dec 4 23:39:26 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f README -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"README\" else echo shar: Extracting \"README\" \(820 characters\) sed "s/^X//" >README <<'END_OF_README' X X XTahoe 4.3 rlogin program X XThis shar file is the Tahoe 4.3 BSD rlogin program. I used it to replace Xthe rlogin shipped with Ultrix 4.0 and 4.1. It has a bug that prevents Xyou from doing an rlogin from Ultrix to a Sun running 4.1 or 4.1.1. X X XI have made no changes and I, of course, don't warranty it. I guess I also Xhave to say that "this software was developed by the University of XCalifornia, Berkeley." Please see the copyright at the top of rlogin.c. X X XWhat worked for me: X XType make to build rlogin. You may want to strip it after you've built it. X Xmv /usr/ucb/rlogin /usr/ucb/rlogin.old X Xcp rlogin /usr/ucb/rlogin X XThe new rlogin must be owned by root and setuid, just like the old one. X X X X XIt should work. I would like to hear if you have any trouble. X XWhy couldn't DEC do this? X X X Brian@cimage.com X X X END_OF_README if test 820 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f Makefile -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Makefile\" else echo shar: Extracting \"Makefile\" \(1314 characters\) sed "s/^X//" >Makefile <<'END_OF_Makefile' X# X# Copyright (c) 1988 Regents of the University of California. X# All rights reserved. X# X# Redistribution and use in source and binary forms are permitted X# provided that the above copyright notice and this paragraph are X# duplicated in all such forms and that any documentation, advertising X# materials, and other materials related to such redistribution and X# use acknowledge that the software was developed by the University X# of California, Berkeley. The name of the University may not be X# used to endorse or promote products derived from this software X# without specific prior written permission. THIS SOFTWARE IS PROVIDED X# ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, X# WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND X# FITNESS FOR A PARTICULAR PURPOSE. X# X# @(#)Makefile 5.1 (Berkeley) 9/19/88 X# X XCFLAGS= -O XLIBC= /lib/libc.a XSRCS= rlogin.c XOBJS= XMAN= rlogin.0 X Xall: rlogin X Xrlogin: ${LIBC} X ${CC} -o $@ ${CFLAGS} $@.c X Xclean: X rm -f ${OBJS} core rlogin X Xcleandir: clean X rm -f ${MAN} tags .depend X Xdepend: ${SRCS} X mkdep -p ${CFLAGS} ${SRCS} X Xinstall: ${MAN} X install -s -o root -g bin -m 4755 rlogin ${DESTDIR}/usr/ucb/rlogin X install -c -o bin -g bin -m 444 rlogin.0 ${DESTDIR}/usr/man/cat1 X Xlint: ${SRCS} X lint ${CFLAGS} ${SRCS} X Xtags: ${SRCS} X ctags ${SRCS} END_OF_Makefile if test 1314 -ne `wc -c <Makefile`; then echo shar: \"Makefile\" unpacked with wrong size! fi # end of overwriting check fi if test -f rlogin.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"rlogin.c\" else echo shar: Extracting \"rlogin.c\" \(13838 characters\) sed "s/^X//" >rlogin.c <<'END_OF_rlogin.c' X/* X * Copyright (c) 1983 The Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley. The name of the X * University may not be used to endorse or promote products derived X * from this software without specific prior written permission. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X */ X X#ifndef lint Xchar copyright[] = X"@(#) Copyright (c) 1983 The Regents of the University of California.\n\ X All rights reserved.\n"; X#endif /* not lint */ X X#ifndef lint Xstatic char sccsid[] = "@(#)rlogin.c 5.12 (Berkeley) 9/19/88"; X#endif /* not lint */ X X/* X * rlogin - remote login X */ X#include <sys/param.h> X#include <sys/errno.h> X#include <sys/file.h> X#include <sys/socket.h> X#include <sys/time.h> X#include <sys/resource.h> X#include <sys/wait.h> X X#include <netinet/in.h> X X#include <stdio.h> X#include <sgtty.h> X#include <errno.h> X#include <pwd.h> X#include <signal.h> X#include <setjmp.h> X#include <netdb.h> X X# ifndef TIOCPKT_WINDOW X# define TIOCPKT_WINDOW 0x80 X# endif TIOCPKT_WINDOW X X/* concession to sun */ X# ifndef SIGUSR1 X# define SIGUSR1 30 X# endif SIGUSR1 X Xchar *index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy(); Xstruct passwd *getpwuid(); Xchar *name; Xint rem; Xchar cmdchar = '~'; Xint eight; Xint litout; Xchar *speeds[] = X { "0", "50", "75", "110", "134", "150", "200", "300", X "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; Xchar term[256] = "network"; Xextern int errno; Xint lostpeer(); Xint dosigwinch = 0; X#ifndef sigmask X#define sigmask(m) (1 << ((m)-1)) X#endif X#ifdef sun Xstruct winsize { X unsigned short ws_row, ws_col; X unsigned short ws_xpixel, ws_ypixel; X}; X#endif sun Xstruct winsize winsize; Xint sigwinch(), oob(); X X/* X * The following routine provides compatibility (such as it is) X * between 4.2BSD Suns and others. Suns have only a `ttysize', X * so we convert it to a winsize. X */ X#ifdef sun Xint Xget_window_size(fd, wp) X int fd; X struct winsize *wp; X{ X struct ttysize ts; X int error; X X if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) X return (error); X wp->ws_row = ts.ts_lines; X wp->ws_col = ts.ts_cols; X wp->ws_xpixel = 0; X wp->ws_ypixel = 0; X return (0); X} X#else sun X#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) X#endif sun X Xmain(argc, argv) X int argc; X char **argv; X{ X char *host, *cp; X struct sgttyb ttyb; X struct passwd *pwd; X struct servent *sp; X int uid, options = 0, oldmask; X int on = 1; X X host = rindex(argv[0], '/'); X if (host) X host++; X else X host = argv[0]; X argv++, --argc; X if (!strcmp(host, "rlogin")) X host = *argv++, --argc; Xanother: X if (argc > 0 && !strcmp(*argv, "-d")) { X argv++, argc--; X options |= SO_DEBUG; X goto another; X } X if (argc > 0 && !strcmp(*argv, "-l")) { X argv++, argc--; X if (argc == 0) X goto usage; X name = *argv++; argc--; X goto another; X } X if (argc > 0 && !strncmp(*argv, "-e", 2)) { X cmdchar = argv[0][2]; X argv++, argc--; X goto another; X } X if (argc > 0 && !strcmp(*argv, "-8")) { X eight = 1; X argv++, argc--; X goto another; X } X if (argc > 0 && !strcmp(*argv, "-L")) { X litout = 1; X argv++, argc--; X goto another; X } X if (host == 0) X goto usage; X if (argc > 0) X goto usage; X pwd = getpwuid(getuid()); X if (pwd == 0) { X fprintf(stderr, "Who are you?\n"); X exit(1); X } X sp = getservbyname("login", "tcp"); X if (sp == 0) { X fprintf(stderr, "rlogin: login/tcp: unknown service\n"); X exit(2); X } X cp = getenv("TERM"); X if (cp) X (void) strcpy(term, cp); X if (ioctl(0, TIOCGETP, &ttyb) == 0) { X (void) strcat(term, "/"); X (void) strcat(term, speeds[ttyb.sg_ospeed]); X } X (void) get_window_size(0, &winsize); X (void) signal(SIGPIPE, lostpeer); X /* will use SIGUSR1 for window size hack, so hold it off */ X oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); X rem = rcmd(&host, sp->s_port, pwd->pw_name, X name ? name : pwd->pw_name, term, 0); X if (rem < 0) X exit(1); X if (options & SO_DEBUG && X setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) X perror("rlogin: setsockopt (SO_DEBUG)"); X uid = getuid(); X if (setuid(uid) < 0) { X perror("rlogin: setuid"); X exit(1); X } X doit(oldmask); X /*NOTREACHED*/ Xusage: X fprintf(stderr, X "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n"); X exit(1); X} X X#define CRLF "\r\n" X Xint child; Xint catchild(); Xint copytochild(), writeroob(); X Xint defflags, tabflag; Xint deflflags; Xchar deferase, defkill; Xstruct tchars deftc; Xstruct ltchars defltc; Xstruct tchars notc = { -1, -1, -1, -1, -1, -1 }; Xstruct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; X Xdoit(oldmask) X{ X int exit(); X struct sgttyb sb; X X (void) ioctl(0, TIOCGETP, (char *)&sb); X defflags = sb.sg_flags; X tabflag = defflags & TBDELAY; X defflags &= ECHO | CRMOD; X deferase = sb.sg_erase; X defkill = sb.sg_kill; X (void) ioctl(0, TIOCLGET, (char *)&deflflags); X (void) ioctl(0, TIOCGETC, (char *)&deftc); X notc.t_startc = deftc.t_startc; X notc.t_stopc = deftc.t_stopc; X (void) ioctl(0, TIOCGLTC, (char *)&defltc); X (void) signal(SIGINT, SIG_IGN); X setsignal(SIGHUP, exit); X setsignal(SIGQUIT, exit); X child = fork(); X if (child == -1) { X perror("rlogin: fork"); X done(1); X } X if (child == 0) { X mode(1); X if (reader(oldmask) == 0) { X prf("Connection closed."); X exit(0); X } X sleep(1); X prf("\007Connection closed."); X exit(3); X } X X /* X * We may still own the socket, and may have a pending SIGURG X * (or might receive one soon) that we really want to send to X * the reader. Set a trap that simply copies such signals to X * the child. X */ X (void) signal(SIGURG, copytochild); X (void) signal(SIGUSR1, writeroob); X (void) sigsetmask(oldmask); X (void) signal(SIGCHLD, catchild); X writer(); X prf("Closed connection."); X done(0); X} X X/* X * Trap a signal, unless it is being ignored. X */ Xsetsignal(sig, act) X int sig, (*act)(); X{ X int omask = sigblock(sigmask(sig)); X X if (signal(sig, act) == SIG_IGN) X (void) signal(sig, SIG_IGN); X (void) sigsetmask(omask); X} X Xdone(status) X int status; X{ X int w; X X mode(0); X if (child > 0) { X /* make sure catchild does not snap it up */ X (void) signal(SIGCHLD, SIG_DFL); X if (kill(child, SIGKILL) >= 0) X while ((w = wait((union wait *)0)) > 0 && w != child) X /*void*/; X } X exit(status); X} X X/* X * Copy SIGURGs to the child process. X */ Xcopytochild() X{ X X (void) kill(child, SIGURG); X} X X/* X * This is called when the reader process gets the out-of-band (urgent) X * request to turn on the window-changing protocol. X */ Xwriteroob() X{ X X if (dosigwinch == 0) { X sendwindow(); X (void) signal(SIGWINCH, sigwinch); X } X dosigwinch = 1; X} X Xcatchild() X{ X union wait status; X int pid; X Xagain: X pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0); X if (pid == 0) X return; X /* X * if the child (reader) dies, just quit X */ X if (pid < 0 || pid == child && !WIFSTOPPED(status)) X done((int)(status.w_termsig | status.w_retcode)); X goto again; X} X X/* X * writer: write to remote: 0 -> line. X * ~. terminate X * ~^Z suspend rlogin process. X * ~^Y suspend rlogin process, but leave reader alone. X */ Xwriter() X{ X char c; X register n; X register bol = 1; /* beginning of line */ X register local = 0; X X for (;;) { X n = read(0, &c, 1); X if (n <= 0) { X if (n < 0 && errno == EINTR) X continue; X break; X } X /* X * If we're at the beginning of the line X * and recognize a command character, then X * we echo locally. Otherwise, characters X * are echo'd remotely. If the command X * character is doubled, this acts as a X * force and local echo is suppressed. X */ X if (bol) { X bol = 0; X if (c == cmdchar) { X bol = 0; X local = 1; X continue; X } X } else if (local) { X local = 0; X if (c == '.' || c == deftc.t_eofc) { X echo(c); X break; X } X if (c == defltc.t_suspc || c == defltc.t_dsuspc) { X bol = 1; X echo(c); X stop(c); X continue; X } X if (c != cmdchar) X (void) write(rem, &cmdchar, 1); X } X if (write(rem, &c, 1) == 0) { X prf("line gone"); X break; X } X bol = c == defkill || c == deftc.t_eofc || X c == deftc.t_intrc || c == defltc.t_suspc || X c == '\r' || c == '\n'; X } X} X Xecho(c) Xregister char c; X{ X char buf[8]; X register char *p = buf; X X c &= 0177; X *p++ = cmdchar; X if (c < ' ') { X *p++ = '^'; X *p++ = c + '@'; X } else if (c == 0177) { X *p++ = '^'; X *p++ = '?'; X } else X *p++ = c; X *p++ = '\r'; X *p++ = '\n'; X (void) write(1, buf, p - buf); X} X Xstop(cmdc) X char cmdc; X{ X mode(0); X (void) signal(SIGCHLD, SIG_IGN); X (void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); X (void) signal(SIGCHLD, catchild); X mode(1); X sigwinch(); /* check for size changes */ X} X Xsigwinch() X{ X struct winsize ws; X X if (dosigwinch && get_window_size(0, &ws) == 0 && X bcmp(&ws, &winsize, sizeof (ws))) { X winsize = ws; X sendwindow(); X } X} X X/* X * Send the window size to the server via the magic escape X */ Xsendwindow() X{ X char obuf[4 + sizeof (struct winsize)]; X struct winsize *wp = (struct winsize *)(obuf+4); X X obuf[0] = 0377; X obuf[1] = 0377; X obuf[2] = 's'; X obuf[3] = 's'; X wp->ws_row = htons(winsize.ws_row); X wp->ws_col = htons(winsize.ws_col); X wp->ws_xpixel = htons(winsize.ws_xpixel); X wp->ws_ypixel = htons(winsize.ws_ypixel); X (void) write(rem, obuf, sizeof(obuf)); X} X X/* X * reader: read from remote: line -> 1 X */ X#define READING 1 X#define WRITING 2 X Xchar rcvbuf[8 * 1024]; Xint rcvcnt; Xint rcvstate; Xint ppid; Xjmp_buf rcvtop; X Xoob() X{ X int out = FWRITE, atmark, n; X int rcvd = 0; X char waste[BUFSIZ], mark; X struct sgttyb sb; X X while (recv(rem, &mark, 1, MSG_OOB) < 0) X switch (errno) { X X case EWOULDBLOCK: X /* X * Urgent data not here yet. X * It may not be possible to send it yet X * if we are blocked for output X * and our input buffer is full. X */ X if (rcvcnt < sizeof(rcvbuf)) { X n = read(rem, rcvbuf + rcvcnt, X sizeof(rcvbuf) - rcvcnt); X if (n <= 0) X return; X rcvd += n; X } else { X n = read(rem, waste, sizeof(waste)); X if (n <= 0) X return; X } X continue; X X default: X return; X } X if (mark & TIOCPKT_WINDOW) { X /* X * Let server know about window size changes X */ X (void) kill(ppid, SIGUSR1); X } X if (!eight && (mark & TIOCPKT_NOSTOP)) { X (void) ioctl(0, TIOCGETP, (char *)&sb); X sb.sg_flags &= ~CBREAK; X sb.sg_flags |= RAW; X (void) ioctl(0, TIOCSETN, (char *)&sb); X notc.t_stopc = -1; X notc.t_startc = -1; X (void) ioctl(0, TIOCSETC, (char *)¬c); X } X if (!eight && (mark & TIOCPKT_DOSTOP)) { X (void) ioctl(0, TIOCGETP, (char *)&sb); X sb.sg_flags &= ~RAW; X sb.sg_flags |= CBREAK; X (void) ioctl(0, TIOCSETN, (char *)&sb); X notc.t_stopc = deftc.t_stopc; X notc.t_startc = deftc.t_startc; X (void) ioctl(0, TIOCSETC, (char *)¬c); X } X if (mark & TIOCPKT_FLUSHWRITE) { X (void) ioctl(1, TIOCFLUSH, (char *)&out); X for (;;) { X if (ioctl(rem, SIOCATMARK, &atmark) < 0) { X perror("ioctl"); X break; X } X if (atmark) X break; X n = read(rem, waste, sizeof (waste)); X if (n <= 0) X break; X } X /* X * Don't want any pending data to be output, X * so clear the recv buffer. X * If we were hanging on a write when interrupted, X * don't want it to restart. If we were reading, X * restart anyway. X */ X rcvcnt = 0; X longjmp(rcvtop, 1); X } X X /* X * oob does not do FLUSHREAD (alas!) X */ X X /* X * If we filled the receive buffer while a read was pending, X * longjmp to the top to restart appropriately. Don't abort X * a pending write, however, or we won't know how much was written. X */ X if (rcvd && rcvstate == READING) X longjmp(rcvtop, 1); X} X X/* X * reader: read from remote: line -> 1 X */ Xreader(oldmask) X int oldmask; X{ X#if !defined(BSD) || BSD < 43 X int pid = -getpid(); X#else X int pid = getpid(); X#endif X int n, remaining; X char *bufp = rcvbuf; X X (void) signal(SIGTTOU, SIG_IGN); X (void) signal(SIGURG, oob); X ppid = getppid(); X (void) fcntl(rem, F_SETOWN, pid); X (void) setjmp(rcvtop); X (void) sigsetmask(oldmask); X for (;;) { X while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { X rcvstate = WRITING; X n = write(1, bufp, remaining); X if (n < 0) { X if (errno != EINTR) X return (-1); X continue; X } X bufp += n; X } X bufp = rcvbuf; X rcvcnt = 0; X rcvstate = READING; X rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); X if (rcvcnt == 0) X return (0); X if (rcvcnt < 0) { X if (errno == EINTR) X continue; X perror("read"); X return (-1); X } X } X} X Xmode(f) X{ X struct tchars *tc; X struct ltchars *ltc; X struct sgttyb sb; X int lflags; X X (void) ioctl(0, TIOCGETP, (char *)&sb); X (void) ioctl(0, TIOCLGET, (char *)&lflags); X switch (f) { X X case 0: X sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); X sb.sg_flags |= defflags|tabflag; X tc = &deftc; X ltc = &defltc; X sb.sg_kill = defkill; X sb.sg_erase = deferase; X lflags = deflflags; X break; X X case 1: X sb.sg_flags |= (eight ? RAW : CBREAK); X sb.sg_flags &= ~defflags; X /* preserve tab delays, but turn off XTABS */ X if ((sb.sg_flags & TBDELAY) == XTABS) X sb.sg_flags &= ~TBDELAY; X tc = ¬c; X ltc = &noltc; X sb.sg_kill = sb.sg_erase = -1; X if (litout) X lflags |= LLITOUT; X break; X X default: X return; X } X (void) ioctl(0, TIOCSLTC, (char *)ltc); X (void) ioctl(0, TIOCSETC, (char *)tc); X (void) ioctl(0, TIOCSETN, (char *)&sb); X (void) ioctl(0, TIOCLSET, (char *)&lflags); X} X X/*VARARGS*/ Xprf(f, a1, a2, a3, a4, a5) X char *f; X{ X X fprintf(stderr, f, a1, a2, a3, a4, a5); X fprintf(stderr, CRLF); X} X Xlostpeer() X{ X X (void) signal(SIGPIPE, SIG_IGN); X prf("\007Connection closed."); X done(1); X} END_OF_rlogin.c if test 13838 -ne `wc -c <rlogin.c`; then echo shar: \"rlogin.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of shell archive. exit 0