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*24727Smckusick static char sccsid[] = "@(#)rlogin.c 5.5 (Berkeley) 09/12/85"; 1521595Sdist #endif not lint 1621595Sdist 1712990Ssam /* 1812990Ssam * rlogin - remote login 1912990Ssam */ 206444Swnj #include <sys/types.h> 21*24727Smckusick #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; 5224726Smckusick int nosigwin = 0; 5318358Ssam struct winsize winsize; 5424726Smckusick int sigwinch(), oob(); 556444Swnj 566444Swnj main(argc, argv) 576444Swnj int argc; 586444Swnj char **argv; 596444Swnj { 609365Ssam char *host, *cp; 616444Swnj struct sgttyb ttyb; 626444Swnj struct passwd *pwd; 639365Ssam struct servent *sp; 6424726Smckusick int uid, options = 0, oldmask; 6517449Slepreau int on = 1; 666444Swnj 676444Swnj host = rindex(argv[0], '/'); 686444Swnj if (host) 696444Swnj host++; 706444Swnj else 716444Swnj host = argv[0]; 726444Swnj argv++, --argc; 736444Swnj if (!strcmp(host, "rlogin")) 746444Swnj host = *argv++, --argc; 756444Swnj another: 7610839Ssam if (argc > 0 && !strcmp(*argv, "-d")) { 776444Swnj argv++, argc--; 7810415Ssam options |= SO_DEBUG; 796444Swnj goto another; 806444Swnj } 8110839Ssam if (argc > 0 && !strcmp(*argv, "-l")) { 826444Swnj argv++, argc--; 836444Swnj if (argc == 0) 846444Swnj goto usage; 856444Swnj name = *argv++; argc--; 866444Swnj goto another; 876444Swnj } 8810839Ssam if (argc > 0 && !strncmp(*argv, "-e", 2)) { 896444Swnj cmdchar = argv[0][2]; 906444Swnj argv++, argc--; 916444Swnj goto another; 926444Swnj } 9310839Ssam if (argc > 0 && !strcmp(*argv, "-8")) { 946444Swnj eight = 1; 956444Swnj argv++, argc--; 966444Swnj goto another; 976444Swnj } 9821583Sbloom if (argc > 0 && !strcmp(*argv, "-L")) { 9921583Sbloom litout = 1; 10021583Sbloom argv++, argc--; 10121583Sbloom goto another; 10221583Sbloom } 10318358Ssam if (argc > 0 && !strcmp(*argv, "-w")) { 10418358Ssam nosigwin++; 10518358Ssam argv++, argc--; 10618358Ssam goto another; 10718358Ssam } 1086444Swnj if (host == 0) 1096444Swnj goto usage; 1106444Swnj if (argc > 0) 1116444Swnj goto usage; 1126444Swnj pwd = getpwuid(getuid()); 1136444Swnj if (pwd == 0) { 1146444Swnj fprintf(stderr, "Who are you?\n"); 1156444Swnj exit(1); 1166444Swnj } 1179365Ssam sp = getservbyname("login", "tcp"); 1189365Ssam if (sp == 0) { 1199365Ssam fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 1209365Ssam exit(2); 1219365Ssam } 1229241Ssam cp = getenv("TERM"); 1239241Ssam if (cp) 1249241Ssam strcpy(term, cp); 12518358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 1266444Swnj strcat(term, "/"); 1276444Swnj strcat(term, speeds[ttyb.sg_ospeed]); 1286444Swnj } 12924726Smckusick (void) ioctl(0, TIOCGWINSZ, &winsize); 13012990Ssam signal(SIGPIPE, lostpeer); 13124726Smckusick signal(SIGURG, oob); 13224726Smckusick oldmask = sigblock(sigmask(SIGURG)); 1339365Ssam rem = rcmd(&host, sp->s_port, pwd->pw_name, 1346444Swnj name ? name : pwd->pw_name, term, 0); 1356444Swnj if (rem < 0) 1366444Swnj exit(1); 13710415Ssam if (options & SO_DEBUG && 13817449Slepreau setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) 13910415Ssam perror("rlogin: setsockopt (SO_DEBUG)"); 1409365Ssam uid = getuid(); 1419365Ssam if (setuid(uid) < 0) { 1429365Ssam perror("rlogin: setuid"); 1439365Ssam exit(1); 1449365Ssam } 14524726Smckusick doit(oldmask); 1469365Ssam /*NOTREACHED*/ 1476444Swnj usage: 1486444Swnj fprintf(stderr, 14921583Sbloom "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -w ]\n"); 1506444Swnj exit(1); 1516444Swnj } 1526444Swnj 1536444Swnj #define CRLF "\r\n" 1546444Swnj 1559365Ssam int child; 15611803Sedward int catchild(); 15724726Smckusick int writeroob(); 1589365Ssam 15913075Ssam int defflags, tabflag; 16021583Sbloom int deflflags; 16113075Ssam char deferase, defkill; 16213075Ssam struct tchars deftc; 16313075Ssam struct ltchars defltc; 16413075Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 16513075Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 1666444Swnj 16724726Smckusick doit(oldmask) 1686444Swnj { 1696444Swnj int exit(); 17013075Ssam struct sgttyb sb; 1716444Swnj 17213075Ssam ioctl(0, TIOCGETP, (char *)&sb); 17313075Ssam defflags = sb.sg_flags; 17412155Ssam tabflag = defflags & TBDELAY; 1759962Ssam defflags &= ECHO | CRMOD; 17613075Ssam deferase = sb.sg_erase; 17713075Ssam defkill = sb.sg_kill; 17821583Sbloom ioctl(0, TIOCLGET, (char *)&deflflags); 17913075Ssam ioctl(0, TIOCGETC, (char *)&deftc); 18013075Ssam notc.t_startc = deftc.t_startc; 18113075Ssam notc.t_stopc = deftc.t_stopc; 18213075Ssam ioctl(0, TIOCGLTC, (char *)&defltc); 18324726Smckusick signal(SIGINT, SIG_IGN); 18412990Ssam signal(SIGHUP, exit); 18512990Ssam signal(SIGQUIT, exit); 1869365Ssam child = fork(); 1879365Ssam if (child == -1) { 1889365Ssam perror("rlogin: fork"); 1899365Ssam done(); 1909365Ssam } 1919365Ssam if (child == 0) { 19224726Smckusick mode(1); 19324726Smckusick sigsetmask(oldmask); 1949365Ssam reader(); 19512155Ssam sleep(1); 19612155Ssam prf("\007Connection closed."); 1976444Swnj exit(3); 1986444Swnj } 19924726Smckusick signal(SIGURG, writeroob); 20024726Smckusick sigsetmask(oldmask); 20112990Ssam signal(SIGCHLD, catchild); 20218358Ssam if (!nosigwin) 20318358Ssam signal(SIGWINCH, sigwinch); 2049365Ssam writer(); 20512155Ssam prf("Closed connection."); 2066444Swnj done(); 2076444Swnj } 2086444Swnj 2096444Swnj done() 2106444Swnj { 2116444Swnj 2126444Swnj mode(0); 2139365Ssam if (child > 0 && kill(child, SIGKILL) >= 0) 2149365Ssam wait((int *)0); 2156444Swnj exit(0); 2166444Swnj } 2176444Swnj 21824726Smckusick /* 21924726Smckusick * This is called when the reader process gets the out-of-band (urgent) 22024726Smckusick * request to turn on the window-changing protocol. 22124726Smckusick */ 22224726Smckusick writeroob() 22324726Smckusick { 22424726Smckusick 22524726Smckusick dosigwinch = 1; 22624726Smckusick sendwindow(); 22724726Smckusick } 22824726Smckusick 22911803Sedward catchild() 23011803Sedward { 23111803Sedward union wait status; 23211803Sedward int pid; 23311803Sedward 23411803Sedward again: 23511803Sedward pid = wait3(&status, WNOHANG|WUNTRACED, 0); 23611803Sedward if (pid == 0) 23711803Sedward return; 23811803Sedward /* 23911803Sedward * if the child (reader) dies, just quit 24011803Sedward */ 24111803Sedward if (pid < 0 || pid == child && !WIFSTOPPED(status)) 24211803Sedward done(); 24311803Sedward goto again; 24411803Sedward } 24511803Sedward 2466444Swnj /* 2479365Ssam * writer: write to remote: 0 -> line. 2489365Ssam * ~. terminate 2499365Ssam * ~^Z suspend rlogin process. 25010415Ssam * ~^Y suspend rlogin process, but leave reader alone. 2516444Swnj */ 2529365Ssam writer() 2536444Swnj { 25423530Sbloom char c; 25511803Sedward register n; 25623530Sbloom register bol = 1; /* beginning of line */ 25723530Sbloom register local = 0; 2586444Swnj 25911803Sedward for (;;) { 26011803Sedward n = read(0, &c, 1); 26118358Ssam if (n <= 0) { 26218358Ssam if (n < 0 && errno == EINTR) 26318358Ssam continue; 26411803Sedward break; 26518358Ssam } 2669365Ssam /* 2679365Ssam * If we're at the beginning of the line 2689365Ssam * and recognize a command character, then 2699365Ssam * we echo locally. Otherwise, characters 2709365Ssam * are echo'd remotely. If the command 2719365Ssam * character is doubled, this acts as a 2729365Ssam * force and local echo is suppressed. 2739365Ssam */ 27423530Sbloom if (bol) { 27523530Sbloom bol = 0; 27623530Sbloom if (c == cmdchar) { 27723530Sbloom bol = 0; 27823530Sbloom local = 1; 27923530Sbloom continue; 2806444Swnj } 28123530Sbloom } else if (local) { 28223530Sbloom local = 0; 28323530Sbloom if (c == '.' || c == deftc.t_eofc) { 28423530Sbloom echo(c); 28523530Sbloom break; 2866444Swnj } 28723530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 28823530Sbloom bol = 1; 28923530Sbloom echo(c); 29023530Sbloom stop(c); 29123530Sbloom continue; 29223530Sbloom } 29323530Sbloom if (c != cmdchar) 29423530Sbloom write(rem, &cmdchar, 1); 2956444Swnj } 29623530Sbloom if (write(rem, &c, 1) == 0) { 29723530Sbloom prf("line gone"); 29823530Sbloom break; 2996444Swnj } 30023530Sbloom bol = c == defkill || c == deftc.t_eofc || 30123530Sbloom c == '\r' || c == '\n'; 3026444Swnj } 3036444Swnj } 3046444Swnj 30523530Sbloom echo(c) 30623530Sbloom register char c; 30723530Sbloom { 30823530Sbloom char buf[8]; 30923530Sbloom register char *p = buf; 31023530Sbloom 31123530Sbloom c &= 0177; 31223530Sbloom *p++ = cmdchar; 31323530Sbloom if (c < ' ') { 31423530Sbloom *p++ = '^'; 31523530Sbloom *p++ = c + '@'; 31623530Sbloom } else if (c == 0177) { 31723530Sbloom *p++ = '^'; 31823530Sbloom *p++ = '?'; 31923530Sbloom } else 32023530Sbloom *p++ = c; 32123530Sbloom *p++ = '\r'; 32223530Sbloom *p++ = '\n'; 32323530Sbloom write(1, buf, p - buf); 32423530Sbloom } 32523530Sbloom 32618358Ssam stop(cmdc) 32718358Ssam char cmdc; 32818358Ssam { 32918358Ssam mode(0); 33018358Ssam signal(SIGCHLD, SIG_IGN); 33118358Ssam kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 33218358Ssam signal(SIGCHLD, catchild); 33318358Ssam mode(1); 33418358Ssam sigwinch(); /* check for size changes */ 33518358Ssam } 33618358Ssam 33718358Ssam sigwinch() 33818358Ssam { 33918358Ssam struct winsize ws; 34018358Ssam 34124726Smckusick if (dosigwinch && !nosigwin && ioctl(0, TIOCGWINSZ, &ws) == 0 && 34218358Ssam bcmp(&ws, &winsize, sizeof (ws))) { 34318358Ssam winsize = ws; 34424726Smckusick sendwindow(); 34518358Ssam } 34618358Ssam } 34718358Ssam 34824726Smckusick /* 34924726Smckusick * Send the window size to the server via the magic escape 35024726Smckusick */ 35124726Smckusick sendwindow() 35224726Smckusick { 35324726Smckusick char obuf[4 + sizeof (struct winsize)]; 35424726Smckusick struct winsize *wp = (struct winsize *)(obuf+4); 35524726Smckusick 35624726Smckusick obuf[0] = 0377; 35724726Smckusick obuf[1] = 0377; 35824726Smckusick obuf[2] = 's'; 35924726Smckusick obuf[3] = 's'; 36024726Smckusick wp->ws_row = htons(winsize.ws_row); 36124726Smckusick wp->ws_col = htons(winsize.ws_col); 36224726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 36324726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 36424726Smckusick (void) write(rem, obuf, sizeof(obuf)); 36524726Smckusick } 36624726Smckusick 3676444Swnj oob() 3686444Swnj { 36910839Ssam int out = 1+1, atmark; 3709365Ssam char waste[BUFSIZ], mark; 37124726Smckusick struct sgttyb sb; 3726444Swnj 3739365Ssam ioctl(1, TIOCFLUSH, (char *)&out); 3746444Swnj for (;;) { 37524726Smckusick int rv; 37610839Ssam if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 3776444Swnj perror("ioctl"); 3786444Swnj break; 3796444Swnj } 38010839Ssam if (atmark) 3816444Swnj break; 38224726Smckusick rv = read(rem, waste, sizeof (waste)); 38324726Smckusick if (rv <= 0) 38423230Sbloom break; 3856444Swnj } 38612990Ssam recv(rem, &mark, 1, MSG_OOB); 38724726Smckusick if (mark & TIOCPKT_WINDOW) { 38824726Smckusick /* 38924726Smckusick * Let server know about window size changes 39024726Smckusick */ 39124726Smckusick kill(getppid(), SIGURG); 39224726Smckusick } 39324726Smckusick if (eight) 39424726Smckusick return; 3956444Swnj if (mark & TIOCPKT_NOSTOP) { 39624726Smckusick ioctl(0, TIOCGETP, (char *)&sb); 39724726Smckusick sb.sg_flags &= ~CBREAK; 39824726Smckusick sb.sg_flags |= RAW; 39924726Smckusick ioctl(0, TIOCSETN, (char *)&sb); 40013075Ssam notc.t_stopc = -1; 40113075Ssam notc.t_startc = -1; 40213075Ssam ioctl(0, TIOCSETC, (char *)¬c); 4036444Swnj } 4046444Swnj if (mark & TIOCPKT_DOSTOP) { 40524726Smckusick ioctl(0, TIOCGETP, (char *)&sb); 40624726Smckusick sb.sg_flags &= ~RAW; 40724726Smckusick sb.sg_flags |= CBREAK; 40824726Smckusick ioctl(0, TIOCSETN, (char *)&sb); 40913075Ssam notc.t_stopc = deftc.t_stopc; 41013075Ssam notc.t_startc = deftc.t_startc; 41113075Ssam ioctl(0, TIOCSETC, (char *)¬c); 4126444Swnj } 4136444Swnj } 4146444Swnj 4159365Ssam /* 4169365Ssam * reader: read from remote: line -> 1 4179365Ssam */ 4189365Ssam reader() 4196444Swnj { 4209365Ssam char rb[BUFSIZ]; 4219365Ssam register int cnt; 4226444Swnj 42323530Sbloom signal(SIGTTOU, SIG_IGN); 424*24727Smckusick { int pid = getpid(); 425*24727Smckusick fcntl(rem, F_SETOWN, pid); } 4266444Swnj for (;;) { 4279365Ssam cnt = read(rem, rb, sizeof (rb)); 42811396Ssam if (cnt == 0) 42911396Ssam break; 43011396Ssam if (cnt < 0) { 4319365Ssam if (errno == EINTR) 4326444Swnj continue; 4336444Swnj break; 4346444Swnj } 4359365Ssam write(1, rb, cnt); 4366444Swnj } 4376444Swnj } 4386444Swnj 4396444Swnj mode(f) 4406444Swnj { 44113075Ssam struct tchars *tc; 44213075Ssam struct ltchars *ltc; 44313075Ssam struct sgttyb sb; 44421583Sbloom int lflags; 4459365Ssam 44613075Ssam ioctl(0, TIOCGETP, (char *)&sb); 44721583Sbloom ioctl(0, TIOCLGET, (char *)&lflags); 4489962Ssam switch (f) { 4499962Ssam 4509962Ssam case 0: 45113075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 45213075Ssam sb.sg_flags |= defflags|tabflag; 4539962Ssam tc = &deftc; 45413075Ssam ltc = &defltc; 45513075Ssam sb.sg_kill = defkill; 45613075Ssam sb.sg_erase = deferase; 45721583Sbloom lflags = deflflags; 4589962Ssam break; 4599962Ssam 4609962Ssam case 1: 46113075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 46213075Ssam sb.sg_flags &= ~defflags; 46312155Ssam /* preserve tab delays, but turn off XTABS */ 46413075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 46513075Ssam sb.sg_flags &= ~TBDELAY; 4669962Ssam tc = ¬c; 46713075Ssam ltc = &noltc; 46813075Ssam sb.sg_kill = sb.sg_erase = -1; 46921583Sbloom if (litout) 47021583Sbloom lflags |= LLITOUT; 4719962Ssam break; 4729962Ssam 4739962Ssam default: 4749962Ssam return; 4756444Swnj } 47613075Ssam ioctl(0, TIOCSLTC, (char *)ltc); 47713075Ssam ioctl(0, TIOCSETC, (char *)tc); 47813075Ssam ioctl(0, TIOCSETN, (char *)&sb); 47921583Sbloom ioctl(0, TIOCLSET, (char *)&lflags); 4806444Swnj } 4816444Swnj 4829365Ssam /*VARARGS*/ 48324726Smckusick prf(f, a1, a2, a3, a4, a5) 4849365Ssam char *f; 4856444Swnj { 48624726Smckusick fprintf(stderr, f, a1, a2, a3, a4, a5); 4876444Swnj fprintf(stderr, CRLF); 4886444Swnj } 4896444Swnj 4909365Ssam lostpeer() 4916444Swnj { 49212990Ssam signal(SIGPIPE, SIG_IGN); 49312155Ssam prf("\007Connection closed."); 4949365Ssam done(); 4956444Swnj } 496