16444Swnj #ifndef lint 2*18358Ssam static char sccsid[] = "@(#)rlogin.c 4.17 (Berkeley) 85/03/17"; 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> 20*18358Ssam #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; 286444Swnj char *speeds[] = 296444Swnj { "0", "50", "75", "110", "134", "150", "200", "300", 306444Swnj "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 31*18358Ssam char term[256] = "network"; 329365Ssam extern int errno; 339365Ssam int lostpeer(); 34*18358Ssam int nosigwin; 35*18358Ssam jmp_buf winsizechanged; 36*18358Ssam struct winsize winsize; 37*18358Ssam int sigwinch(); 386444Swnj 396444Swnj main(argc, argv) 406444Swnj int argc; 416444Swnj char **argv; 426444Swnj { 439365Ssam char *host, *cp; 446444Swnj struct sgttyb ttyb; 456444Swnj struct passwd *pwd; 469365Ssam struct servent *sp; 4710415Ssam int uid, options = 0; 4817449Slepreau int on = 1; 496444Swnj 506444Swnj host = rindex(argv[0], '/'); 516444Swnj if (host) 526444Swnj host++; 536444Swnj else 546444Swnj host = argv[0]; 556444Swnj argv++, --argc; 566444Swnj if (!strcmp(host, "rlogin")) 576444Swnj host = *argv++, --argc; 586444Swnj another: 5910839Ssam if (argc > 0 && !strcmp(*argv, "-d")) { 606444Swnj argv++, argc--; 6110415Ssam options |= SO_DEBUG; 626444Swnj goto another; 636444Swnj } 6410839Ssam if (argc > 0 && !strcmp(*argv, "-l")) { 656444Swnj argv++, argc--; 666444Swnj if (argc == 0) 676444Swnj goto usage; 686444Swnj name = *argv++; argc--; 696444Swnj goto another; 706444Swnj } 7110839Ssam if (argc > 0 && !strncmp(*argv, "-e", 2)) { 726444Swnj cmdchar = argv[0][2]; 736444Swnj argv++, argc--; 746444Swnj goto another; 756444Swnj } 7610839Ssam if (argc > 0 && !strcmp(*argv, "-8")) { 776444Swnj eight = 1; 786444Swnj argv++, argc--; 796444Swnj goto another; 806444Swnj } 81*18358Ssam if (argc > 0 && !strcmp(*argv, "-w")) { 82*18358Ssam nosigwin++; 83*18358Ssam argv++, argc--; 84*18358Ssam goto another; 85*18358Ssam } 866444Swnj if (host == 0) 876444Swnj goto usage; 886444Swnj if (argc > 0) 896444Swnj goto usage; 906444Swnj pwd = getpwuid(getuid()); 916444Swnj if (pwd == 0) { 926444Swnj fprintf(stderr, "Who are you?\n"); 936444Swnj exit(1); 946444Swnj } 959365Ssam sp = getservbyname("login", "tcp"); 969365Ssam if (sp == 0) { 979365Ssam fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 989365Ssam exit(2); 999365Ssam } 1009241Ssam cp = getenv("TERM"); 1019241Ssam if (cp) 1029241Ssam strcpy(term, cp); 103*18358Ssam if (ioctl(0, TIOCGETP, &ttyb) == 0) { 1046444Swnj strcat(term, "/"); 1056444Swnj strcat(term, speeds[ttyb.sg_ospeed]); 1066444Swnj } 107*18358Ssam if (!nosigwin && ioctl(0, TIOCGWINSZ, &winsize) == 0) { 108*18358Ssam cp = index(term, '\0'); 109*18358Ssam sprintf(cp, "/%u,%u,%u,%u", winsize.ws_row, winsize.ws_col, 110*18358Ssam winsize.ws_xpixel, winsize.ws_ypixel); 111*18358Ssam } 11212990Ssam signal(SIGPIPE, lostpeer); 1139365Ssam rem = rcmd(&host, sp->s_port, pwd->pw_name, 1146444Swnj name ? name : pwd->pw_name, term, 0); 1156444Swnj if (rem < 0) 1166444Swnj exit(1); 11710415Ssam if (options & SO_DEBUG && 11817449Slepreau setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) 11910415Ssam perror("rlogin: setsockopt (SO_DEBUG)"); 1209365Ssam uid = getuid(); 1219365Ssam if (setuid(uid) < 0) { 1229365Ssam perror("rlogin: setuid"); 1239365Ssam exit(1); 1249365Ssam } 1259365Ssam doit(); 1269365Ssam /*NOTREACHED*/ 1276444Swnj usage: 1286444Swnj fprintf(stderr, 12912155Ssam "usage: rlogin host [ -ex ] [ -l username ] [ -8 ]\n"); 1306444Swnj exit(1); 1316444Swnj } 1326444Swnj 1336444Swnj #define CRLF "\r\n" 1346444Swnj 1359365Ssam int child; 13611803Sedward int catchild(); 1379365Ssam 13813075Ssam int defflags, tabflag; 13913075Ssam char deferase, defkill; 14013075Ssam struct tchars deftc; 14113075Ssam struct ltchars defltc; 14213075Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 14313075Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 1446444Swnj 1459365Ssam doit() 1466444Swnj { 1476444Swnj int exit(); 14813075Ssam struct sgttyb sb; 1496444Swnj 15013075Ssam ioctl(0, TIOCGETP, (char *)&sb); 15113075Ssam defflags = sb.sg_flags; 15212155Ssam tabflag = defflags & TBDELAY; 1539962Ssam defflags &= ECHO | CRMOD; 15413075Ssam deferase = sb.sg_erase; 15513075Ssam defkill = sb.sg_kill; 15613075Ssam ioctl(0, TIOCGETC, (char *)&deftc); 15713075Ssam notc.t_startc = deftc.t_startc; 15813075Ssam notc.t_stopc = deftc.t_stopc; 15913075Ssam ioctl(0, TIOCGLTC, (char *)&defltc); 16012990Ssam signal(SIGINT, exit); 16112990Ssam signal(SIGHUP, exit); 16212990Ssam signal(SIGQUIT, exit); 1639365Ssam child = fork(); 1649365Ssam if (child == -1) { 1659365Ssam perror("rlogin: fork"); 1669365Ssam done(); 1679365Ssam } 16812990Ssam signal(SIGINT, SIG_IGN); 16911803Sedward mode(1); 1709365Ssam if (child == 0) { 1719365Ssam reader(); 17212155Ssam sleep(1); 17312155Ssam prf("\007Connection closed."); 1746444Swnj exit(3); 1756444Swnj } 17612990Ssam signal(SIGCHLD, catchild); 177*18358Ssam if (!nosigwin) 178*18358Ssam signal(SIGWINCH, sigwinch); 1799365Ssam writer(); 18012155Ssam prf("Closed connection."); 1816444Swnj done(); 1826444Swnj } 1836444Swnj 1846444Swnj done() 1856444Swnj { 1866444Swnj 1876444Swnj mode(0); 1889365Ssam if (child > 0 && kill(child, SIGKILL) >= 0) 1899365Ssam wait((int *)0); 1906444Swnj exit(0); 1916444Swnj } 1926444Swnj 19311803Sedward catchild() 19411803Sedward { 19511803Sedward union wait status; 19611803Sedward int pid; 19711803Sedward 19811803Sedward again: 19911803Sedward pid = wait3(&status, WNOHANG|WUNTRACED, 0); 20011803Sedward if (pid == 0) 20111803Sedward return; 20211803Sedward /* 20311803Sedward * if the child (reader) dies, just quit 20411803Sedward */ 20511803Sedward if (pid < 0 || pid == child && !WIFSTOPPED(status)) 20611803Sedward done(); 20711803Sedward goto again; 20811803Sedward } 20911803Sedward 2106444Swnj /* 2119365Ssam * writer: write to remote: 0 -> line. 2129365Ssam * ~. terminate 2139365Ssam * ~^Z suspend rlogin process. 21410415Ssam * ~^Y suspend rlogin process, but leave reader alone. 2156444Swnj */ 2169365Ssam writer() 2176444Swnj { 218*18358Ssam char obuf[600], c; 219*18358Ssam register char *op; 22011803Sedward register n; 2216444Swnj 222*18358Ssam /* 223*18358Ssam * Handle SIGWINCH's with in-band signaling of new 224*18358Ssam * window size. It seems reasonable that we flush 225*18358Ssam * pending input and not force out of band signal 226*18358Ssam * as this most likely will occur from an input device 227*18358Ssam * other than the keyboard (e.g. a mouse). 228*18358Ssam * 229*18358Ssam * The hack of using 0377 to signal an in-band signal 230*18358Ssam * is pretty bad, but otherwise we'd be forced to 231*18358Ssam * either get complicated (use MSG_OOB) or go to a 232*18358Ssam * serious (telnet-style) protocol. 233*18358Ssam */ 234*18358Ssam if (setjmp(winsizechanged)) { 235*18358Ssam struct winsize *wp = (struct winsize *)(obuf+4); 236*18358Ssam 237*18358Ssam obuf[0] = 0377; /* XXX */ 238*18358Ssam obuf[1] = 0377; /* XXX */ 239*18358Ssam obuf[2] = 's'; /* XXX */ 240*18358Ssam obuf[3] = 's'; /* XXX */ 241*18358Ssam wp->ws_row = htons(winsize.ws_row); 242*18358Ssam wp->ws_col = htons(winsize.ws_col); 243*18358Ssam wp->ws_xpixel = htons(winsize.ws_xpixel); 244*18358Ssam wp->ws_ypixel = htons(winsize.ws_ypixel); 245*18358Ssam (void) write(rem, obuf, 4+sizeof (*wp)); 246*18358Ssam } 2479365Ssam top: 248*18358Ssam op = obuf; 24911803Sedward for (;;) { 2509365Ssam int local; 2519365Ssam 25211803Sedward n = read(0, &c, 1); 253*18358Ssam if (n <= 0) { 254*18358Ssam if (n < 0 && errno == EINTR) 255*18358Ssam continue; 25611803Sedward break; 257*18358Ssam } 258*18358Ssam if (!eight) 2599365Ssam c &= 0177; 2609365Ssam /* 2619365Ssam * If we're at the beginning of the line 2629365Ssam * and recognize a command character, then 2639365Ssam * we echo locally. Otherwise, characters 2649365Ssam * are echo'd remotely. If the command 2659365Ssam * character is doubled, this acts as a 2669365Ssam * force and local echo is suppressed. 2679365Ssam */ 268*18358Ssam if (op == obuf) 2699365Ssam local = (c == cmdchar); 270*18358Ssam if (op == obuf + 1 && *obuf == cmdchar) 2719365Ssam local = (c != cmdchar); 2729365Ssam if (!local) { 2739365Ssam if (write(rem, &c, 1) == 0) { 2749365Ssam prf("line gone"); 2759365Ssam return; 2766444Swnj } 277*18358Ssam if (!eight) 2789365Ssam c &= 0177; 2799365Ssam } else { 2809365Ssam if (c == '\r' || c == '\n') { 281*18358Ssam char cmdc = obuf[1]; 2826444Swnj 28313075Ssam if (cmdc == '.' || cmdc == deftc.t_eofc) { 2849365Ssam write(0, CRLF, sizeof(CRLF)); 2859365Ssam return; 2869962Ssam } 28713075Ssam if (cmdc == defltc.t_suspc || 28813075Ssam cmdc == defltc.t_dsuspc) { 289*18358Ssam stop(cmdc); 2909365Ssam goto top; 2916444Swnj } 292*18358Ssam *op++ = c; 293*18358Ssam write(rem, obuf, op - obuf); 2949365Ssam goto top; 2956444Swnj } 2969365Ssam write(1, &c, 1); 2976444Swnj } 298*18358Ssam *op++ = c; 29913075Ssam if (c == deferase) { 300*18358Ssam op -= 2; 301*18358Ssam if (op < obuf) 3029365Ssam goto top; 3036444Swnj } 30413075Ssam if (c == defkill || c == deftc.t_eofc || 3059365Ssam c == '\r' || c == '\n') 3069365Ssam goto top; 307*18358Ssam if (op >= &obuf[sizeof (obuf)]) 308*18358Ssam op--; 3096444Swnj } 3106444Swnj } 3116444Swnj 312*18358Ssam stop(cmdc) 313*18358Ssam char cmdc; 314*18358Ssam { 315*18358Ssam struct winsize ws; 316*18358Ssam 317*18358Ssam write(0, CRLF, sizeof(CRLF)); 318*18358Ssam mode(0); 319*18358Ssam signal(SIGCHLD, SIG_IGN); 320*18358Ssam kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 321*18358Ssam signal(SIGCHLD, catchild); 322*18358Ssam mode(1); 323*18358Ssam sigwinch(); /* check for size changes */ 324*18358Ssam } 325*18358Ssam 326*18358Ssam sigwinch() 327*18358Ssam { 328*18358Ssam struct winsize ws; 329*18358Ssam 330*18358Ssam if (!nosigwin && ioctl(0, TIOCGWINSZ, &ws) == 0 && 331*18358Ssam bcmp(&ws, &winsize, sizeof (ws))) { 332*18358Ssam winsize = ws; 333*18358Ssam longjmp(winsizechanged, 1); 334*18358Ssam } 335*18358Ssam } 336*18358Ssam 3376444Swnj oob() 3386444Swnj { 33910839Ssam int out = 1+1, atmark; 3409365Ssam char waste[BUFSIZ], mark; 3416444Swnj 3429365Ssam ioctl(1, TIOCFLUSH, (char *)&out); 3436444Swnj for (;;) { 34410839Ssam if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 3456444Swnj perror("ioctl"); 3466444Swnj break; 3476444Swnj } 34810839Ssam if (atmark) 3496444Swnj break; 3509365Ssam (void) read(rem, waste, sizeof (waste)); 3516444Swnj } 35212990Ssam recv(rem, &mark, 1, MSG_OOB); 3536444Swnj if (mark & TIOCPKT_NOSTOP) { 35413075Ssam notc.t_stopc = -1; 35513075Ssam notc.t_startc = -1; 35613075Ssam ioctl(0, TIOCSETC, (char *)¬c); 3576444Swnj } 3586444Swnj if (mark & TIOCPKT_DOSTOP) { 35913075Ssam notc.t_stopc = deftc.t_stopc; 36013075Ssam notc.t_startc = deftc.t_startc; 36113075Ssam ioctl(0, TIOCSETC, (char *)¬c); 3626444Swnj } 3636444Swnj } 3646444Swnj 3659365Ssam /* 3669365Ssam * reader: read from remote: line -> 1 3679365Ssam */ 3689365Ssam reader() 3696444Swnj { 3709365Ssam char rb[BUFSIZ]; 3719365Ssam register int cnt; 3726444Swnj 37312990Ssam signal(SIGURG, oob); 3746444Swnj { int pid = -getpid(); 3759365Ssam ioctl(rem, SIOCSPGRP, (char *)&pid); } 3766444Swnj for (;;) { 3779365Ssam cnt = read(rem, rb, sizeof (rb)); 37811396Ssam if (cnt == 0) 37911396Ssam break; 38011396Ssam if (cnt < 0) { 3819365Ssam if (errno == EINTR) 3826444Swnj continue; 3836444Swnj break; 3846444Swnj } 3859365Ssam write(1, rb, cnt); 3866444Swnj } 3876444Swnj } 3886444Swnj 3896444Swnj mode(f) 3906444Swnj { 39113075Ssam struct tchars *tc; 39213075Ssam struct ltchars *ltc; 39313075Ssam struct sgttyb sb; 3949365Ssam 39513075Ssam ioctl(0, TIOCGETP, (char *)&sb); 3969962Ssam switch (f) { 3979962Ssam 3989962Ssam case 0: 39913075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 40013075Ssam sb.sg_flags |= defflags|tabflag; 4019962Ssam tc = &deftc; 40213075Ssam ltc = &defltc; 40313075Ssam sb.sg_kill = defkill; 40413075Ssam sb.sg_erase = deferase; 4059962Ssam break; 4069962Ssam 4079962Ssam case 1: 40813075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 40913075Ssam sb.sg_flags &= ~defflags; 41012155Ssam /* preserve tab delays, but turn off XTABS */ 41113075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 41213075Ssam sb.sg_flags &= ~TBDELAY; 4139962Ssam tc = ¬c; 41413075Ssam ltc = &noltc; 41513075Ssam sb.sg_kill = sb.sg_erase = -1; 4169962Ssam break; 4179962Ssam 4189962Ssam default: 4199962Ssam return; 4206444Swnj } 42113075Ssam ioctl(0, TIOCSLTC, (char *)ltc); 42213075Ssam ioctl(0, TIOCSETC, (char *)tc); 42313075Ssam ioctl(0, TIOCSETN, (char *)&sb); 4246444Swnj } 4256444Swnj 4269365Ssam /*VARARGS*/ 4276444Swnj prf(f, a1, a2, a3) 4289365Ssam char *f; 4296444Swnj { 4306444Swnj fprintf(stderr, f, a1, a2, a3); 4316444Swnj fprintf(stderr, CRLF); 4326444Swnj } 4336444Swnj 4349365Ssam lostpeer() 4356444Swnj { 43612990Ssam signal(SIGPIPE, SIG_IGN); 43712155Ssam prf("\007Connection closed."); 4389365Ssam done(); 4396444Swnj } 440