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*23530Sbloom static char sccsid[] = "@(#)rlogin.c 5.3 (Berkeley) 06/18/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> 3218358Ssam #include <setjmp.h> 336444Swnj 346444Swnj char *index(), *rindex(), *malloc(), *getenv(); 356444Swnj struct passwd *getpwuid(); 369365Ssam char *name; 376444Swnj int rem; 386444Swnj char cmdchar = '~'; 396444Swnj int eight; 4021583Sbloom int litout; 416444Swnj char *speeds[] = 426444Swnj { "0", "50", "75", "110", "134", "150", "200", "300", 436444Swnj "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 4418358Ssam char term[256] = "network"; 459365Ssam extern int errno; 469365Ssam int lostpeer(); 4718358Ssam int nosigwin; 4818358Ssam jmp_buf winsizechanged; 4918358Ssam struct winsize winsize; 5018358Ssam int sigwinch(); 516444Swnj 526444Swnj main(argc, argv) 536444Swnj int argc; 546444Swnj char **argv; 556444Swnj { 569365Ssam char *host, *cp; 576444Swnj struct sgttyb ttyb; 586444Swnj struct passwd *pwd; 599365Ssam struct servent *sp; 6010415Ssam int uid, options = 0; 6117449Slepreau int on = 1; 626444Swnj 636444Swnj host = rindex(argv[0], '/'); 646444Swnj if (host) 656444Swnj host++; 666444Swnj else 676444Swnj host = argv[0]; 686444Swnj argv++, --argc; 696444Swnj if (!strcmp(host, "rlogin")) 706444Swnj host = *argv++, --argc; 716444Swnj another: 7210839Ssam if (argc > 0 && !strcmp(*argv, "-d")) { 736444Swnj argv++, argc--; 7410415Ssam options |= SO_DEBUG; 756444Swnj goto another; 766444Swnj } 7710839Ssam if (argc > 0 && !strcmp(*argv, "-l")) { 786444Swnj argv++, argc--; 796444Swnj if (argc == 0) 806444Swnj goto usage; 816444Swnj name = *argv++; argc--; 826444Swnj goto another; 836444Swnj } 8410839Ssam if (argc > 0 && !strncmp(*argv, "-e", 2)) { 856444Swnj cmdchar = argv[0][2]; 866444Swnj argv++, argc--; 876444Swnj goto another; 886444Swnj } 8910839Ssam if (argc > 0 && !strcmp(*argv, "-8")) { 906444Swnj eight = 1; 916444Swnj argv++, argc--; 926444Swnj goto another; 936444Swnj } 9421583Sbloom if (argc > 0 && !strcmp(*argv, "-L")) { 9521583Sbloom litout = 1; 9621583Sbloom argv++, argc--; 9721583Sbloom goto another; 9821583Sbloom } 9918358Ssam if (argc > 0 && !strcmp(*argv, "-w")) { 10018358Ssam nosigwin++; 10118358Ssam argv++, argc--; 10218358Ssam goto another; 10318358Ssam } 1046444Swnj if (host == 0) 1056444Swnj goto usage; 1066444Swnj if (argc > 0) 1076444Swnj goto usage; 1086444Swnj pwd = getpwuid(getuid()); 1096444Swnj if (pwd == 0) { 1106444Swnj fprintf(stderr, "Who are you?\n"); 1116444Swnj exit(1); 1126444Swnj } 1139365Ssam sp = getservbyname("login", "tcp"); 1149365Ssam if (sp == 0) { 1159365Ssam fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 1169365Ssam exit(2); 1179365Ssam } 1189241Ssam cp = getenv("TERM"); 1199241Ssam if (cp) 1209241Ssam strcpy(term, cp); 12118358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 1226444Swnj strcat(term, "/"); 1236444Swnj strcat(term, speeds[ttyb.sg_ospeed]); 1246444Swnj } 12518358Ssam if (!nosigwin && ioctl(0, TIOCGWINSZ, &winsize) == 0) { 12618358Ssam cp = index(term, '\0'); 12718358Ssam sprintf(cp, "/%u,%u,%u,%u", winsize.ws_row, winsize.ws_col, 12818358Ssam winsize.ws_xpixel, winsize.ws_ypixel); 12918358Ssam } 13012990Ssam signal(SIGPIPE, lostpeer); 1319365Ssam rem = rcmd(&host, sp->s_port, pwd->pw_name, 1326444Swnj name ? name : pwd->pw_name, term, 0); 1336444Swnj if (rem < 0) 1346444Swnj exit(1); 13510415Ssam if (options & SO_DEBUG && 13617449Slepreau setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) 13710415Ssam perror("rlogin: setsockopt (SO_DEBUG)"); 1389365Ssam uid = getuid(); 1399365Ssam if (setuid(uid) < 0) { 1409365Ssam perror("rlogin: setuid"); 1419365Ssam exit(1); 1429365Ssam } 1439365Ssam doit(); 1449365Ssam /*NOTREACHED*/ 1456444Swnj usage: 1466444Swnj fprintf(stderr, 14721583Sbloom "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -w ]\n"); 1486444Swnj exit(1); 1496444Swnj } 1506444Swnj 1516444Swnj #define CRLF "\r\n" 1526444Swnj 1539365Ssam int child; 15411803Sedward int catchild(); 1559365Ssam 15613075Ssam int defflags, tabflag; 15721583Sbloom int deflflags; 15813075Ssam char deferase, defkill; 15913075Ssam struct tchars deftc; 16013075Ssam struct ltchars defltc; 16113075Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 16213075Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 1636444Swnj 1649365Ssam doit() 1656444Swnj { 1666444Swnj int exit(); 16713075Ssam struct sgttyb sb; 1686444Swnj 16913075Ssam ioctl(0, TIOCGETP, (char *)&sb); 17013075Ssam defflags = sb.sg_flags; 17112155Ssam tabflag = defflags & TBDELAY; 1729962Ssam defflags &= ECHO | CRMOD; 17313075Ssam deferase = sb.sg_erase; 17413075Ssam defkill = sb.sg_kill; 17521583Sbloom ioctl(0, TIOCLGET, (char *)&deflflags); 17613075Ssam ioctl(0, TIOCGETC, (char *)&deftc); 17713075Ssam notc.t_startc = deftc.t_startc; 17813075Ssam notc.t_stopc = deftc.t_stopc; 17913075Ssam ioctl(0, TIOCGLTC, (char *)&defltc); 18012990Ssam signal(SIGINT, exit); 18112990Ssam signal(SIGHUP, exit); 18212990Ssam signal(SIGQUIT, exit); 1839365Ssam child = fork(); 1849365Ssam if (child == -1) { 1859365Ssam perror("rlogin: fork"); 1869365Ssam done(); 1879365Ssam } 18812990Ssam signal(SIGINT, SIG_IGN); 18911803Sedward mode(1); 1909365Ssam if (child == 0) { 1919365Ssam reader(); 19212155Ssam sleep(1); 19312155Ssam prf("\007Connection closed."); 1946444Swnj exit(3); 1956444Swnj } 19612990Ssam signal(SIGCHLD, catchild); 19718358Ssam if (!nosigwin) 19818358Ssam signal(SIGWINCH, sigwinch); 1999365Ssam writer(); 20012155Ssam prf("Closed connection."); 2016444Swnj done(); 2026444Swnj } 2036444Swnj 2046444Swnj done() 2056444Swnj { 2066444Swnj 2076444Swnj mode(0); 2089365Ssam if (child > 0 && kill(child, SIGKILL) >= 0) 2099365Ssam wait((int *)0); 2106444Swnj exit(0); 2116444Swnj } 2126444Swnj 21311803Sedward catchild() 21411803Sedward { 21511803Sedward union wait status; 21611803Sedward int pid; 21711803Sedward 21811803Sedward again: 21911803Sedward pid = wait3(&status, WNOHANG|WUNTRACED, 0); 22011803Sedward if (pid == 0) 22111803Sedward return; 22211803Sedward /* 22311803Sedward * if the child (reader) dies, just quit 22411803Sedward */ 22511803Sedward if (pid < 0 || pid == child && !WIFSTOPPED(status)) 22611803Sedward done(); 22711803Sedward goto again; 22811803Sedward } 22911803Sedward 2306444Swnj /* 2319365Ssam * writer: write to remote: 0 -> line. 2329365Ssam * ~. terminate 2339365Ssam * ~^Z suspend rlogin process. 23410415Ssam * ~^Y suspend rlogin process, but leave reader alone. 2356444Swnj */ 2369365Ssam writer() 2376444Swnj { 238*23530Sbloom char c; 23911803Sedward register n; 240*23530Sbloom register bol = 1; /* beginning of line */ 241*23530Sbloom register local = 0; 2426444Swnj 24318358Ssam /* 24418358Ssam * Handle SIGWINCH's with in-band signaling of new 24518358Ssam * window size. It seems reasonable that we flush 24618358Ssam * pending input and not force out of band signal 24718358Ssam * as this most likely will occur from an input device 24818358Ssam * other than the keyboard (e.g. a mouse). 24918358Ssam * 25018358Ssam * The hack of using 0377 to signal an in-band signal 25118358Ssam * is pretty bad, but otherwise we'd be forced to 25218358Ssam * either get complicated (use MSG_OOB) or go to a 25318358Ssam * serious (telnet-style) protocol. 25418358Ssam */ 25518358Ssam if (setjmp(winsizechanged)) { 256*23530Sbloom char obuf[4 + sizeof (struct winsize)]; 25718358Ssam struct winsize *wp = (struct winsize *)(obuf+4); 25818358Ssam 25918358Ssam obuf[0] = 0377; /* XXX */ 26018358Ssam obuf[1] = 0377; /* XXX */ 26118358Ssam obuf[2] = 's'; /* XXX */ 26218358Ssam obuf[3] = 's'; /* XXX */ 26318358Ssam wp->ws_row = htons(winsize.ws_row); 26418358Ssam wp->ws_col = htons(winsize.ws_col); 26518358Ssam wp->ws_xpixel = htons(winsize.ws_xpixel); 26618358Ssam wp->ws_ypixel = htons(winsize.ws_ypixel); 26718358Ssam (void) write(rem, obuf, 4+sizeof (*wp)); 26818358Ssam } 269*23530Sbloom 27011803Sedward for (;;) { 27111803Sedward n = read(0, &c, 1); 27218358Ssam if (n <= 0) { 27318358Ssam if (n < 0 && errno == EINTR) 27418358Ssam continue; 27511803Sedward break; 27618358Ssam } 27718358Ssam if (!eight) 2789365Ssam c &= 0177; 2799365Ssam /* 2809365Ssam * If we're at the beginning of the line 2819365Ssam * and recognize a command character, then 2829365Ssam * we echo locally. Otherwise, characters 2839365Ssam * are echo'd remotely. If the command 2849365Ssam * character is doubled, this acts as a 2859365Ssam * force and local echo is suppressed. 2869365Ssam */ 287*23530Sbloom if (bol) { 288*23530Sbloom bol = 0; 289*23530Sbloom if (c == cmdchar) { 290*23530Sbloom bol = 0; 291*23530Sbloom local = 1; 292*23530Sbloom continue; 2936444Swnj } 294*23530Sbloom } else if (local) { 295*23530Sbloom local = 0; 296*23530Sbloom if (c == '.' || c == deftc.t_eofc) { 297*23530Sbloom echo(c); 298*23530Sbloom break; 2996444Swnj } 300*23530Sbloom if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 301*23530Sbloom bol = 1; 302*23530Sbloom echo(c); 303*23530Sbloom stop(c); 304*23530Sbloom continue; 305*23530Sbloom } 306*23530Sbloom if (c != cmdchar) 307*23530Sbloom write(rem, &cmdchar, 1); 3086444Swnj } 309*23530Sbloom if (write(rem, &c, 1) == 0) { 310*23530Sbloom prf("line gone"); 311*23530Sbloom break; 3126444Swnj } 313*23530Sbloom bol = c == defkill || c == deftc.t_eofc || 314*23530Sbloom c == '\r' || c == '\n'; 3156444Swnj } 3166444Swnj } 3176444Swnj 318*23530Sbloom echo(c) 319*23530Sbloom register char c; 320*23530Sbloom { 321*23530Sbloom char buf[8]; 322*23530Sbloom register char *p = buf; 323*23530Sbloom 324*23530Sbloom c &= 0177; 325*23530Sbloom *p++ = cmdchar; 326*23530Sbloom if (c < ' ') { 327*23530Sbloom *p++ = '^'; 328*23530Sbloom *p++ = c + '@'; 329*23530Sbloom } else if (c == 0177) { 330*23530Sbloom *p++ = '^'; 331*23530Sbloom *p++ = '?'; 332*23530Sbloom } else 333*23530Sbloom *p++ = c; 334*23530Sbloom *p++ = '\r'; 335*23530Sbloom *p++ = '\n'; 336*23530Sbloom write(1, buf, p - buf); 337*23530Sbloom } 338*23530Sbloom 33918358Ssam stop(cmdc) 34018358Ssam char cmdc; 34118358Ssam { 34218358Ssam struct winsize ws; 34318358Ssam 34418358Ssam mode(0); 34518358Ssam signal(SIGCHLD, SIG_IGN); 34618358Ssam kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 34718358Ssam signal(SIGCHLD, catchild); 34818358Ssam mode(1); 34918358Ssam sigwinch(); /* check for size changes */ 35018358Ssam } 35118358Ssam 35218358Ssam sigwinch() 35318358Ssam { 35418358Ssam struct winsize ws; 35518358Ssam 35618358Ssam if (!nosigwin && ioctl(0, TIOCGWINSZ, &ws) == 0 && 35718358Ssam bcmp(&ws, &winsize, sizeof (ws))) { 35818358Ssam winsize = ws; 35918358Ssam longjmp(winsizechanged, 1); 36018358Ssam } 36118358Ssam } 36218358Ssam 3636444Swnj oob() 3646444Swnj { 36510839Ssam int out = 1+1, atmark; 3669365Ssam char waste[BUFSIZ], mark; 3676444Swnj 3689365Ssam ioctl(1, TIOCFLUSH, (char *)&out); 3696444Swnj for (;;) { 37010839Ssam if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 3716444Swnj perror("ioctl"); 3726444Swnj break; 3736444Swnj } 37410839Ssam if (atmark) 3756444Swnj break; 37623230Sbloom if (read(rem, waste, sizeof (waste)) <= 0) 37723230Sbloom break; 3786444Swnj } 37912990Ssam recv(rem, &mark, 1, MSG_OOB); 3806444Swnj if (mark & TIOCPKT_NOSTOP) { 38113075Ssam notc.t_stopc = -1; 38213075Ssam notc.t_startc = -1; 38313075Ssam ioctl(0, TIOCSETC, (char *)¬c); 3846444Swnj } 3856444Swnj if (mark & TIOCPKT_DOSTOP) { 38613075Ssam notc.t_stopc = deftc.t_stopc; 38713075Ssam notc.t_startc = deftc.t_startc; 38813075Ssam ioctl(0, TIOCSETC, (char *)¬c); 3896444Swnj } 3906444Swnj } 3916444Swnj 3929365Ssam /* 3939365Ssam * reader: read from remote: line -> 1 3949365Ssam */ 3959365Ssam reader() 3966444Swnj { 3979365Ssam char rb[BUFSIZ]; 3989365Ssam register int cnt; 3996444Swnj 40012990Ssam signal(SIGURG, oob); 401*23530Sbloom signal(SIGTTOU, SIG_IGN); 4026444Swnj { int pid = -getpid(); 4039365Ssam ioctl(rem, SIOCSPGRP, (char *)&pid); } 4046444Swnj for (;;) { 4059365Ssam cnt = read(rem, rb, sizeof (rb)); 40611396Ssam if (cnt == 0) 40711396Ssam break; 40811396Ssam if (cnt < 0) { 4099365Ssam if (errno == EINTR) 4106444Swnj continue; 4116444Swnj break; 4126444Swnj } 4139365Ssam write(1, rb, cnt); 4146444Swnj } 4156444Swnj } 4166444Swnj 4176444Swnj mode(f) 4186444Swnj { 41913075Ssam struct tchars *tc; 42013075Ssam struct ltchars *ltc; 42113075Ssam struct sgttyb sb; 42221583Sbloom int lflags; 4239365Ssam 42413075Ssam ioctl(0, TIOCGETP, (char *)&sb); 42521583Sbloom ioctl(0, TIOCLGET, (char *)&lflags); 4269962Ssam switch (f) { 4279962Ssam 4289962Ssam case 0: 42913075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 43013075Ssam sb.sg_flags |= defflags|tabflag; 4319962Ssam tc = &deftc; 43213075Ssam ltc = &defltc; 43313075Ssam sb.sg_kill = defkill; 43413075Ssam sb.sg_erase = deferase; 43521583Sbloom lflags = deflflags; 4369962Ssam break; 4379962Ssam 4389962Ssam case 1: 43913075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 44013075Ssam sb.sg_flags &= ~defflags; 44112155Ssam /* preserve tab delays, but turn off XTABS */ 44213075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 44313075Ssam sb.sg_flags &= ~TBDELAY; 4449962Ssam tc = ¬c; 44513075Ssam ltc = &noltc; 44613075Ssam sb.sg_kill = sb.sg_erase = -1; 44721583Sbloom if (litout) 44821583Sbloom lflags |= LLITOUT; 4499962Ssam break; 4509962Ssam 4519962Ssam default: 4529962Ssam return; 4536444Swnj } 45413075Ssam ioctl(0, TIOCSLTC, (char *)ltc); 45513075Ssam ioctl(0, TIOCSETC, (char *)tc); 45613075Ssam ioctl(0, TIOCSETN, (char *)&sb); 45721583Sbloom ioctl(0, TIOCLSET, (char *)&lflags); 4586444Swnj } 4596444Swnj 4609365Ssam /*VARARGS*/ 4616444Swnj prf(f, a1, a2, a3) 4629365Ssam char *f; 4636444Swnj { 4646444Swnj fprintf(stderr, f, a1, a2, a3); 4656444Swnj fprintf(stderr, CRLF); 4666444Swnj } 4676444Swnj 4689365Ssam lostpeer() 4696444Swnj { 47012990Ssam signal(SIGPIPE, SIG_IGN); 47112155Ssam prf("\007Connection closed."); 4729365Ssam done(); 4736444Swnj } 474