121174Sdist /* 235441Sbostic * Copyright (c) 1983 The Regents of the University of California. 335441Sbostic * All rights reserved. 435441Sbostic * 535441Sbostic * Redistribution and use in source and binary forms are permitted 635441Sbostic * provided that the above copyright notice and this paragraph are 735441Sbostic * duplicated in all such forms and that any documentation, 835441Sbostic * advertising materials, and other materials related to such 935441Sbostic * distribution and use acknowledge that the software was developed 1035441Sbostic * by the University of California, Berkeley. The name of the 1135441Sbostic * University may not be used to endorse or promote products derived 1235441Sbostic * from this software without specific prior written permission. 1335441Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435441Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535441Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621174Sdist */ 1721174Sdist 186446Swnj #ifndef lint 1921174Sdist char copyright[] = 2035441Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ 2121174Sdist All rights reserved.\n"; 2235441Sbostic #endif /* not lint */ 236446Swnj 2421174Sdist #ifndef lint 25*36319Sbostic static char sccsid[] = "@(#)rlogind.c 5.18 (Berkeley) 12/08/88"; 2635441Sbostic #endif /* not lint */ 2721174Sdist 2816369Skarels /* 2916369Skarels * remote login server: 3016369Skarels * remuser\0 3116369Skarels * locuser\0 3218357Ssam * terminal info\0 3316369Skarels * data 3416369Skarels */ 3516369Skarels 366446Swnj #include <stdio.h> 376446Swnj #include <sys/types.h> 386446Swnj #include <sys/stat.h> 396446Swnj #include <sys/socket.h> 4013554Ssam #include <sys/wait.h> 4118357Ssam #include <sys/file.h> 429208Ssam 439208Ssam #include <netinet/in.h> 449208Ssam 456446Swnj #include <errno.h> 466446Swnj #include <pwd.h> 476446Swnj #include <signal.h> 486446Swnj #include <sgtty.h> 496446Swnj #include <stdio.h> 508380Ssam #include <netdb.h> 5117187Sralph #include <syslog.h> 5218357Ssam #include <strings.h> 536446Swnj 5424723Smckusick # ifndef TIOCPKT_WINDOW 5524723Smckusick # define TIOCPKT_WINDOW 0x80 5624723Smckusick # endif TIOCPKT_WINDOW 5724723Smckusick 5834424Sbostic extern int errno; 5910417Ssam int reapchild(); 606446Swnj struct passwd *getpwnam(); 6124723Smckusick char *malloc(); 6216369Skarels 6334424Sbostic /*ARGSUSED*/ 646446Swnj main(argc, argv) 656446Swnj int argc; 666446Swnj char **argv; 676446Swnj { 68*36319Sbostic extern int opterr, optind, _check_rhosts_file; 69*36319Sbostic int ch; 7034424Sbostic int on = 1, fromlen; 716446Swnj struct sockaddr_in from; 726446Swnj 7324855Seric openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH); 74*36319Sbostic 75*36319Sbostic opterr = 0; 76*36319Sbostic while ((ch = getopt(argc, argv, "l")) != EOF) 77*36319Sbostic switch((char)ch) { 78*36319Sbostic case 'l': 79*36319Sbostic _check_rhosts_file = 0; 80*36319Sbostic break; 81*36319Sbostic case '?': 82*36319Sbostic default: 83*36319Sbostic syslog(LOG_ERR, "usage: rlogind [-l]"); 84*36319Sbostic break; 85*36319Sbostic } 86*36319Sbostic argc -= optind; 87*36319Sbostic argv += optind; 88*36319Sbostic 8916369Skarels fromlen = sizeof (from); 9016369Skarels if (getpeername(0, &from, &fromlen) < 0) { 9116369Skarels fprintf(stderr, "%s: ", argv[0]); 9216369Skarels perror("getpeername"); 93*36319Sbostic exit(1); 948380Ssam } 9517156Ssam if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { 9617187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 976446Swnj } 9816369Skarels doit(0, &from); 996446Swnj } 1006446Swnj 1016446Swnj int child; 1026446Swnj int cleanup(); 1036446Swnj int netf; 1046446Swnj char *line; 10524724Smckusick extern char *inet_ntoa(); 1066446Swnj 10724889Smckusick struct winsize win = { 0, 0, 0, 0 }; 10824723Smckusick 10924889Smckusick 1106446Swnj doit(f, fromp) 1116446Swnj int f; 1126446Swnj struct sockaddr_in *fromp; 1136446Swnj { 11418357Ssam int i, p, t, pid, on = 1; 11518357Ssam register struct hostent *hp; 11624724Smckusick struct hostent hostent; 1178380Ssam char c; 1186446Swnj 1196446Swnj alarm(60); 1206446Swnj read(f, &c, 1); 1216446Swnj if (c != 0) 1226446Swnj exit(1); 1236446Swnj alarm(0); 12416227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 1258380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 1268380Ssam fromp->sin_family); 12711345Ssam if (hp == 0) { 12824724Smckusick /* 12924724Smckusick * Only the name is used below. 13024724Smckusick */ 13124724Smckusick hp = &hostent; 13224724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 13311345Ssam } 1346446Swnj if (fromp->sin_family != AF_INET || 13532116Skarels fromp->sin_port >= IPPORT_RESERVED || 13632116Skarels fromp->sin_port < IPPORT_RESERVED/2) 1379242Ssam fatal(f, "Permission denied"); 1386446Swnj write(f, "", 1); 1396446Swnj for (c = 'p'; c <= 's'; c++) { 1406446Swnj struct stat stb; 1416446Swnj line = "/dev/ptyXX"; 1426446Swnj line[strlen("/dev/pty")] = c; 1436446Swnj line[strlen("/dev/ptyp")] = '0'; 1446446Swnj if (stat(line, &stb) < 0) 1456446Swnj break; 1466446Swnj for (i = 0; i < 16; i++) { 14734424Sbostic line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 14834424Sbostic p = open(line, O_RDWR); 1496446Swnj if (p > 0) 1506446Swnj goto gotpty; 1516446Swnj } 1526446Swnj } 15324723Smckusick fatal(f, "Out of ptys"); 1549242Ssam /*NOTREACHED*/ 1556446Swnj gotpty: 15624889Smckusick (void) ioctl(p, TIOCSWINSZ, &win); 15716227Skarels netf = f; 1586446Swnj line[strlen("/dev/")] = 't'; 15934424Sbostic t = open(line, O_RDWR); 16034424Sbostic if (t < 0) 16134424Sbostic fatalperror(f, line); 16234424Sbostic if (fchmod(t, 0)) 16334424Sbostic fatalperror(f, line); 16434424Sbostic (void)signal(SIGHUP, SIG_IGN); 16534424Sbostic vhangup(); 16634424Sbostic (void)signal(SIGHUP, SIG_DFL); 16734424Sbostic t = open(line, O_RDWR); 16834424Sbostic if (t < 0) 16934424Sbostic fatalperror(f, line); 17034424Sbostic { 17134424Sbostic struct sgttyb b; 17234424Sbostic 17334424Sbostic (void)ioctl(t, TIOCGETP, &b); 17434424Sbostic b.sg_flags = RAW|ANYP; 17534424Sbostic (void)ioctl(t, TIOCSETP, &b); 17634424Sbostic } 1776446Swnj #ifdef DEBUG 17834424Sbostic { 17934424Sbostic int tt = open("/dev/tty", O_RDWR); 18034424Sbostic if (tt > 0) { 18134424Sbostic (void)ioctl(tt, TIOCNOTTY, 0); 18234424Sbostic (void)close(tt); 18334424Sbostic } 1846446Swnj } 1856446Swnj #endif 1869242Ssam pid = fork(); 1879242Ssam if (pid < 0) 18834424Sbostic fatalperror(f, ""); 18918357Ssam if (pid == 0) { 19018357Ssam close(f), close(p); 19118357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 19216227Skarels close(t); 19318357Ssam execl("/bin/login", "login", "-r", hp->h_name, 0); 19434424Sbostic fatalperror(2, "/bin/login"); 19518357Ssam /*NOTREACHED*/ 19618357Ssam } 19718357Ssam close(t); 19818357Ssam ioctl(f, FIONBIO, &on); 19918357Ssam ioctl(p, FIONBIO, &on); 20018357Ssam ioctl(p, TIOCPKT, &on); 20118357Ssam signal(SIGTSTP, SIG_IGN); 20218357Ssam signal(SIGCHLD, cleanup); 20324724Smckusick setpgrp(0, 0); 20418357Ssam protocol(f, p); 20530600Smckusick signal(SIGCHLD, SIG_IGN); 20618357Ssam cleanup(); 20718357Ssam } 2089242Ssam 20918357Ssam char magic[2] = { 0377, 0377 }; 21025423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 21118357Ssam 21218357Ssam /* 21318357Ssam * Handle a "control" request (signaled by magic being present) 21418357Ssam * in the data stream. For now, we are only willing to handle 21518357Ssam * window size changes. 21618357Ssam */ 21718357Ssam control(pty, cp, n) 21818357Ssam int pty; 21918357Ssam char *cp; 22018357Ssam int n; 22118357Ssam { 22228705Smckusick struct winsize w; 22318357Ssam 22428705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 22518357Ssam return (0); 22625423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 22728705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 22828705Smckusick w.ws_row = ntohs(w.ws_row); 22928705Smckusick w.ws_col = ntohs(w.ws_col); 23028705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 23128705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 23228705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 23328705Smckusick return (4+sizeof (w)); 23418357Ssam } 23518357Ssam 23618357Ssam /* 23718357Ssam * rlogin "protocol" machine. 23818357Ssam */ 23918357Ssam protocol(f, p) 24018357Ssam int f, p; 24118357Ssam { 24218357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 24318357Ssam register pcc = 0, fcc = 0; 24425423Skarels int cc; 24525740Skarels char cntl; 24618357Ssam 24718482Ssam /* 24818484Ssam * Must ignore SIGTTOU, otherwise we'll stop 24918484Ssam * when we try and set slave pty's window shape 25025423Skarels * (our controlling tty is the master pty). 25118482Ssam */ 25218484Ssam (void) signal(SIGTTOU, SIG_IGN); 25325423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 25418357Ssam for (;;) { 25525740Skarels int ibits, obits, ebits; 25618357Ssam 25725740Skarels ibits = 0; 25825740Skarels obits = 0; 25918357Ssam if (fcc) 26018357Ssam obits |= (1<<p); 26118357Ssam else 26218357Ssam ibits |= (1<<f); 26318357Ssam if (pcc >= 0) 26418357Ssam if (pcc) 26518357Ssam obits |= (1<<f); 2669242Ssam else 26718357Ssam ibits |= (1<<p); 26825740Skarels ebits = (1<<p); 26925740Skarels if (select(16, &ibits, &obits, &ebits, 0) < 0) { 27018357Ssam if (errno == EINTR) 2716446Swnj continue; 27234424Sbostic fatalperror(f, "select"); 27318357Ssam } 27425740Skarels if (ibits == 0 && obits == 0 && ebits == 0) { 27518357Ssam /* shouldn't happen... */ 27618357Ssam sleep(5); 27718357Ssam continue; 27818357Ssam } 27925740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 28025740Skarels if (ebits & (1<<p)) { 28125740Skarels cc = read(p, &cntl, 1); 28225740Skarels if (cc == 1 && pkcontrol(cntl)) { 28325740Skarels cntl |= oobdata[0]; 28425740Skarels send(f, &cntl, 1, MSG_OOB); 28525740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 28625740Skarels pcc = 0; 28725740Skarels ibits &= ~(1<<p); 28825740Skarels } 28925740Skarels } 29025740Skarels } 29118357Ssam if (ibits & (1<<f)) { 29218357Ssam fcc = read(f, fibuf, sizeof (fibuf)); 29318357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 29418357Ssam fcc = 0; 29518357Ssam else { 29618357Ssam register char *cp; 29718357Ssam int left, n; 29818357Ssam 29918357Ssam if (fcc <= 0) 30016227Skarels break; 30118357Ssam fbp = fibuf; 30224723Smckusick 30318357Ssam top: 30425423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 30518357Ssam if (cp[0] == magic[0] && 30618357Ssam cp[1] == magic[1]) { 30718357Ssam left = fcc - (cp-fibuf); 30818357Ssam n = control(p, cp, left); 30918357Ssam if (n) { 31018357Ssam left -= n; 31118357Ssam if (left > 0) 31225423Skarels bcopy(cp+n, cp, left); 31318357Ssam fcc -= n; 31418357Ssam goto top; /* n^2 */ 31525423Skarels } 31625423Skarels } 31725423Skarels } 31825423Skarels } 31924723Smckusick 32024723Smckusick if ((obits & (1<<p)) && fcc > 0) { 32125423Skarels cc = write(p, fbp, fcc); 32224723Smckusick if (cc > 0) { 32324723Smckusick fcc -= cc; 32424723Smckusick fbp += cc; 3256446Swnj } 32618357Ssam } 32724723Smckusick 32818357Ssam if (ibits & (1<<p)) { 32918357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 33018357Ssam pbp = pibuf; 33118357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 33218357Ssam pcc = 0; 33318357Ssam else if (pcc <= 0) 33418357Ssam break; 33518357Ssam else if (pibuf[0] == 0) 33618357Ssam pbp++, pcc--; 33718357Ssam else { 33818357Ssam if (pkcontrol(pibuf[0])) { 33925423Skarels pibuf[0] |= oobdata[0]; 34018357Ssam send(f, &pibuf[0], 1, MSG_OOB); 34116227Skarels } 34218357Ssam pcc = 0; 3436446Swnj } 34418357Ssam } 34518357Ssam if ((obits & (1<<f)) && pcc > 0) { 34625423Skarels cc = write(f, pbp, pcc); 34725423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 34825423Skarels /* also shouldn't happen */ 34925423Skarels sleep(5); 35025423Skarels continue; 35125423Skarels } 35218357Ssam if (cc > 0) { 35318357Ssam pcc -= cc; 35418357Ssam pbp += cc; 35518357Ssam } 3566446Swnj } 3576446Swnj } 3586446Swnj } 3596446Swnj 3606446Swnj cleanup() 3616446Swnj { 36235440Sbostic char *p; 36335440Sbostic 36435440Sbostic p = line + sizeof("/dev/") - 1; 36535440Sbostic if (logout(p)) 36635440Sbostic logwtmp(p, "", ""); 36735440Sbostic (void)chmod(line, 0666); 36835440Sbostic (void)chown(line, 0, 0); 36935440Sbostic *p = 'p'; 37035440Sbostic (void)chmod(line, 0666); 37135440Sbostic (void)chown(line, 0, 0); 37210192Ssam shutdown(netf, 2); 3736446Swnj exit(1); 3746446Swnj } 3756446Swnj 3769242Ssam fatal(f, msg) 3779242Ssam int f; 3789242Ssam char *msg; 3799242Ssam { 3809242Ssam char buf[BUFSIZ]; 3819242Ssam 3829242Ssam buf[0] = '\01'; /* error indicator */ 38313554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 3849242Ssam (void) write(f, buf, strlen(buf)); 3859242Ssam exit(1); 3869242Ssam } 3879242Ssam 38834424Sbostic fatalperror(f, msg) 3899242Ssam int f; 3909242Ssam char *msg; 3919242Ssam { 3929242Ssam char buf[BUFSIZ]; 39316227Skarels extern int sys_nerr; 3949242Ssam extern char *sys_errlist[]; 3959242Ssam 39618357Ssam if ((unsigned)errno < sys_nerr) 39716227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 39816227Skarels else 39916227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 4009242Ssam fatal(f, buf); 4019242Ssam } 402