16444Swnj #ifndef lint 2*13075Ssam static char sccsid[] = "@(#)rlogin.c 4.14 83/06/13"; 36444Swnj #endif 46444Swnj 512990Ssam /* 612990Ssam * rlogin - remote login 712990Ssam */ 86444Swnj #include <sys/types.h> 96444Swnj #include <sys/socket.h> 109365Ssam 119207Ssam #include <netinet/in.h> 129365Ssam 139365Ssam #include <stdio.h> 149365Ssam #include <sgtty.h> 156444Swnj #include <errno.h> 166444Swnj #include <pwd.h> 179365Ssam #include <signal.h> 189365Ssam #include <netdb.h> 1911803Sedward #include <wait.h> 206444Swnj 216444Swnj char *index(), *rindex(), *malloc(), *getenv(); 226444Swnj struct passwd *getpwuid(); 239365Ssam char *name; 246444Swnj int rem; 256444Swnj char cmdchar = '~'; 266444Swnj int eight; 276444Swnj char *speeds[] = 286444Swnj { "0", "50", "75", "110", "134", "150", "200", "300", 296444Swnj "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 309365Ssam char term[64] = "network"; 319365Ssam extern int errno; 329365Ssam int lostpeer(); 336444Swnj 346444Swnj main(argc, argv) 356444Swnj int argc; 366444Swnj char **argv; 376444Swnj { 389365Ssam char *host, *cp; 396444Swnj struct sgttyb ttyb; 406444Swnj struct passwd *pwd; 419365Ssam struct servent *sp; 4210415Ssam int uid, options = 0; 436444Swnj 446444Swnj host = rindex(argv[0], '/'); 456444Swnj if (host) 466444Swnj host++; 476444Swnj else 486444Swnj host = argv[0]; 496444Swnj argv++, --argc; 506444Swnj if (!strcmp(host, "rlogin")) 516444Swnj host = *argv++, --argc; 526444Swnj another: 5310839Ssam if (argc > 0 && !strcmp(*argv, "-d")) { 546444Swnj argv++, argc--; 5510415Ssam options |= SO_DEBUG; 566444Swnj goto another; 576444Swnj } 5810839Ssam if (argc > 0 && !strcmp(*argv, "-l")) { 596444Swnj argv++, argc--; 606444Swnj if (argc == 0) 616444Swnj goto usage; 626444Swnj name = *argv++; argc--; 636444Swnj goto another; 646444Swnj } 6510839Ssam if (argc > 0 && !strncmp(*argv, "-e", 2)) { 666444Swnj cmdchar = argv[0][2]; 676444Swnj argv++, argc--; 686444Swnj goto another; 696444Swnj } 7010839Ssam if (argc > 0 && !strcmp(*argv, "-8")) { 716444Swnj eight = 1; 726444Swnj argv++, argc--; 736444Swnj goto another; 746444Swnj } 756444Swnj if (host == 0) 766444Swnj goto usage; 776444Swnj if (argc > 0) 786444Swnj goto usage; 796444Swnj pwd = getpwuid(getuid()); 806444Swnj if (pwd == 0) { 816444Swnj fprintf(stderr, "Who are you?\n"); 826444Swnj exit(1); 836444Swnj } 849365Ssam sp = getservbyname("login", "tcp"); 859365Ssam if (sp == 0) { 869365Ssam fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 879365Ssam exit(2); 889365Ssam } 899241Ssam cp = getenv("TERM"); 909241Ssam if (cp) 919241Ssam strcpy(term, cp); 929962Ssam if (ioctl(0, TIOCGETP, &ttyb)==0) { 936444Swnj strcat(term, "/"); 946444Swnj strcat(term, speeds[ttyb.sg_ospeed]); 956444Swnj } 9612990Ssam signal(SIGPIPE, lostpeer); 979365Ssam rem = rcmd(&host, sp->s_port, pwd->pw_name, 986444Swnj name ? name : pwd->pw_name, term, 0); 996444Swnj if (rem < 0) 1006444Swnj exit(1); 10110415Ssam if (options & SO_DEBUG && 10210415Ssam setsockopt(rem, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 10310415Ssam perror("rlogin: setsockopt (SO_DEBUG)"); 1049365Ssam uid = getuid(); 1059365Ssam if (setuid(uid) < 0) { 1069365Ssam perror("rlogin: setuid"); 1079365Ssam exit(1); 1089365Ssam } 1099365Ssam doit(); 1109365Ssam /*NOTREACHED*/ 1116444Swnj usage: 1126444Swnj fprintf(stderr, 11312155Ssam "usage: rlogin host [ -ex ] [ -l username ] [ -8 ]\n"); 1146444Swnj exit(1); 1156444Swnj } 1166444Swnj 1176444Swnj #define CRLF "\r\n" 1186444Swnj 1199365Ssam int child; 12011803Sedward int catchild(); 1219365Ssam 122*13075Ssam int defflags, tabflag; 123*13075Ssam char deferase, defkill; 124*13075Ssam struct tchars deftc; 125*13075Ssam struct ltchars defltc; 126*13075Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 127*13075Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 1286444Swnj 1299365Ssam doit() 1306444Swnj { 1316444Swnj int exit(); 132*13075Ssam struct sgttyb sb; 1336444Swnj 134*13075Ssam ioctl(0, TIOCGETP, (char *)&sb); 135*13075Ssam defflags = sb.sg_flags; 13612155Ssam tabflag = defflags & TBDELAY; 1379962Ssam defflags &= ECHO | CRMOD; 138*13075Ssam deferase = sb.sg_erase; 139*13075Ssam defkill = sb.sg_kill; 140*13075Ssam ioctl(0, TIOCGETC, (char *)&deftc); 141*13075Ssam notc.t_startc = deftc.t_startc; 142*13075Ssam notc.t_stopc = deftc.t_stopc; 143*13075Ssam ioctl(0, TIOCGLTC, (char *)&defltc); 14412990Ssam signal(SIGINT, exit); 14512990Ssam signal(SIGHUP, exit); 14612990Ssam signal(SIGQUIT, exit); 1479365Ssam child = fork(); 1489365Ssam if (child == -1) { 1499365Ssam perror("rlogin: fork"); 1509365Ssam done(); 1519365Ssam } 15212990Ssam signal(SIGINT, SIG_IGN); 15311803Sedward mode(1); 1549365Ssam if (child == 0) { 1559365Ssam reader(); 15612155Ssam sleep(1); 15712155Ssam prf("\007Connection closed."); 1586444Swnj exit(3); 1596444Swnj } 16012990Ssam signal(SIGCHLD, catchild); 1619365Ssam writer(); 16212155Ssam prf("Closed connection."); 1636444Swnj done(); 1646444Swnj } 1656444Swnj 1666444Swnj done() 1676444Swnj { 1686444Swnj 1696444Swnj mode(0); 1709365Ssam if (child > 0 && kill(child, SIGKILL) >= 0) 1719365Ssam wait((int *)0); 1726444Swnj exit(0); 1736444Swnj } 1746444Swnj 17511803Sedward catchild() 17611803Sedward { 17711803Sedward union wait status; 17811803Sedward int pid; 17911803Sedward 18011803Sedward again: 18111803Sedward pid = wait3(&status, WNOHANG|WUNTRACED, 0); 18211803Sedward if (pid == 0) 18311803Sedward return; 18411803Sedward /* 18511803Sedward * if the child (reader) dies, just quit 18611803Sedward */ 18711803Sedward if (pid < 0 || pid == child && !WIFSTOPPED(status)) 18811803Sedward done(); 18911803Sedward goto again; 19011803Sedward } 19111803Sedward 1926444Swnj /* 1939365Ssam * writer: write to remote: 0 -> line. 1949365Ssam * ~. terminate 1959365Ssam * ~^Z suspend rlogin process. 19610415Ssam * ~^Y suspend rlogin process, but leave reader alone. 1976444Swnj */ 1989365Ssam writer() 1996444Swnj { 2009365Ssam char b[600], c; 2019365Ssam register char *p; 20211803Sedward register n; 2036444Swnj 2049365Ssam top: 2059365Ssam p = b; 20611803Sedward for (;;) { 2079365Ssam int local; 2089365Ssam 20911803Sedward n = read(0, &c, 1); 21011803Sedward if (n == 0) 21111803Sedward break; 21211803Sedward if (n < 0) 21311803Sedward if (errno == EINTR) 21411803Sedward continue; 21511803Sedward else 21611803Sedward break; 21711803Sedward 2189365Ssam if (eight == 0) 2199365Ssam c &= 0177; 2209365Ssam /* 2219365Ssam * If we're at the beginning of the line 2229365Ssam * and recognize a command character, then 2239365Ssam * we echo locally. Otherwise, characters 2249365Ssam * are echo'd remotely. If the command 2259365Ssam * character is doubled, this acts as a 2269365Ssam * force and local echo is suppressed. 2279365Ssam */ 2289365Ssam if (p == b) 2299365Ssam local = (c == cmdchar); 2309365Ssam if (p == b + 1 && *b == cmdchar) 2319365Ssam local = (c != cmdchar); 2329365Ssam if (!local) { 2339365Ssam if (write(rem, &c, 1) == 0) { 2349365Ssam prf("line gone"); 2359365Ssam return; 2366444Swnj } 2379365Ssam if (eight == 0) 2389365Ssam c &= 0177; 2399365Ssam } else { 2409365Ssam if (c == '\r' || c == '\n') { 2419962Ssam char cmdc = b[1]; 2426444Swnj 243*13075Ssam if (cmdc == '.' || cmdc == deftc.t_eofc) { 2449365Ssam write(0, CRLF, sizeof(CRLF)); 2459365Ssam return; 2469962Ssam } 247*13075Ssam if (cmdc == defltc.t_suspc || 248*13075Ssam cmdc == defltc.t_dsuspc) { 2499365Ssam write(0, CRLF, sizeof(CRLF)); 2509365Ssam mode(0); 25112990Ssam signal(SIGCHLD, SIG_IGN); 252*13075Ssam kill(cmdc == defltc.t_suspc ? 2539962Ssam 0 : getpid(), SIGTSTP); 25412990Ssam signal(SIGCHLD, catchild); 2559365Ssam mode(1); 2569365Ssam goto top; 2576444Swnj } 2589365Ssam *p++ = c; 2599365Ssam write(rem, b, p - b); 2609365Ssam goto top; 2616444Swnj } 2629365Ssam write(1, &c, 1); 2636444Swnj } 2649365Ssam *p++ = c; 265*13075Ssam if (c == deferase) { 2669365Ssam p -= 2; 2679365Ssam if (p < b) 2689365Ssam goto top; 2696444Swnj } 270*13075Ssam if (c == defkill || c == deftc.t_eofc || 2719365Ssam c == '\r' || c == '\n') 2729365Ssam goto top; 27311803Sedward if (p >= &b[sizeof b]) 27411803Sedward p--; 2756444Swnj } 2766444Swnj } 2776444Swnj 2786444Swnj oob() 2796444Swnj { 28010839Ssam int out = 1+1, atmark; 2819365Ssam char waste[BUFSIZ], mark; 2826444Swnj 2839365Ssam ioctl(1, TIOCFLUSH, (char *)&out); 2846444Swnj for (;;) { 28510839Ssam if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 2866444Swnj perror("ioctl"); 2876444Swnj break; 2886444Swnj } 28910839Ssam if (atmark) 2906444Swnj break; 2919365Ssam (void) read(rem, waste, sizeof (waste)); 2926444Swnj } 29312990Ssam recv(rem, &mark, 1, MSG_OOB); 2946444Swnj if (mark & TIOCPKT_NOSTOP) { 295*13075Ssam notc.t_stopc = -1; 296*13075Ssam notc.t_startc = -1; 297*13075Ssam ioctl(0, TIOCSETC, (char *)¬c); 2986444Swnj } 2996444Swnj if (mark & TIOCPKT_DOSTOP) { 300*13075Ssam notc.t_stopc = deftc.t_stopc; 301*13075Ssam notc.t_startc = deftc.t_startc; 302*13075Ssam ioctl(0, TIOCSETC, (char *)¬c); 3036444Swnj } 3046444Swnj } 3056444Swnj 3069365Ssam /* 3079365Ssam * reader: read from remote: line -> 1 3089365Ssam */ 3099365Ssam reader() 3106444Swnj { 3119365Ssam char rb[BUFSIZ]; 3129365Ssam register int cnt; 3136444Swnj 31412990Ssam signal(SIGURG, oob); 3156444Swnj { int pid = -getpid(); 3169365Ssam ioctl(rem, SIOCSPGRP, (char *)&pid); } 3176444Swnj for (;;) { 3189365Ssam cnt = read(rem, rb, sizeof (rb)); 31911396Ssam if (cnt == 0) 32011396Ssam break; 32111396Ssam if (cnt < 0) { 3229365Ssam if (errno == EINTR) 3236444Swnj continue; 3246444Swnj break; 3256444Swnj } 3269365Ssam write(1, rb, cnt); 3276444Swnj } 3286444Swnj } 3296444Swnj 3306444Swnj mode(f) 3316444Swnj { 332*13075Ssam struct tchars *tc; 333*13075Ssam struct ltchars *ltc; 334*13075Ssam struct sgttyb sb; 3359365Ssam 336*13075Ssam ioctl(0, TIOCGETP, (char *)&sb); 3379962Ssam switch (f) { 3389962Ssam 3399962Ssam case 0: 340*13075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 341*13075Ssam sb.sg_flags |= defflags|tabflag; 3429962Ssam tc = &deftc; 343*13075Ssam ltc = &defltc; 344*13075Ssam sb.sg_kill = defkill; 345*13075Ssam sb.sg_erase = deferase; 3469962Ssam break; 3479962Ssam 3489962Ssam case 1: 349*13075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 350*13075Ssam sb.sg_flags &= ~defflags; 35112155Ssam /* preserve tab delays, but turn off XTABS */ 352*13075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 353*13075Ssam sb.sg_flags &= ~TBDELAY; 3549962Ssam tc = ¬c; 355*13075Ssam ltc = &noltc; 356*13075Ssam sb.sg_kill = sb.sg_erase = -1; 3579962Ssam break; 3589962Ssam 3599962Ssam default: 3609962Ssam return; 3616444Swnj } 362*13075Ssam ioctl(0, TIOCSLTC, (char *)ltc); 363*13075Ssam ioctl(0, TIOCSETC, (char *)tc); 364*13075Ssam ioctl(0, TIOCSETN, (char *)&sb); 3656444Swnj } 3666444Swnj 3679365Ssam /*VARARGS*/ 3686444Swnj prf(f, a1, a2, a3) 3699365Ssam char *f; 3706444Swnj { 3716444Swnj fprintf(stderr, f, a1, a2, a3); 3726444Swnj fprintf(stderr, CRLF); 3736444Swnj } 3746444Swnj 3759365Ssam lostpeer() 3766444Swnj { 37712990Ssam signal(SIGPIPE, SIG_IGN); 37812155Ssam prf("\007Connection closed."); 3799365Ssam done(); 3806444Swnj } 381