121595Sdist /* 221595Sdist * Copyright (c) 1983 Regents of the University of California. 321595Sdist * All rights reserved. The Berkeley software License Agreement 421595Sdist * specifies the terms and conditions for redistribution. 521595Sdist */ 621595Sdist 76444Swnj #ifndef lint 821595Sdist char copyright[] = 921595Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 1021595Sdist All rights reserved.\n"; 1121595Sdist #endif not lint 126444Swnj 1321595Sdist #ifndef lint 14*25341Smckusick static char sccsid[] = "@(#)rlogin.c 5.7 (Berkeley) 10/30/85"; 1521595Sdist #endif not lint 1621595Sdist 1712990Ssam /* 1812990Ssam * rlogin - remote login 1912990Ssam */ 206444Swnj #include <sys/types.h> 2124727Smckusick #include <sys/file.h> 226444Swnj #include <sys/socket.h> 2313620Ssam #include <sys/wait.h> 249365Ssam 259207Ssam #include <netinet/in.h> 269365Ssam 279365Ssam #include <stdio.h> 289365Ssam #include <sgtty.h> 296444Swnj #include <errno.h> 306444Swnj #include <pwd.h> 319365Ssam #include <signal.h> 329365Ssam #include <netdb.h> 336444Swnj 3424726Smckusick # ifndef TIOCPKT_WINDOW 3524726Smckusick # define TIOCPKT_WINDOW 0x80 3624726Smckusick # endif TIOCPKT_WINDOW 3724726Smckusick 386444Swnj char *index(), *rindex(), *malloc(), *getenv(); 396444Swnj struct passwd *getpwuid(); 409365Ssam char *name; 416444Swnj int rem; 426444Swnj char cmdchar = '~'; 436444Swnj int eight; 4421583Sbloom int litout; 456444Swnj char *speeds[] = 466444Swnj { "0", "50", "75", "110", "134", "150", "200", "300", 476444Swnj "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 4818358Ssam char term[256] = "network"; 499365Ssam extern int errno; 509365Ssam int lostpeer(); 5124726Smckusick int dosigwinch = 0; 5218358Ssam struct winsize winsize; 5324726Smckusick int sigwinch(), oob(); 546444Swnj 556444Swnj main(argc, argv) 566444Swnj int argc; 576444Swnj char **argv; 586444Swnj { 599365Ssam char *host, *cp; 606444Swnj struct sgttyb ttyb; 616444Swnj struct passwd *pwd; 629365Ssam struct servent *sp; 6324726Smckusick int uid, options = 0, oldmask; 6417449Slepreau int on = 1; 656444Swnj 666444Swnj host = rindex(argv[0], '/'); 676444Swnj if (host) 686444Swnj host++; 696444Swnj else 706444Swnj host = argv[0]; 716444Swnj argv++, --argc; 726444Swnj if (!strcmp(host, "rlogin")) 736444Swnj host = *argv++, --argc; 746444Swnj another: 7510839Ssam if (argc > 0 && !strcmp(*argv, "-d")) { 766444Swnj argv++, argc--; 7710415Ssam options |= SO_DEBUG; 786444Swnj goto another; 796444Swnj } 8010839Ssam if (argc > 0 && !strcmp(*argv, "-l")) { 816444Swnj argv++, argc--; 826444Swnj if (argc == 0) 836444Swnj goto usage; 846444Swnj name = *argv++; argc--; 856444Swnj goto another; 866444Swnj } 8710839Ssam if (argc > 0 && !strncmp(*argv, "-e", 2)) { 886444Swnj cmdchar = argv[0][2]; 896444Swnj argv++, argc--; 906444Swnj goto another; 916444Swnj } 9210839Ssam if (argc > 0 && !strcmp(*argv, "-8")) { 936444Swnj eight = 1; 946444Swnj argv++, argc--; 956444Swnj goto another; 966444Swnj } 9721583Sbloom if (argc > 0 && !strcmp(*argv, "-L")) { 9821583Sbloom litout = 1; 9921583Sbloom argv++, argc--; 10021583Sbloom goto another; 10121583Sbloom } 1026444Swnj if (host == 0) 1036444Swnj goto usage; 1046444Swnj if (argc > 0) 1056444Swnj goto usage; 1066444Swnj pwd = getpwuid(getuid()); 1076444Swnj if (pwd == 0) { 1086444Swnj fprintf(stderr, "Who are you?\n"); 1096444Swnj exit(1); 1106444Swnj } 1119365Ssam sp = getservbyname("login", "tcp"); 1129365Ssam if (sp == 0) { 1139365Ssam fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 1149365Ssam exit(2); 1159365Ssam } 1169241Ssam cp = getenv("TERM"); 1179241Ssam if (cp) 1189241Ssam strcpy(term, cp); 11918358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 1206444Swnj strcat(term, "/"); 1216444Swnj strcat(term, speeds[ttyb.sg_ospeed]); 1226444Swnj } 12324726Smckusick (void) ioctl(0, TIOCGWINSZ, &winsize); 12412990Ssam signal(SIGPIPE, lostpeer); 12524726Smckusick signal(SIGURG, oob); 12624726Smckusick oldmask = sigblock(sigmask(SIGURG)); 1279365Ssam rem = rcmd(&host, sp->s_port, pwd->pw_name, 1286444Swnj name ? name : pwd->pw_name, term, 0); 1296444Swnj if (rem < 0) 1306444Swnj exit(1); 13110415Ssam if (options & SO_DEBUG && 13217449Slepreau setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) 13310415Ssam perror("rlogin: setsockopt (SO_DEBUG)"); 1349365Ssam uid = getuid(); 1359365Ssam if (setuid(uid) < 0) { 1369365Ssam perror("rlogin: setuid"); 1379365Ssam exit(1); 1389365Ssam } 13924726Smckusick doit(oldmask); 1409365Ssam /*NOTREACHED*/ 1416444Swnj usage: 1426444Swnj fprintf(stderr, 143*25341Smckusick "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n"); 1446444Swnj exit(1); 1456444Swnj } 1466444Swnj 1476444Swnj #define CRLF "\r\n" 1486444Swnj 1499365Ssam int child; 15011803Sedward int catchild(); 15124726Smckusick int writeroob(); 1529365Ssam 15313075Ssam int defflags, tabflag; 15421583Sbloom int deflflags; 15513075Ssam char deferase, defkill; 15613075Ssam struct tchars deftc; 15713075Ssam struct ltchars defltc; 15813075Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 15913075Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 1606444Swnj 16124726Smckusick doit(oldmask) 1626444Swnj { 1636444Swnj int exit(); 16413075Ssam struct sgttyb sb; 1656444Swnj 16613075Ssam ioctl(0, TIOCGETP, (char *)&sb); 16713075Ssam defflags = sb.sg_flags; 16812155Ssam tabflag = defflags & TBDELAY; 1699962Ssam defflags &= ECHO | CRMOD; 17013075Ssam deferase = sb.sg_erase; 17113075Ssam defkill = sb.sg_kill; 17221583Sbloom ioctl(0, TIOCLGET, (char *)&deflflags); 17313075Ssam ioctl(0, TIOCGETC, (char *)&deftc); 17413075Ssam notc.t_startc = deftc.t_startc; 17513075Ssam notc.t_stopc = deftc.t_stopc; 17613075Ssam ioctl(0, TIOCGLTC, (char *)&defltc); 17724726Smckusick signal(SIGINT, SIG_IGN); 17812990Ssam signal(SIGHUP, exit); 17912990Ssam signal(SIGQUIT, exit); 1809365Ssam child = fork(); 1819365Ssam if (child == -1) { 1829365Ssam perror("rlogin: fork"); 1839365Ssam done(); 1849365Ssam } 1859365Ssam if (child == 0) { 18624726Smckusick mode(1); 18724726Smckusick sigsetmask(oldmask); 1889365Ssam reader(); 18912155Ssam sleep(1); 19012155Ssam prf("\007Connection closed."); 1916444Swnj exit(3); 1926444Swnj } 19324726Smckusick signal(SIGURG, writeroob); 19424726Smckusick sigsetmask(oldmask); 19512990Ssam signal(SIGCHLD, catchild); 1969365Ssam writer(); 19712155Ssam prf("Closed connection."); 1986444Swnj done(); 1996444Swnj } 2006444Swnj 2016444Swnj done() 2026444Swnj { 2036444Swnj 2046444Swnj mode(0); 2059365Ssam if (child > 0 && kill(child, SIGKILL) >= 0) 2069365Ssam wait((int *)0); 2076444Swnj exit(0); 2086444Swnj } 2096444Swnj 21024726Smckusick /* 21124726Smckusick * This is called when the reader process gets the out-of-band (urgent) 21224726Smckusick * request to turn on the window-changing protocol. 21324726Smckusick */ 21424726Smckusick writeroob() 21524726Smckusick { 21624726Smckusick 217*25341Smckusick if (dosigwinch == 0) { 21824919Smckusick sendwindow(); 219*25341Smckusick signal(SIGWINCH, sigwinch); 220*25341Smckusick } 22124726Smckusick dosigwinch = 1; 22224726Smckusick } 22324726Smckusick 22411803Sedward catchild() 22511803Sedward { 22611803Sedward union wait status; 22711803Sedward int pid; 22811803Sedward 22911803Sedward again: 23011803Sedward pid = wait3(&status, WNOHANG|WUNTRACED, 0); 23111803Sedward if (pid == 0) 23211803Sedward return; 23311803Sedward /* 23411803Sedward * if the child (reader) dies, just quit 23511803Sedward */ 23611803Sedward if (pid < 0 || pid == child && !WIFSTOPPED(status)) 23711803Sedward done(); 23811803Sedward goto again; 23911803Sedward } 24011803Sedward 2416444Swnj /* 2429365Ssam * writer: write to remote: 0 -> line. 2439365Ssam * ~. terminate 2449365Ssam * ~^Z suspend rlogin process. 24510415Ssam * ~^Y suspend rlogin process, but leave reader alone. 2466444Swnj */ 2479365Ssam writer() 2486444Swnj { 24923530Sbloom char c; 25011803Sedward register n; 25123530Sbloom register bol = 1; /* beginning of line */ 25223530Sbloom register local = 0; 2536444Swnj 25411803Sedward for (;;) { 25511803Sedward n = read(0, &c, 1); 25618358Ssam if (n <= 0) { 25718358Ssam if (n < 0 && errno == EINTR) 25818358Ssam continue; 25911803Sedward break; 26018358Ssam } 2619365Ssam /* 2629365Ssam * If we're at the beginning of the line 2639365Ssam * and recognize a command character, then 2649365Ssam * we echo locally. Otherwise, characters 2659365Ssam * are echo'd remotely. If the command 2669365Ssam * character is doubled, this acts as a 2679365Ssam * force and local echo is suppressed. 2689365Ssam */ 26923530Sbloom if (bol) { 27023530Sbloom bol = 0; 27123530Sbloom if (c == cmdchar) { 27223530Sbloom bol = 0; 27323530Sbloom local = 1; 27423530Sbloom continue; 2756444Swnj } 27623530Sbloom } else if (local) { 27723530Sbloom local = 0; 27823530Sbloom if (c == '.' || c == deftc.t_eofc) { 27923530Sbloom echo(c); 28023530Sbloom break; 2816444Swnj } 28223530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 28323530Sbloom bol = 1; 28423530Sbloom echo(c); 28523530Sbloom stop(c); 28623530Sbloom continue; 28723530Sbloom } 28823530Sbloom if (c != cmdchar) 28923530Sbloom write(rem, &cmdchar, 1); 2906444Swnj } 29123530Sbloom if (write(rem, &c, 1) == 0) { 29223530Sbloom prf("line gone"); 29323530Sbloom break; 2946444Swnj } 29523530Sbloom bol = c == defkill || c == deftc.t_eofc || 29623530Sbloom c == '\r' || c == '\n'; 2976444Swnj } 2986444Swnj } 2996444Swnj 30023530Sbloom echo(c) 30123530Sbloom register char c; 30223530Sbloom { 30323530Sbloom char buf[8]; 30423530Sbloom register char *p = buf; 30523530Sbloom 30623530Sbloom c &= 0177; 30723530Sbloom *p++ = cmdchar; 30823530Sbloom if (c < ' ') { 30923530Sbloom *p++ = '^'; 31023530Sbloom *p++ = c + '@'; 31123530Sbloom } else if (c == 0177) { 31223530Sbloom *p++ = '^'; 31323530Sbloom *p++ = '?'; 31423530Sbloom } else 31523530Sbloom *p++ = c; 31623530Sbloom *p++ = '\r'; 31723530Sbloom *p++ = '\n'; 31823530Sbloom write(1, buf, p - buf); 31923530Sbloom } 32023530Sbloom 32118358Ssam stop(cmdc) 32218358Ssam char cmdc; 32318358Ssam { 32418358Ssam mode(0); 32518358Ssam signal(SIGCHLD, SIG_IGN); 32618358Ssam kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 32718358Ssam signal(SIGCHLD, catchild); 32818358Ssam mode(1); 32918358Ssam sigwinch(); /* check for size changes */ 33018358Ssam } 33118358Ssam 33218358Ssam sigwinch() 33318358Ssam { 33418358Ssam struct winsize ws; 33518358Ssam 336*25341Smckusick if (dosigwinch && ioctl(0, TIOCGWINSZ, &ws) == 0 && 33718358Ssam bcmp(&ws, &winsize, sizeof (ws))) { 33818358Ssam winsize = ws; 33924726Smckusick sendwindow(); 34018358Ssam } 34118358Ssam } 34218358Ssam 34324726Smckusick /* 34424726Smckusick * Send the window size to the server via the magic escape 34524726Smckusick */ 34624726Smckusick sendwindow() 34724726Smckusick { 34824726Smckusick char obuf[4 + sizeof (struct winsize)]; 34924726Smckusick struct winsize *wp = (struct winsize *)(obuf+4); 35024726Smckusick 35124726Smckusick obuf[0] = 0377; 35224726Smckusick obuf[1] = 0377; 35324726Smckusick obuf[2] = 's'; 35424726Smckusick obuf[3] = 's'; 35524726Smckusick wp->ws_row = htons(winsize.ws_row); 35624726Smckusick wp->ws_col = htons(winsize.ws_col); 35724726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 35824726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 35924726Smckusick (void) write(rem, obuf, sizeof(obuf)); 36024726Smckusick } 36124726Smckusick 3626444Swnj oob() 3636444Swnj { 36410839Ssam int out = 1+1, atmark; 3659365Ssam char waste[BUFSIZ], mark; 36624726Smckusick struct sgttyb sb; 36724919Smckusick static int didnotify = 0; 3686444Swnj 3699365Ssam ioctl(1, TIOCFLUSH, (char *)&out); 3706444Swnj for (;;) { 37124726Smckusick int rv; 37210839Ssam if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 3736444Swnj perror("ioctl"); 3746444Swnj break; 3756444Swnj } 37610839Ssam if (atmark) 3776444Swnj break; 37824726Smckusick rv = read(rem, waste, sizeof (waste)); 37924726Smckusick if (rv <= 0) 38023230Sbloom break; 3816444Swnj } 38212990Ssam recv(rem, &mark, 1, MSG_OOB); 38324919Smckusick if (didnotify == 0 && (mark & TIOCPKT_WINDOW)) { 38424726Smckusick /* 38524726Smckusick * Let server know about window size changes 38624726Smckusick */ 38724726Smckusick kill(getppid(), SIGURG); 38824919Smckusick didnotify = 1; 38924726Smckusick } 39024726Smckusick if (eight) 39124726Smckusick return; 3926444Swnj if (mark & TIOCPKT_NOSTOP) { 39324726Smckusick ioctl(0, TIOCGETP, (char *)&sb); 39424726Smckusick sb.sg_flags &= ~CBREAK; 39524726Smckusick sb.sg_flags |= RAW; 39624726Smckusick ioctl(0, TIOCSETN, (char *)&sb); 39713075Ssam notc.t_stopc = -1; 39813075Ssam notc.t_startc = -1; 39913075Ssam ioctl(0, TIOCSETC, (char *)¬c); 4006444Swnj } 4016444Swnj if (mark & TIOCPKT_DOSTOP) { 40224726Smckusick ioctl(0, TIOCGETP, (char *)&sb); 40324726Smckusick sb.sg_flags &= ~RAW; 40424726Smckusick sb.sg_flags |= CBREAK; 40524726Smckusick ioctl(0, TIOCSETN, (char *)&sb); 40613075Ssam notc.t_stopc = deftc.t_stopc; 40713075Ssam notc.t_startc = deftc.t_startc; 40813075Ssam ioctl(0, TIOCSETC, (char *)¬c); 4096444Swnj } 4106444Swnj } 4116444Swnj 4129365Ssam /* 4139365Ssam * reader: read from remote: line -> 1 4149365Ssam */ 4159365Ssam reader() 4166444Swnj { 4179365Ssam char rb[BUFSIZ]; 4189365Ssam register int cnt; 4196444Swnj 42023530Sbloom signal(SIGTTOU, SIG_IGN); 42124727Smckusick { int pid = getpid(); 42224727Smckusick fcntl(rem, F_SETOWN, pid); } 4236444Swnj for (;;) { 4249365Ssam cnt = read(rem, rb, sizeof (rb)); 42511396Ssam if (cnt == 0) 42611396Ssam break; 42711396Ssam if (cnt < 0) { 4289365Ssam if (errno == EINTR) 4296444Swnj continue; 4306444Swnj break; 4316444Swnj } 4329365Ssam write(1, rb, cnt); 4336444Swnj } 4346444Swnj } 4356444Swnj 4366444Swnj mode(f) 4376444Swnj { 43813075Ssam struct tchars *tc; 43913075Ssam struct ltchars *ltc; 44013075Ssam struct sgttyb sb; 44121583Sbloom int lflags; 4429365Ssam 44313075Ssam ioctl(0, TIOCGETP, (char *)&sb); 44421583Sbloom ioctl(0, TIOCLGET, (char *)&lflags); 4459962Ssam switch (f) { 4469962Ssam 4479962Ssam case 0: 44813075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 44913075Ssam sb.sg_flags |= defflags|tabflag; 4509962Ssam tc = &deftc; 45113075Ssam ltc = &defltc; 45213075Ssam sb.sg_kill = defkill; 45313075Ssam sb.sg_erase = deferase; 45421583Sbloom lflags = deflflags; 4559962Ssam break; 4569962Ssam 4579962Ssam case 1: 45813075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 45913075Ssam sb.sg_flags &= ~defflags; 46012155Ssam /* preserve tab delays, but turn off XTABS */ 46113075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 46213075Ssam sb.sg_flags &= ~TBDELAY; 4639962Ssam tc = ¬c; 46413075Ssam ltc = &noltc; 46513075Ssam sb.sg_kill = sb.sg_erase = -1; 46621583Sbloom if (litout) 46721583Sbloom lflags |= LLITOUT; 4689962Ssam break; 4699962Ssam 4709962Ssam default: 4719962Ssam return; 4726444Swnj } 47313075Ssam ioctl(0, TIOCSLTC, (char *)ltc); 47413075Ssam ioctl(0, TIOCSETC, (char *)tc); 47513075Ssam ioctl(0, TIOCSETN, (char *)&sb); 47621583Sbloom ioctl(0, TIOCLSET, (char *)&lflags); 4776444Swnj } 4786444Swnj 4799365Ssam /*VARARGS*/ 48024726Smckusick prf(f, a1, a2, a3, a4, a5) 4819365Ssam char *f; 4826444Swnj { 48324726Smckusick fprintf(stderr, f, a1, a2, a3, a4, a5); 4846444Swnj fprintf(stderr, CRLF); 4856444Swnj } 4866444Swnj 4879365Ssam lostpeer() 4886444Swnj { 48912990Ssam signal(SIGPIPE, SIG_IGN); 49012155Ssam prf("\007Connection closed."); 4919365Ssam done(); 4926444Swnj } 493