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*24726Smckusick static char sccsid[] = "@(#)rlogin.c 5.3.1.2 (Berkeley) 09/12/85"; 1521595Sdist #endif not lint 1621595Sdist 1712990Ssam /* 1812990Ssam * rlogin - remote login 1912990Ssam */ 206444Swnj #include <sys/types.h> 216444Swnj #include <sys/socket.h> 2213620Ssam #include <sys/wait.h> 239365Ssam 249207Ssam #include <netinet/in.h> 259365Ssam 269365Ssam #include <stdio.h> 279365Ssam #include <sgtty.h> 286444Swnj #include <errno.h> 296444Swnj #include <pwd.h> 309365Ssam #include <signal.h> 319365Ssam #include <netdb.h> 326444Swnj 33*24726Smckusick # ifndef TIOCPKT_WINDOW 34*24726Smckusick # define TIOCPKT_WINDOW 0x80 35*24726Smckusick # endif TIOCPKT_WINDOW 36*24726Smckusick 376444Swnj char *index(), *rindex(), *malloc(), *getenv(); 386444Swnj struct passwd *getpwuid(); 399365Ssam char *name; 406444Swnj int rem; 416444Swnj char cmdchar = '~'; 426444Swnj int eight; 4321583Sbloom int litout; 446444Swnj char *speeds[] = 456444Swnj { "0", "50", "75", "110", "134", "150", "200", "300", 466444Swnj "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 4718358Ssam char term[256] = "network"; 489365Ssam extern int errno; 499365Ssam int lostpeer(); 50*24726Smckusick int dosigwinch = 0; 51*24726Smckusick int nosigwin = 0; 5218358Ssam struct winsize winsize; 53*24726Smckusick 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; 63*24726Smckusick 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 } 10218358Ssam if (argc > 0 && !strcmp(*argv, "-w")) { 10318358Ssam nosigwin++; 10418358Ssam argv++, argc--; 10518358Ssam goto another; 10618358Ssam } 1076444Swnj if (host == 0) 1086444Swnj goto usage; 1096444Swnj if (argc > 0) 1106444Swnj goto usage; 1116444Swnj pwd = getpwuid(getuid()); 1126444Swnj if (pwd == 0) { 1136444Swnj fprintf(stderr, "Who are you?\n"); 1146444Swnj exit(1); 1156444Swnj } 1169365Ssam sp = getservbyname("login", "tcp"); 1179365Ssam if (sp == 0) { 1189365Ssam fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 1199365Ssam exit(2); 1209365Ssam } 1219241Ssam cp = getenv("TERM"); 1229241Ssam if (cp) 1239241Ssam strcpy(term, cp); 12418358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 1256444Swnj strcat(term, "/"); 1266444Swnj strcat(term, speeds[ttyb.sg_ospeed]); 1276444Swnj } 128*24726Smckusick (void) ioctl(0, TIOCGWINSZ, &winsize); 12912990Ssam signal(SIGPIPE, lostpeer); 130*24726Smckusick signal(SIGURG, oob); 131*24726Smckusick oldmask = sigblock(sigmask(SIGURG)); 1329365Ssam rem = rcmd(&host, sp->s_port, pwd->pw_name, 1336444Swnj name ? name : pwd->pw_name, term, 0); 1346444Swnj if (rem < 0) 1356444Swnj exit(1); 13610415Ssam if (options & SO_DEBUG && 13717449Slepreau setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) 13810415Ssam perror("rlogin: setsockopt (SO_DEBUG)"); 1399365Ssam uid = getuid(); 1409365Ssam if (setuid(uid) < 0) { 1419365Ssam perror("rlogin: setuid"); 1429365Ssam exit(1); 1439365Ssam } 144*24726Smckusick doit(oldmask); 1459365Ssam /*NOTREACHED*/ 1466444Swnj usage: 1476444Swnj fprintf(stderr, 14821583Sbloom "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -w ]\n"); 1496444Swnj exit(1); 1506444Swnj } 1516444Swnj 1526444Swnj #define CRLF "\r\n" 1536444Swnj 1549365Ssam int child; 15511803Sedward int catchild(); 156*24726Smckusick int writeroob(); 1579365Ssam 15813075Ssam int defflags, tabflag; 15921583Sbloom int deflflags; 16013075Ssam char deferase, defkill; 16113075Ssam struct tchars deftc; 16213075Ssam struct ltchars defltc; 16313075Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 16413075Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 1656444Swnj 166*24726Smckusick doit(oldmask) 1676444Swnj { 1686444Swnj int exit(); 16913075Ssam struct sgttyb sb; 1706444Swnj 17113075Ssam ioctl(0, TIOCGETP, (char *)&sb); 17213075Ssam defflags = sb.sg_flags; 17312155Ssam tabflag = defflags & TBDELAY; 1749962Ssam defflags &= ECHO | CRMOD; 17513075Ssam deferase = sb.sg_erase; 17613075Ssam defkill = sb.sg_kill; 17721583Sbloom ioctl(0, TIOCLGET, (char *)&deflflags); 17813075Ssam ioctl(0, TIOCGETC, (char *)&deftc); 17913075Ssam notc.t_startc = deftc.t_startc; 18013075Ssam notc.t_stopc = deftc.t_stopc; 18113075Ssam ioctl(0, TIOCGLTC, (char *)&defltc); 182*24726Smckusick signal(SIGINT, SIG_IGN); 18312990Ssam signal(SIGHUP, exit); 18412990Ssam signal(SIGQUIT, exit); 1859365Ssam child = fork(); 1869365Ssam if (child == -1) { 1879365Ssam perror("rlogin: fork"); 1889365Ssam done(); 1899365Ssam } 1909365Ssam if (child == 0) { 191*24726Smckusick mode(1); 192*24726Smckusick sigsetmask(oldmask); 1939365Ssam reader(); 19412155Ssam sleep(1); 19512155Ssam prf("\007Connection closed."); 1966444Swnj exit(3); 1976444Swnj } 198*24726Smckusick signal(SIGURG, writeroob); 199*24726Smckusick sigsetmask(oldmask); 20012990Ssam signal(SIGCHLD, catchild); 20118358Ssam if (!nosigwin) 20218358Ssam signal(SIGWINCH, sigwinch); 2039365Ssam writer(); 20412155Ssam prf("Closed connection."); 2056444Swnj done(); 2066444Swnj } 2076444Swnj 2086444Swnj done() 2096444Swnj { 2106444Swnj 2116444Swnj mode(0); 2129365Ssam if (child > 0 && kill(child, SIGKILL) >= 0) 2139365Ssam wait((int *)0); 2146444Swnj exit(0); 2156444Swnj } 2166444Swnj 217*24726Smckusick /* 218*24726Smckusick * This is called when the reader process gets the out-of-band (urgent) 219*24726Smckusick * request to turn on the window-changing protocol. 220*24726Smckusick */ 221*24726Smckusick writeroob() 222*24726Smckusick { 223*24726Smckusick 224*24726Smckusick dosigwinch = 1; 225*24726Smckusick sendwindow(); 226*24726Smckusick } 227*24726Smckusick 22811803Sedward catchild() 22911803Sedward { 23011803Sedward union wait status; 23111803Sedward int pid; 23211803Sedward 23311803Sedward again: 23411803Sedward pid = wait3(&status, WNOHANG|WUNTRACED, 0); 23511803Sedward if (pid == 0) 23611803Sedward return; 23711803Sedward /* 23811803Sedward * if the child (reader) dies, just quit 23911803Sedward */ 24011803Sedward if (pid < 0 || pid == child && !WIFSTOPPED(status)) 24111803Sedward done(); 24211803Sedward goto again; 24311803Sedward } 24411803Sedward 2456444Swnj /* 2469365Ssam * writer: write to remote: 0 -> line. 2479365Ssam * ~. terminate 2489365Ssam * ~^Z suspend rlogin process. 24910415Ssam * ~^Y suspend rlogin process, but leave reader alone. 2506444Swnj */ 2519365Ssam writer() 2526444Swnj { 25323530Sbloom char c; 25411803Sedward register n; 25523530Sbloom register bol = 1; /* beginning of line */ 25623530Sbloom register local = 0; 2576444Swnj 25811803Sedward for (;;) { 25911803Sedward n = read(0, &c, 1); 26018358Ssam if (n <= 0) { 26118358Ssam if (n < 0 && errno == EINTR) 26218358Ssam continue; 26311803Sedward break; 26418358Ssam } 2659365Ssam /* 2669365Ssam * If we're at the beginning of the line 2679365Ssam * and recognize a command character, then 2689365Ssam * we echo locally. Otherwise, characters 2699365Ssam * are echo'd remotely. If the command 2709365Ssam * character is doubled, this acts as a 2719365Ssam * force and local echo is suppressed. 2729365Ssam */ 27323530Sbloom if (bol) { 27423530Sbloom bol = 0; 27523530Sbloom if (c == cmdchar) { 27623530Sbloom bol = 0; 27723530Sbloom local = 1; 27823530Sbloom continue; 2796444Swnj } 28023530Sbloom } else if (local) { 28123530Sbloom local = 0; 28223530Sbloom if (c == '.' || c == deftc.t_eofc) { 28323530Sbloom echo(c); 28423530Sbloom break; 2856444Swnj } 28623530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 28723530Sbloom bol = 1; 28823530Sbloom echo(c); 28923530Sbloom stop(c); 29023530Sbloom continue; 29123530Sbloom } 29223530Sbloom if (c != cmdchar) 29323530Sbloom write(rem, &cmdchar, 1); 2946444Swnj } 29523530Sbloom if (write(rem, &c, 1) == 0) { 29623530Sbloom prf("line gone"); 29723530Sbloom break; 2986444Swnj } 29923530Sbloom bol = c == defkill || c == deftc.t_eofc || 30023530Sbloom c == '\r' || c == '\n'; 3016444Swnj } 3026444Swnj } 3036444Swnj 30423530Sbloom echo(c) 30523530Sbloom register char c; 30623530Sbloom { 30723530Sbloom char buf[8]; 30823530Sbloom register char *p = buf; 30923530Sbloom 31023530Sbloom c &= 0177; 31123530Sbloom *p++ = cmdchar; 31223530Sbloom if (c < ' ') { 31323530Sbloom *p++ = '^'; 31423530Sbloom *p++ = c + '@'; 31523530Sbloom } else if (c == 0177) { 31623530Sbloom *p++ = '^'; 31723530Sbloom *p++ = '?'; 31823530Sbloom } else 31923530Sbloom *p++ = c; 32023530Sbloom *p++ = '\r'; 32123530Sbloom *p++ = '\n'; 32223530Sbloom write(1, buf, p - buf); 32323530Sbloom } 32423530Sbloom 32518358Ssam stop(cmdc) 32618358Ssam char cmdc; 32718358Ssam { 32818358Ssam mode(0); 32918358Ssam signal(SIGCHLD, SIG_IGN); 33018358Ssam kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 33118358Ssam signal(SIGCHLD, catchild); 33218358Ssam mode(1); 33318358Ssam sigwinch(); /* check for size changes */ 33418358Ssam } 33518358Ssam 33618358Ssam sigwinch() 33718358Ssam { 33818358Ssam struct winsize ws; 33918358Ssam 340*24726Smckusick if (dosigwinch && !nosigwin && ioctl(0, TIOCGWINSZ, &ws) == 0 && 34118358Ssam bcmp(&ws, &winsize, sizeof (ws))) { 34218358Ssam winsize = ws; 343*24726Smckusick sendwindow(); 34418358Ssam } 34518358Ssam } 34618358Ssam 347*24726Smckusick /* 348*24726Smckusick * Send the window size to the server via the magic escape 349*24726Smckusick */ 350*24726Smckusick sendwindow() 351*24726Smckusick { 352*24726Smckusick char obuf[4 + sizeof (struct winsize)]; 353*24726Smckusick struct winsize *wp = (struct winsize *)(obuf+4); 354*24726Smckusick 355*24726Smckusick obuf[0] = 0377; 356*24726Smckusick obuf[1] = 0377; 357*24726Smckusick obuf[2] = 's'; 358*24726Smckusick obuf[3] = 's'; 359*24726Smckusick wp->ws_row = htons(winsize.ws_row); 360*24726Smckusick wp->ws_col = htons(winsize.ws_col); 361*24726Smckusick wp->ws_xpixel = htons(winsize.ws_xpixel); 362*24726Smckusick wp->ws_ypixel = htons(winsize.ws_ypixel); 363*24726Smckusick (void) write(rem, obuf, sizeof(obuf)); 364*24726Smckusick } 365*24726Smckusick 3666444Swnj oob() 3676444Swnj { 36810839Ssam int out = 1+1, atmark; 3699365Ssam char waste[BUFSIZ], mark; 370*24726Smckusick struct sgttyb sb; 3716444Swnj 3729365Ssam ioctl(1, TIOCFLUSH, (char *)&out); 3736444Swnj for (;;) { 374*24726Smckusick int rv; 37510839Ssam if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 3766444Swnj perror("ioctl"); 3776444Swnj break; 3786444Swnj } 37910839Ssam if (atmark) 3806444Swnj break; 381*24726Smckusick rv = read(rem, waste, sizeof (waste)); 382*24726Smckusick if (rv <= 0) 38323230Sbloom break; 3846444Swnj } 38512990Ssam recv(rem, &mark, 1, MSG_OOB); 386*24726Smckusick if (mark & TIOCPKT_WINDOW) { 387*24726Smckusick /* 388*24726Smckusick * Let server know about window size changes 389*24726Smckusick */ 390*24726Smckusick kill(getppid(), SIGURG); 391*24726Smckusick } 392*24726Smckusick if (eight) 393*24726Smckusick return; 3946444Swnj if (mark & TIOCPKT_NOSTOP) { 395*24726Smckusick ioctl(0, TIOCGETP, (char *)&sb); 396*24726Smckusick sb.sg_flags &= ~CBREAK; 397*24726Smckusick sb.sg_flags |= RAW; 398*24726Smckusick ioctl(0, TIOCSETN, (char *)&sb); 39913075Ssam notc.t_stopc = -1; 40013075Ssam notc.t_startc = -1; 40113075Ssam ioctl(0, TIOCSETC, (char *)¬c); 4026444Swnj } 4036444Swnj if (mark & TIOCPKT_DOSTOP) { 404*24726Smckusick ioctl(0, TIOCGETP, (char *)&sb); 405*24726Smckusick sb.sg_flags &= ~RAW; 406*24726Smckusick sb.sg_flags |= CBREAK; 407*24726Smckusick ioctl(0, TIOCSETN, (char *)&sb); 40813075Ssam notc.t_stopc = deftc.t_stopc; 40913075Ssam notc.t_startc = deftc.t_startc; 41013075Ssam ioctl(0, TIOCSETC, (char *)¬c); 4116444Swnj } 4126444Swnj } 4136444Swnj 4149365Ssam /* 4159365Ssam * reader: read from remote: line -> 1 4169365Ssam */ 4179365Ssam reader() 4186444Swnj { 4199365Ssam char rb[BUFSIZ]; 4209365Ssam register int cnt; 4216444Swnj 42223530Sbloom signal(SIGTTOU, SIG_IGN); 42324725Smckusick { int pid = -getpid(); 42424725Smckusick ioctl(rem, SIOCSPGRP, (char *)&pid); } 4256444Swnj for (;;) { 4269365Ssam cnt = read(rem, rb, sizeof (rb)); 42711396Ssam if (cnt == 0) 42811396Ssam break; 42911396Ssam if (cnt < 0) { 4309365Ssam if (errno == EINTR) 4316444Swnj continue; 4326444Swnj break; 4336444Swnj } 4349365Ssam write(1, rb, cnt); 4356444Swnj } 4366444Swnj } 4376444Swnj 4386444Swnj mode(f) 4396444Swnj { 44013075Ssam struct tchars *tc; 44113075Ssam struct ltchars *ltc; 44213075Ssam struct sgttyb sb; 44321583Sbloom int lflags; 4449365Ssam 44513075Ssam ioctl(0, TIOCGETP, (char *)&sb); 44621583Sbloom ioctl(0, TIOCLGET, (char *)&lflags); 4479962Ssam switch (f) { 4489962Ssam 4499962Ssam case 0: 45013075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 45113075Ssam sb.sg_flags |= defflags|tabflag; 4529962Ssam tc = &deftc; 45313075Ssam ltc = &defltc; 45413075Ssam sb.sg_kill = defkill; 45513075Ssam sb.sg_erase = deferase; 45621583Sbloom lflags = deflflags; 4579962Ssam break; 4589962Ssam 4599962Ssam case 1: 46013075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 46113075Ssam sb.sg_flags &= ~defflags; 46212155Ssam /* preserve tab delays, but turn off XTABS */ 46313075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 46413075Ssam sb.sg_flags &= ~TBDELAY; 4659962Ssam tc = ¬c; 46613075Ssam ltc = &noltc; 46713075Ssam sb.sg_kill = sb.sg_erase = -1; 46821583Sbloom if (litout) 46921583Sbloom lflags |= LLITOUT; 4709962Ssam break; 4719962Ssam 4729962Ssam default: 4739962Ssam return; 4746444Swnj } 47513075Ssam ioctl(0, TIOCSLTC, (char *)ltc); 47613075Ssam ioctl(0, TIOCSETC, (char *)tc); 47713075Ssam ioctl(0, TIOCSETN, (char *)&sb); 47821583Sbloom ioctl(0, TIOCLSET, (char *)&lflags); 4796444Swnj } 4806444Swnj 4819365Ssam /*VARARGS*/ 482*24726Smckusick prf(f, a1, a2, a3, a4, a5) 4839365Ssam char *f; 4846444Swnj { 485*24726Smckusick fprintf(stderr, f, a1, a2, a3, a4, a5); 4866444Swnj fprintf(stderr, CRLF); 4876444Swnj } 4886444Swnj 4899365Ssam lostpeer() 4906444Swnj { 49112990Ssam signal(SIGPIPE, SIG_IGN); 49212155Ssam prf("\007Connection closed."); 4939365Ssam done(); 4946444Swnj } 495