16444Swnj #ifndef lint 2*21583Sbloom static char sccsid[] = "@(#)rlogin.c 4.18 (Berkeley) 85/05/31"; 36444Swnj #endif 46444Swnj 512990Ssam /* 612990Ssam * rlogin - remote login 712990Ssam */ 86444Swnj #include <sys/types.h> 96444Swnj #include <sys/socket.h> 1013620Ssam #include <sys/wait.h> 119365Ssam 129207Ssam #include <netinet/in.h> 139365Ssam 149365Ssam #include <stdio.h> 159365Ssam #include <sgtty.h> 166444Swnj #include <errno.h> 176444Swnj #include <pwd.h> 189365Ssam #include <signal.h> 199365Ssam #include <netdb.h> 2018358Ssam #include <setjmp.h> 216444Swnj 226444Swnj char *index(), *rindex(), *malloc(), *getenv(); 236444Swnj struct passwd *getpwuid(); 249365Ssam char *name; 256444Swnj int rem; 266444Swnj char cmdchar = '~'; 276444Swnj int eight; 28*21583Sbloom int litout; 296444Swnj char *speeds[] = 306444Swnj { "0", "50", "75", "110", "134", "150", "200", "300", 316444Swnj "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 3218358Ssam char term[256] = "network"; 339365Ssam extern int errno; 349365Ssam int lostpeer(); 3518358Ssam int nosigwin; 3618358Ssam jmp_buf winsizechanged; 3718358Ssam struct winsize winsize; 3818358Ssam int sigwinch(); 396444Swnj 406444Swnj main(argc, argv) 416444Swnj int argc; 426444Swnj char **argv; 436444Swnj { 449365Ssam char *host, *cp; 456444Swnj struct sgttyb ttyb; 466444Swnj struct passwd *pwd; 479365Ssam struct servent *sp; 4810415Ssam int uid, options = 0; 4917449Slepreau int on = 1; 506444Swnj 516444Swnj host = rindex(argv[0], '/'); 526444Swnj if (host) 536444Swnj host++; 546444Swnj else 556444Swnj host = argv[0]; 566444Swnj argv++, --argc; 576444Swnj if (!strcmp(host, "rlogin")) 586444Swnj host = *argv++, --argc; 596444Swnj another: 6010839Ssam if (argc > 0 && !strcmp(*argv, "-d")) { 616444Swnj argv++, argc--; 6210415Ssam options |= SO_DEBUG; 636444Swnj goto another; 646444Swnj } 6510839Ssam if (argc > 0 && !strcmp(*argv, "-l")) { 666444Swnj argv++, argc--; 676444Swnj if (argc == 0) 686444Swnj goto usage; 696444Swnj name = *argv++; argc--; 706444Swnj goto another; 716444Swnj } 7210839Ssam if (argc > 0 && !strncmp(*argv, "-e", 2)) { 736444Swnj cmdchar = argv[0][2]; 746444Swnj argv++, argc--; 756444Swnj goto another; 766444Swnj } 7710839Ssam if (argc > 0 && !strcmp(*argv, "-8")) { 786444Swnj eight = 1; 796444Swnj argv++, argc--; 806444Swnj goto another; 816444Swnj } 82*21583Sbloom if (argc > 0 && !strcmp(*argv, "-L")) { 83*21583Sbloom litout = 1; 84*21583Sbloom argv++, argc--; 85*21583Sbloom goto another; 86*21583Sbloom } 8718358Ssam if (argc > 0 && !strcmp(*argv, "-w")) { 8818358Ssam nosigwin++; 8918358Ssam argv++, argc--; 9018358Ssam goto another; 9118358Ssam } 926444Swnj if (host == 0) 936444Swnj goto usage; 946444Swnj if (argc > 0) 956444Swnj goto usage; 966444Swnj pwd = getpwuid(getuid()); 976444Swnj if (pwd == 0) { 986444Swnj fprintf(stderr, "Who are you?\n"); 996444Swnj exit(1); 1006444Swnj } 1019365Ssam sp = getservbyname("login", "tcp"); 1029365Ssam if (sp == 0) { 1039365Ssam fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 1049365Ssam exit(2); 1059365Ssam } 1069241Ssam cp = getenv("TERM"); 1079241Ssam if (cp) 1089241Ssam strcpy(term, cp); 10918358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 1106444Swnj strcat(term, "/"); 1116444Swnj strcat(term, speeds[ttyb.sg_ospeed]); 1126444Swnj } 11318358Ssam if (!nosigwin && ioctl(0, TIOCGWINSZ, &winsize) == 0) { 11418358Ssam cp = index(term, '\0'); 11518358Ssam sprintf(cp, "/%u,%u,%u,%u", winsize.ws_row, winsize.ws_col, 11618358Ssam winsize.ws_xpixel, winsize.ws_ypixel); 11718358Ssam } 11812990Ssam signal(SIGPIPE, lostpeer); 1199365Ssam rem = rcmd(&host, sp->s_port, pwd->pw_name, 1206444Swnj name ? name : pwd->pw_name, term, 0); 1216444Swnj if (rem < 0) 1226444Swnj exit(1); 12310415Ssam if (options & SO_DEBUG && 12417449Slepreau setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) 12510415Ssam perror("rlogin: setsockopt (SO_DEBUG)"); 1269365Ssam uid = getuid(); 1279365Ssam if (setuid(uid) < 0) { 1289365Ssam perror("rlogin: setuid"); 1299365Ssam exit(1); 1309365Ssam } 1319365Ssam doit(); 1329365Ssam /*NOTREACHED*/ 1336444Swnj usage: 1346444Swnj fprintf(stderr, 135*21583Sbloom "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -w ]\n"); 1366444Swnj exit(1); 1376444Swnj } 1386444Swnj 1396444Swnj #define CRLF "\r\n" 1406444Swnj 1419365Ssam int child; 14211803Sedward int catchild(); 1439365Ssam 14413075Ssam int defflags, tabflag; 145*21583Sbloom int deflflags; 14613075Ssam char deferase, defkill; 14713075Ssam struct tchars deftc; 14813075Ssam struct ltchars defltc; 14913075Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 15013075Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 1516444Swnj 1529365Ssam doit() 1536444Swnj { 1546444Swnj int exit(); 15513075Ssam struct sgttyb sb; 1566444Swnj 15713075Ssam ioctl(0, TIOCGETP, (char *)&sb); 15813075Ssam defflags = sb.sg_flags; 15912155Ssam tabflag = defflags & TBDELAY; 1609962Ssam defflags &= ECHO | CRMOD; 16113075Ssam deferase = sb.sg_erase; 16213075Ssam defkill = sb.sg_kill; 163*21583Sbloom ioctl(0, TIOCLGET, (char *)&deflflags); 16413075Ssam ioctl(0, TIOCGETC, (char *)&deftc); 16513075Ssam notc.t_startc = deftc.t_startc; 16613075Ssam notc.t_stopc = deftc.t_stopc; 16713075Ssam ioctl(0, TIOCGLTC, (char *)&defltc); 16812990Ssam signal(SIGINT, exit); 16912990Ssam signal(SIGHUP, exit); 17012990Ssam signal(SIGQUIT, exit); 1719365Ssam child = fork(); 1729365Ssam if (child == -1) { 1739365Ssam perror("rlogin: fork"); 1749365Ssam done(); 1759365Ssam } 17612990Ssam signal(SIGINT, SIG_IGN); 17711803Sedward mode(1); 1789365Ssam if (child == 0) { 1799365Ssam reader(); 18012155Ssam sleep(1); 18112155Ssam prf("\007Connection closed."); 1826444Swnj exit(3); 1836444Swnj } 18412990Ssam signal(SIGCHLD, catchild); 18518358Ssam if (!nosigwin) 18618358Ssam signal(SIGWINCH, sigwinch); 1879365Ssam writer(); 18812155Ssam prf("Closed connection."); 1896444Swnj done(); 1906444Swnj } 1916444Swnj 1926444Swnj done() 1936444Swnj { 1946444Swnj 1956444Swnj mode(0); 1969365Ssam if (child > 0 && kill(child, SIGKILL) >= 0) 1979365Ssam wait((int *)0); 1986444Swnj exit(0); 1996444Swnj } 2006444Swnj 20111803Sedward catchild() 20211803Sedward { 20311803Sedward union wait status; 20411803Sedward int pid; 20511803Sedward 20611803Sedward again: 20711803Sedward pid = wait3(&status, WNOHANG|WUNTRACED, 0); 20811803Sedward if (pid == 0) 20911803Sedward return; 21011803Sedward /* 21111803Sedward * if the child (reader) dies, just quit 21211803Sedward */ 21311803Sedward if (pid < 0 || pid == child && !WIFSTOPPED(status)) 21411803Sedward done(); 21511803Sedward goto again; 21611803Sedward } 21711803Sedward 2186444Swnj /* 2199365Ssam * writer: write to remote: 0 -> line. 2209365Ssam * ~. terminate 2219365Ssam * ~^Z suspend rlogin process. 22210415Ssam * ~^Y suspend rlogin process, but leave reader alone. 2236444Swnj */ 2249365Ssam writer() 2256444Swnj { 22618358Ssam char obuf[600], c; 22718358Ssam register char *op; 22811803Sedward register n; 2296444Swnj 23018358Ssam /* 23118358Ssam * Handle SIGWINCH's with in-band signaling of new 23218358Ssam * window size. It seems reasonable that we flush 23318358Ssam * pending input and not force out of band signal 23418358Ssam * as this most likely will occur from an input device 23518358Ssam * other than the keyboard (e.g. a mouse). 23618358Ssam * 23718358Ssam * The hack of using 0377 to signal an in-band signal 23818358Ssam * is pretty bad, but otherwise we'd be forced to 23918358Ssam * either get complicated (use MSG_OOB) or go to a 24018358Ssam * serious (telnet-style) protocol. 24118358Ssam */ 24218358Ssam if (setjmp(winsizechanged)) { 24318358Ssam struct winsize *wp = (struct winsize *)(obuf+4); 24418358Ssam 24518358Ssam obuf[0] = 0377; /* XXX */ 24618358Ssam obuf[1] = 0377; /* XXX */ 24718358Ssam obuf[2] = 's'; /* XXX */ 24818358Ssam obuf[3] = 's'; /* XXX */ 24918358Ssam wp->ws_row = htons(winsize.ws_row); 25018358Ssam wp->ws_col = htons(winsize.ws_col); 25118358Ssam wp->ws_xpixel = htons(winsize.ws_xpixel); 25218358Ssam wp->ws_ypixel = htons(winsize.ws_ypixel); 25318358Ssam (void) write(rem, obuf, 4+sizeof (*wp)); 25418358Ssam } 2559365Ssam top: 25618358Ssam op = obuf; 25711803Sedward for (;;) { 2589365Ssam int local; 2599365Ssam 26011803Sedward n = read(0, &c, 1); 26118358Ssam if (n <= 0) { 26218358Ssam if (n < 0 && errno == EINTR) 26318358Ssam continue; 26411803Sedward break; 26518358Ssam } 26618358Ssam if (!eight) 2679365Ssam c &= 0177; 2689365Ssam /* 2699365Ssam * If we're at the beginning of the line 2709365Ssam * and recognize a command character, then 2719365Ssam * we echo locally. Otherwise, characters 2729365Ssam * are echo'd remotely. If the command 2739365Ssam * character is doubled, this acts as a 2749365Ssam * force and local echo is suppressed. 2759365Ssam */ 27618358Ssam if (op == obuf) 2779365Ssam local = (c == cmdchar); 27818358Ssam if (op == obuf + 1 && *obuf == cmdchar) 2799365Ssam local = (c != cmdchar); 2809365Ssam if (!local) { 2819365Ssam if (write(rem, &c, 1) == 0) { 2829365Ssam prf("line gone"); 2839365Ssam return; 2846444Swnj } 28518358Ssam if (!eight) 2869365Ssam c &= 0177; 2879365Ssam } else { 2889365Ssam if (c == '\r' || c == '\n') { 28918358Ssam char cmdc = obuf[1]; 2906444Swnj 29113075Ssam if (cmdc == '.' || cmdc == deftc.t_eofc) { 2929365Ssam write(0, CRLF, sizeof(CRLF)); 2939365Ssam return; 2949962Ssam } 29513075Ssam if (cmdc == defltc.t_suspc || 29613075Ssam cmdc == defltc.t_dsuspc) { 29718358Ssam stop(cmdc); 2989365Ssam goto top; 2996444Swnj } 30018358Ssam *op++ = c; 30118358Ssam write(rem, obuf, op - obuf); 3029365Ssam goto top; 3036444Swnj } 3049365Ssam write(1, &c, 1); 3056444Swnj } 30618358Ssam *op++ = c; 30713075Ssam if (c == deferase) { 30818358Ssam op -= 2; 30918358Ssam if (op < obuf) 3109365Ssam goto top; 3116444Swnj } 31213075Ssam if (c == defkill || c == deftc.t_eofc || 3139365Ssam c == '\r' || c == '\n') 3149365Ssam goto top; 31518358Ssam if (op >= &obuf[sizeof (obuf)]) 31618358Ssam op--; 3176444Swnj } 3186444Swnj } 3196444Swnj 32018358Ssam stop(cmdc) 32118358Ssam char cmdc; 32218358Ssam { 32318358Ssam struct winsize ws; 32418358Ssam 32518358Ssam write(0, CRLF, sizeof(CRLF)); 32618358Ssam mode(0); 32718358Ssam signal(SIGCHLD, SIG_IGN); 32818358Ssam kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 32918358Ssam signal(SIGCHLD, catchild); 33018358Ssam mode(1); 33118358Ssam sigwinch(); /* check for size changes */ 33218358Ssam } 33318358Ssam 33418358Ssam sigwinch() 33518358Ssam { 33618358Ssam struct winsize ws; 33718358Ssam 33818358Ssam if (!nosigwin && ioctl(0, TIOCGWINSZ, &ws) == 0 && 33918358Ssam bcmp(&ws, &winsize, sizeof (ws))) { 34018358Ssam winsize = ws; 34118358Ssam longjmp(winsizechanged, 1); 34218358Ssam } 34318358Ssam } 34418358Ssam 3456444Swnj oob() 3466444Swnj { 34710839Ssam int out = 1+1, atmark; 3489365Ssam char waste[BUFSIZ], mark; 3496444Swnj 3509365Ssam ioctl(1, TIOCFLUSH, (char *)&out); 3516444Swnj for (;;) { 35210839Ssam if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 3536444Swnj perror("ioctl"); 3546444Swnj break; 3556444Swnj } 35610839Ssam if (atmark) 3576444Swnj break; 3589365Ssam (void) read(rem, waste, sizeof (waste)); 3596444Swnj } 36012990Ssam recv(rem, &mark, 1, MSG_OOB); 3616444Swnj if (mark & TIOCPKT_NOSTOP) { 36213075Ssam notc.t_stopc = -1; 36313075Ssam notc.t_startc = -1; 36413075Ssam ioctl(0, TIOCSETC, (char *)¬c); 3656444Swnj } 3666444Swnj if (mark & TIOCPKT_DOSTOP) { 36713075Ssam notc.t_stopc = deftc.t_stopc; 36813075Ssam notc.t_startc = deftc.t_startc; 36913075Ssam ioctl(0, TIOCSETC, (char *)¬c); 3706444Swnj } 3716444Swnj } 3726444Swnj 3739365Ssam /* 3749365Ssam * reader: read from remote: line -> 1 3759365Ssam */ 3769365Ssam reader() 3776444Swnj { 3789365Ssam char rb[BUFSIZ]; 3799365Ssam register int cnt; 3806444Swnj 38112990Ssam signal(SIGURG, oob); 3826444Swnj { int pid = -getpid(); 3839365Ssam ioctl(rem, SIOCSPGRP, (char *)&pid); } 3846444Swnj for (;;) { 3859365Ssam cnt = read(rem, rb, sizeof (rb)); 38611396Ssam if (cnt == 0) 38711396Ssam break; 38811396Ssam if (cnt < 0) { 3899365Ssam if (errno == EINTR) 3906444Swnj continue; 3916444Swnj break; 3926444Swnj } 3939365Ssam write(1, rb, cnt); 3946444Swnj } 3956444Swnj } 3966444Swnj 3976444Swnj mode(f) 3986444Swnj { 39913075Ssam struct tchars *tc; 40013075Ssam struct ltchars *ltc; 40113075Ssam struct sgttyb sb; 402*21583Sbloom int lflags; 4039365Ssam 40413075Ssam ioctl(0, TIOCGETP, (char *)&sb); 405*21583Sbloom ioctl(0, TIOCLGET, (char *)&lflags); 4069962Ssam switch (f) { 4079962Ssam 4089962Ssam case 0: 40913075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 41013075Ssam sb.sg_flags |= defflags|tabflag; 4119962Ssam tc = &deftc; 41213075Ssam ltc = &defltc; 41313075Ssam sb.sg_kill = defkill; 41413075Ssam sb.sg_erase = deferase; 415*21583Sbloom lflags = deflflags; 4169962Ssam break; 4179962Ssam 4189962Ssam case 1: 41913075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 42013075Ssam sb.sg_flags &= ~defflags; 42112155Ssam /* preserve tab delays, but turn off XTABS */ 42213075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 42313075Ssam sb.sg_flags &= ~TBDELAY; 4249962Ssam tc = ¬c; 42513075Ssam ltc = &noltc; 42613075Ssam sb.sg_kill = sb.sg_erase = -1; 427*21583Sbloom if (litout) 428*21583Sbloom lflags |= LLITOUT; 4299962Ssam break; 4309962Ssam 4319962Ssam default: 4329962Ssam return; 4336444Swnj } 43413075Ssam ioctl(0, TIOCSLTC, (char *)ltc); 43513075Ssam ioctl(0, TIOCSETC, (char *)tc); 43613075Ssam ioctl(0, TIOCSETN, (char *)&sb); 437*21583Sbloom ioctl(0, TIOCLSET, (char *)&lflags); 4386444Swnj } 4396444Swnj 4409365Ssam /*VARARGS*/ 4416444Swnj prf(f, a1, a2, a3) 4429365Ssam char *f; 4436444Swnj { 4446444Swnj fprintf(stderr, f, a1, a2, a3); 4456444Swnj fprintf(stderr, CRLF); 4466444Swnj } 4476444Swnj 4489365Ssam lostpeer() 4496444Swnj { 45012990Ssam signal(SIGPIPE, SIG_IGN); 45112155Ssam prf("\007Connection closed."); 4529365Ssam done(); 4536444Swnj } 454