16444Swnj #ifndef lint 2*17449Slepreau static char sccsid[] = "@(#)rlogin.c 4.16 (Berkeley) 84/12/03"; 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> 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; 43*17449Slepreau int on = 1; 446444Swnj 456444Swnj host = rindex(argv[0], '/'); 466444Swnj if (host) 476444Swnj host++; 486444Swnj else 496444Swnj host = argv[0]; 506444Swnj argv++, --argc; 516444Swnj if (!strcmp(host, "rlogin")) 526444Swnj host = *argv++, --argc; 536444Swnj another: 5410839Ssam if (argc > 0 && !strcmp(*argv, "-d")) { 556444Swnj argv++, argc--; 5610415Ssam options |= SO_DEBUG; 576444Swnj goto another; 586444Swnj } 5910839Ssam if (argc > 0 && !strcmp(*argv, "-l")) { 606444Swnj argv++, argc--; 616444Swnj if (argc == 0) 626444Swnj goto usage; 636444Swnj name = *argv++; argc--; 646444Swnj goto another; 656444Swnj } 6610839Ssam if (argc > 0 && !strncmp(*argv, "-e", 2)) { 676444Swnj cmdchar = argv[0][2]; 686444Swnj argv++, argc--; 696444Swnj goto another; 706444Swnj } 7110839Ssam if (argc > 0 && !strcmp(*argv, "-8")) { 726444Swnj eight = 1; 736444Swnj argv++, argc--; 746444Swnj goto another; 756444Swnj } 766444Swnj if (host == 0) 776444Swnj goto usage; 786444Swnj if (argc > 0) 796444Swnj goto usage; 806444Swnj pwd = getpwuid(getuid()); 816444Swnj if (pwd == 0) { 826444Swnj fprintf(stderr, "Who are you?\n"); 836444Swnj exit(1); 846444Swnj } 859365Ssam sp = getservbyname("login", "tcp"); 869365Ssam if (sp == 0) { 879365Ssam fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 889365Ssam exit(2); 899365Ssam } 909241Ssam cp = getenv("TERM"); 919241Ssam if (cp) 929241Ssam strcpy(term, cp); 939962Ssam if (ioctl(0, TIOCGETP, &ttyb)==0) { 946444Swnj strcat(term, "/"); 956444Swnj strcat(term, speeds[ttyb.sg_ospeed]); 966444Swnj } 9712990Ssam signal(SIGPIPE, lostpeer); 989365Ssam rem = rcmd(&host, sp->s_port, pwd->pw_name, 996444Swnj name ? name : pwd->pw_name, term, 0); 1006444Swnj if (rem < 0) 1016444Swnj exit(1); 10210415Ssam if (options & SO_DEBUG && 103*17449Slepreau setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) 10410415Ssam perror("rlogin: setsockopt (SO_DEBUG)"); 1059365Ssam uid = getuid(); 1069365Ssam if (setuid(uid) < 0) { 1079365Ssam perror("rlogin: setuid"); 1089365Ssam exit(1); 1099365Ssam } 1109365Ssam doit(); 1119365Ssam /*NOTREACHED*/ 1126444Swnj usage: 1136444Swnj fprintf(stderr, 11412155Ssam "usage: rlogin host [ -ex ] [ -l username ] [ -8 ]\n"); 1156444Swnj exit(1); 1166444Swnj } 1176444Swnj 1186444Swnj #define CRLF "\r\n" 1196444Swnj 1209365Ssam int child; 12111803Sedward int catchild(); 1229365Ssam 12313075Ssam int defflags, tabflag; 12413075Ssam char deferase, defkill; 12513075Ssam struct tchars deftc; 12613075Ssam struct ltchars defltc; 12713075Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 12813075Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 1296444Swnj 1309365Ssam doit() 1316444Swnj { 1326444Swnj int exit(); 13313075Ssam struct sgttyb sb; 1346444Swnj 13513075Ssam ioctl(0, TIOCGETP, (char *)&sb); 13613075Ssam defflags = sb.sg_flags; 13712155Ssam tabflag = defflags & TBDELAY; 1389962Ssam defflags &= ECHO | CRMOD; 13913075Ssam deferase = sb.sg_erase; 14013075Ssam defkill = sb.sg_kill; 14113075Ssam ioctl(0, TIOCGETC, (char *)&deftc); 14213075Ssam notc.t_startc = deftc.t_startc; 14313075Ssam notc.t_stopc = deftc.t_stopc; 14413075Ssam ioctl(0, TIOCGLTC, (char *)&defltc); 14512990Ssam signal(SIGINT, exit); 14612990Ssam signal(SIGHUP, exit); 14712990Ssam signal(SIGQUIT, exit); 1489365Ssam child = fork(); 1499365Ssam if (child == -1) { 1509365Ssam perror("rlogin: fork"); 1519365Ssam done(); 1529365Ssam } 15312990Ssam signal(SIGINT, SIG_IGN); 15411803Sedward mode(1); 1559365Ssam if (child == 0) { 1569365Ssam reader(); 15712155Ssam sleep(1); 15812155Ssam prf("\007Connection closed."); 1596444Swnj exit(3); 1606444Swnj } 16112990Ssam signal(SIGCHLD, catchild); 1629365Ssam writer(); 16312155Ssam prf("Closed connection."); 1646444Swnj done(); 1656444Swnj } 1666444Swnj 1676444Swnj done() 1686444Swnj { 1696444Swnj 1706444Swnj mode(0); 1719365Ssam if (child > 0 && kill(child, SIGKILL) >= 0) 1729365Ssam wait((int *)0); 1736444Swnj exit(0); 1746444Swnj } 1756444Swnj 17611803Sedward catchild() 17711803Sedward { 17811803Sedward union wait status; 17911803Sedward int pid; 18011803Sedward 18111803Sedward again: 18211803Sedward pid = wait3(&status, WNOHANG|WUNTRACED, 0); 18311803Sedward if (pid == 0) 18411803Sedward return; 18511803Sedward /* 18611803Sedward * if the child (reader) dies, just quit 18711803Sedward */ 18811803Sedward if (pid < 0 || pid == child && !WIFSTOPPED(status)) 18911803Sedward done(); 19011803Sedward goto again; 19111803Sedward } 19211803Sedward 1936444Swnj /* 1949365Ssam * writer: write to remote: 0 -> line. 1959365Ssam * ~. terminate 1969365Ssam * ~^Z suspend rlogin process. 19710415Ssam * ~^Y suspend rlogin process, but leave reader alone. 1986444Swnj */ 1999365Ssam writer() 2006444Swnj { 2019365Ssam char b[600], c; 2029365Ssam register char *p; 20311803Sedward register n; 2046444Swnj 2059365Ssam top: 2069365Ssam p = b; 20711803Sedward for (;;) { 2089365Ssam int local; 2099365Ssam 21011803Sedward n = read(0, &c, 1); 21111803Sedward if (n == 0) 21211803Sedward break; 21311803Sedward if (n < 0) 21411803Sedward if (errno == EINTR) 21511803Sedward continue; 21611803Sedward else 21711803Sedward break; 21811803Sedward 2199365Ssam if (eight == 0) 2209365Ssam c &= 0177; 2219365Ssam /* 2229365Ssam * If we're at the beginning of the line 2239365Ssam * and recognize a command character, then 2249365Ssam * we echo locally. Otherwise, characters 2259365Ssam * are echo'd remotely. If the command 2269365Ssam * character is doubled, this acts as a 2279365Ssam * force and local echo is suppressed. 2289365Ssam */ 2299365Ssam if (p == b) 2309365Ssam local = (c == cmdchar); 2319365Ssam if (p == b + 1 && *b == cmdchar) 2329365Ssam local = (c != cmdchar); 2339365Ssam if (!local) { 2349365Ssam if (write(rem, &c, 1) == 0) { 2359365Ssam prf("line gone"); 2369365Ssam return; 2376444Swnj } 2389365Ssam if (eight == 0) 2399365Ssam c &= 0177; 2409365Ssam } else { 2419365Ssam if (c == '\r' || c == '\n') { 2429962Ssam char cmdc = b[1]; 2436444Swnj 24413075Ssam if (cmdc == '.' || cmdc == deftc.t_eofc) { 2459365Ssam write(0, CRLF, sizeof(CRLF)); 2469365Ssam return; 2479962Ssam } 24813075Ssam if (cmdc == defltc.t_suspc || 24913075Ssam cmdc == defltc.t_dsuspc) { 2509365Ssam write(0, CRLF, sizeof(CRLF)); 2519365Ssam mode(0); 25212990Ssam signal(SIGCHLD, SIG_IGN); 25313075Ssam kill(cmdc == defltc.t_suspc ? 2549962Ssam 0 : getpid(), SIGTSTP); 25512990Ssam signal(SIGCHLD, catchild); 2569365Ssam mode(1); 2579365Ssam goto top; 2586444Swnj } 2599365Ssam *p++ = c; 2609365Ssam write(rem, b, p - b); 2619365Ssam goto top; 2626444Swnj } 2639365Ssam write(1, &c, 1); 2646444Swnj } 2659365Ssam *p++ = c; 26613075Ssam if (c == deferase) { 2679365Ssam p -= 2; 2689365Ssam if (p < b) 2699365Ssam goto top; 2706444Swnj } 27113075Ssam if (c == defkill || c == deftc.t_eofc || 2729365Ssam c == '\r' || c == '\n') 2739365Ssam goto top; 27411803Sedward if (p >= &b[sizeof b]) 27511803Sedward p--; 2766444Swnj } 2776444Swnj } 2786444Swnj 2796444Swnj oob() 2806444Swnj { 28110839Ssam int out = 1+1, atmark; 2829365Ssam char waste[BUFSIZ], mark; 2836444Swnj 2849365Ssam ioctl(1, TIOCFLUSH, (char *)&out); 2856444Swnj for (;;) { 28610839Ssam if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 2876444Swnj perror("ioctl"); 2886444Swnj break; 2896444Swnj } 29010839Ssam if (atmark) 2916444Swnj break; 2929365Ssam (void) read(rem, waste, sizeof (waste)); 2936444Swnj } 29412990Ssam recv(rem, &mark, 1, MSG_OOB); 2956444Swnj if (mark & TIOCPKT_NOSTOP) { 29613075Ssam notc.t_stopc = -1; 29713075Ssam notc.t_startc = -1; 29813075Ssam ioctl(0, TIOCSETC, (char *)¬c); 2996444Swnj } 3006444Swnj if (mark & TIOCPKT_DOSTOP) { 30113075Ssam notc.t_stopc = deftc.t_stopc; 30213075Ssam notc.t_startc = deftc.t_startc; 30313075Ssam ioctl(0, TIOCSETC, (char *)¬c); 3046444Swnj } 3056444Swnj } 3066444Swnj 3079365Ssam /* 3089365Ssam * reader: read from remote: line -> 1 3099365Ssam */ 3109365Ssam reader() 3116444Swnj { 3129365Ssam char rb[BUFSIZ]; 3139365Ssam register int cnt; 3146444Swnj 31512990Ssam signal(SIGURG, oob); 3166444Swnj { int pid = -getpid(); 3179365Ssam ioctl(rem, SIOCSPGRP, (char *)&pid); } 3186444Swnj for (;;) { 3199365Ssam cnt = read(rem, rb, sizeof (rb)); 32011396Ssam if (cnt == 0) 32111396Ssam break; 32211396Ssam if (cnt < 0) { 3239365Ssam if (errno == EINTR) 3246444Swnj continue; 3256444Swnj break; 3266444Swnj } 3279365Ssam write(1, rb, cnt); 3286444Swnj } 3296444Swnj } 3306444Swnj 3316444Swnj mode(f) 3326444Swnj { 33313075Ssam struct tchars *tc; 33413075Ssam struct ltchars *ltc; 33513075Ssam struct sgttyb sb; 3369365Ssam 33713075Ssam ioctl(0, TIOCGETP, (char *)&sb); 3389962Ssam switch (f) { 3399962Ssam 3409962Ssam case 0: 34113075Ssam sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 34213075Ssam sb.sg_flags |= defflags|tabflag; 3439962Ssam tc = &deftc; 34413075Ssam ltc = &defltc; 34513075Ssam sb.sg_kill = defkill; 34613075Ssam sb.sg_erase = deferase; 3479962Ssam break; 3489962Ssam 3499962Ssam case 1: 35013075Ssam sb.sg_flags |= (eight ? RAW : CBREAK); 35113075Ssam sb.sg_flags &= ~defflags; 35212155Ssam /* preserve tab delays, but turn off XTABS */ 35313075Ssam if ((sb.sg_flags & TBDELAY) == XTABS) 35413075Ssam sb.sg_flags &= ~TBDELAY; 3559962Ssam tc = ¬c; 35613075Ssam ltc = &noltc; 35713075Ssam sb.sg_kill = sb.sg_erase = -1; 3589962Ssam break; 3599962Ssam 3609962Ssam default: 3619962Ssam return; 3626444Swnj } 36313075Ssam ioctl(0, TIOCSLTC, (char *)ltc); 36413075Ssam ioctl(0, TIOCSETC, (char *)tc); 36513075Ssam ioctl(0, TIOCSETN, (char *)&sb); 3666444Swnj } 3676444Swnj 3689365Ssam /*VARARGS*/ 3696444Swnj prf(f, a1, a2, a3) 3709365Ssam char *f; 3716444Swnj { 3726444Swnj fprintf(stderr, f, a1, a2, a3); 3736444Swnj fprintf(stderr, CRLF); 3746444Swnj } 3756444Swnj 3769365Ssam lostpeer() 3776444Swnj { 37812990Ssam signal(SIGPIPE, SIG_IGN); 37912155Ssam prf("\007Connection closed."); 3809365Ssam done(); 3816444Swnj } 382