121174Sdist /* 221174Sdist * Copyright (c) 1983 Regents of the University of California. 321174Sdist * All rights reserved. The Berkeley software License Agreement 421174Sdist * specifies the terms and conditions for redistribution. 521174Sdist */ 621174Sdist 76446Swnj #ifndef lint 821174Sdist char copyright[] = 921174Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 1021174Sdist All rights reserved.\n"; 1121174Sdist #endif not lint 126446Swnj 1321174Sdist #ifndef lint 14*35440Sbostic static char sccsid[] = "@(#)rlogind.c 5.16 (Berkeley) 08/31/88"; 1521174Sdist #endif not lint 1621174Sdist 1716369Skarels /* 1816369Skarels * remote login server: 1916369Skarels * remuser\0 2016369Skarels * locuser\0 2118357Ssam * terminal info\0 2216369Skarels * data 2316369Skarels */ 2416369Skarels 256446Swnj #include <stdio.h> 266446Swnj #include <sys/types.h> 276446Swnj #include <sys/stat.h> 286446Swnj #include <sys/socket.h> 2913554Ssam #include <sys/wait.h> 3018357Ssam #include <sys/file.h> 319208Ssam 329208Ssam #include <netinet/in.h> 339208Ssam 346446Swnj #include <errno.h> 356446Swnj #include <pwd.h> 366446Swnj #include <signal.h> 376446Swnj #include <sgtty.h> 386446Swnj #include <stdio.h> 398380Ssam #include <netdb.h> 4017187Sralph #include <syslog.h> 4118357Ssam #include <strings.h> 426446Swnj 4324723Smckusick # ifndef TIOCPKT_WINDOW 4424723Smckusick # define TIOCPKT_WINDOW 0x80 4524723Smckusick # endif TIOCPKT_WINDOW 4624723Smckusick 4734424Sbostic extern int errno; 4810417Ssam int reapchild(); 496446Swnj struct passwd *getpwnam(); 5024723Smckusick char *malloc(); 5116369Skarels 5234424Sbostic /*ARGSUSED*/ 536446Swnj main(argc, argv) 546446Swnj int argc; 556446Swnj char **argv; 566446Swnj { 5734424Sbostic int on = 1, fromlen; 586446Swnj struct sockaddr_in from; 596446Swnj 6024855Seric openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH); 6116369Skarels fromlen = sizeof (from); 6216369Skarels if (getpeername(0, &from, &fromlen) < 0) { 6316369Skarels fprintf(stderr, "%s: ", argv[0]); 6416369Skarels perror("getpeername"); 6516369Skarels _exit(1); 668380Ssam } 6717156Ssam if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { 6817187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 696446Swnj } 7016369Skarels doit(0, &from); 716446Swnj } 726446Swnj 736446Swnj int child; 746446Swnj int cleanup(); 756446Swnj int netf; 766446Swnj char *line; 7724724Smckusick extern char *inet_ntoa(); 786446Swnj 7924889Smckusick struct winsize win = { 0, 0, 0, 0 }; 8024723Smckusick 8124889Smckusick 826446Swnj doit(f, fromp) 836446Swnj int f; 846446Swnj struct sockaddr_in *fromp; 856446Swnj { 8618357Ssam int i, p, t, pid, on = 1; 8718357Ssam register struct hostent *hp; 8824724Smckusick struct hostent hostent; 898380Ssam char c; 906446Swnj 916446Swnj alarm(60); 926446Swnj read(f, &c, 1); 936446Swnj if (c != 0) 946446Swnj exit(1); 956446Swnj alarm(0); 9616227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 978380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 988380Ssam fromp->sin_family); 9911345Ssam if (hp == 0) { 10024724Smckusick /* 10124724Smckusick * Only the name is used below. 10224724Smckusick */ 10324724Smckusick hp = &hostent; 10424724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 10511345Ssam } 1066446Swnj if (fromp->sin_family != AF_INET || 10732116Skarels fromp->sin_port >= IPPORT_RESERVED || 10832116Skarels fromp->sin_port < IPPORT_RESERVED/2) 1099242Ssam fatal(f, "Permission denied"); 1106446Swnj write(f, "", 1); 1116446Swnj for (c = 'p'; c <= 's'; c++) { 1126446Swnj struct stat stb; 1136446Swnj line = "/dev/ptyXX"; 1146446Swnj line[strlen("/dev/pty")] = c; 1156446Swnj line[strlen("/dev/ptyp")] = '0'; 1166446Swnj if (stat(line, &stb) < 0) 1176446Swnj break; 1186446Swnj for (i = 0; i < 16; i++) { 11934424Sbostic line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 12034424Sbostic p = open(line, O_RDWR); 1216446Swnj if (p > 0) 1226446Swnj goto gotpty; 1236446Swnj } 1246446Swnj } 12524723Smckusick fatal(f, "Out of ptys"); 1269242Ssam /*NOTREACHED*/ 1276446Swnj gotpty: 12824889Smckusick (void) ioctl(p, TIOCSWINSZ, &win); 12916227Skarels netf = f; 1306446Swnj line[strlen("/dev/")] = 't'; 13134424Sbostic t = open(line, O_RDWR); 13234424Sbostic if (t < 0) 13334424Sbostic fatalperror(f, line); 13434424Sbostic if (fchmod(t, 0)) 13534424Sbostic fatalperror(f, line); 13634424Sbostic (void)signal(SIGHUP, SIG_IGN); 13734424Sbostic vhangup(); 13834424Sbostic (void)signal(SIGHUP, SIG_DFL); 13934424Sbostic t = open(line, O_RDWR); 14034424Sbostic if (t < 0) 14134424Sbostic fatalperror(f, line); 14234424Sbostic { 14334424Sbostic struct sgttyb b; 14434424Sbostic 14534424Sbostic (void)ioctl(t, TIOCGETP, &b); 14634424Sbostic b.sg_flags = RAW|ANYP; 14734424Sbostic (void)ioctl(t, TIOCSETP, &b); 14834424Sbostic } 1496446Swnj #ifdef DEBUG 15034424Sbostic { 15134424Sbostic int tt = open("/dev/tty", O_RDWR); 15234424Sbostic if (tt > 0) { 15334424Sbostic (void)ioctl(tt, TIOCNOTTY, 0); 15434424Sbostic (void)close(tt); 15534424Sbostic } 1566446Swnj } 1576446Swnj #endif 1589242Ssam pid = fork(); 1599242Ssam if (pid < 0) 16034424Sbostic fatalperror(f, ""); 16118357Ssam if (pid == 0) { 16218357Ssam close(f), close(p); 16318357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 16416227Skarels close(t); 16518357Ssam execl("/bin/login", "login", "-r", hp->h_name, 0); 16634424Sbostic fatalperror(2, "/bin/login"); 16718357Ssam /*NOTREACHED*/ 16818357Ssam } 16918357Ssam close(t); 17018357Ssam ioctl(f, FIONBIO, &on); 17118357Ssam ioctl(p, FIONBIO, &on); 17218357Ssam ioctl(p, TIOCPKT, &on); 17318357Ssam signal(SIGTSTP, SIG_IGN); 17418357Ssam signal(SIGCHLD, cleanup); 17524724Smckusick setpgrp(0, 0); 17618357Ssam protocol(f, p); 17730600Smckusick signal(SIGCHLD, SIG_IGN); 17818357Ssam cleanup(); 17918357Ssam } 1809242Ssam 18118357Ssam char magic[2] = { 0377, 0377 }; 18225423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 18318357Ssam 18418357Ssam /* 18518357Ssam * Handle a "control" request (signaled by magic being present) 18618357Ssam * in the data stream. For now, we are only willing to handle 18718357Ssam * window size changes. 18818357Ssam */ 18918357Ssam control(pty, cp, n) 19018357Ssam int pty; 19118357Ssam char *cp; 19218357Ssam int n; 19318357Ssam { 19428705Smckusick struct winsize w; 19518357Ssam 19628705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 19718357Ssam return (0); 19825423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 19928705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 20028705Smckusick w.ws_row = ntohs(w.ws_row); 20128705Smckusick w.ws_col = ntohs(w.ws_col); 20228705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 20328705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 20428705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 20528705Smckusick return (4+sizeof (w)); 20618357Ssam } 20718357Ssam 20818357Ssam /* 20918357Ssam * rlogin "protocol" machine. 21018357Ssam */ 21118357Ssam protocol(f, p) 21218357Ssam int f, p; 21318357Ssam { 21418357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 21518357Ssam register pcc = 0, fcc = 0; 21625423Skarels int cc; 21725740Skarels char cntl; 21818357Ssam 21918482Ssam /* 22018484Ssam * Must ignore SIGTTOU, otherwise we'll stop 22118484Ssam * when we try and set slave pty's window shape 22225423Skarels * (our controlling tty is the master pty). 22318482Ssam */ 22418484Ssam (void) signal(SIGTTOU, SIG_IGN); 22525423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 22618357Ssam for (;;) { 22725740Skarels int ibits, obits, ebits; 22818357Ssam 22925740Skarels ibits = 0; 23025740Skarels obits = 0; 23118357Ssam if (fcc) 23218357Ssam obits |= (1<<p); 23318357Ssam else 23418357Ssam ibits |= (1<<f); 23518357Ssam if (pcc >= 0) 23618357Ssam if (pcc) 23718357Ssam obits |= (1<<f); 2389242Ssam else 23918357Ssam ibits |= (1<<p); 24025740Skarels ebits = (1<<p); 24125740Skarels if (select(16, &ibits, &obits, &ebits, 0) < 0) { 24218357Ssam if (errno == EINTR) 2436446Swnj continue; 24434424Sbostic fatalperror(f, "select"); 24518357Ssam } 24625740Skarels if (ibits == 0 && obits == 0 && ebits == 0) { 24718357Ssam /* shouldn't happen... */ 24818357Ssam sleep(5); 24918357Ssam continue; 25018357Ssam } 25125740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 25225740Skarels if (ebits & (1<<p)) { 25325740Skarels cc = read(p, &cntl, 1); 25425740Skarels if (cc == 1 && pkcontrol(cntl)) { 25525740Skarels cntl |= oobdata[0]; 25625740Skarels send(f, &cntl, 1, MSG_OOB); 25725740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 25825740Skarels pcc = 0; 25925740Skarels ibits &= ~(1<<p); 26025740Skarels } 26125740Skarels } 26225740Skarels } 26318357Ssam if (ibits & (1<<f)) { 26418357Ssam fcc = read(f, fibuf, sizeof (fibuf)); 26518357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 26618357Ssam fcc = 0; 26718357Ssam else { 26818357Ssam register char *cp; 26918357Ssam int left, n; 27018357Ssam 27118357Ssam if (fcc <= 0) 27216227Skarels break; 27318357Ssam fbp = fibuf; 27424723Smckusick 27518357Ssam top: 27625423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 27718357Ssam if (cp[0] == magic[0] && 27818357Ssam cp[1] == magic[1]) { 27918357Ssam left = fcc - (cp-fibuf); 28018357Ssam n = control(p, cp, left); 28118357Ssam if (n) { 28218357Ssam left -= n; 28318357Ssam if (left > 0) 28425423Skarels bcopy(cp+n, cp, left); 28518357Ssam fcc -= n; 28618357Ssam goto top; /* n^2 */ 28725423Skarels } 28825423Skarels } 28925423Skarels } 29025423Skarels } 29124723Smckusick 29224723Smckusick if ((obits & (1<<p)) && fcc > 0) { 29325423Skarels cc = write(p, fbp, fcc); 29424723Smckusick if (cc > 0) { 29524723Smckusick fcc -= cc; 29624723Smckusick fbp += cc; 2976446Swnj } 29818357Ssam } 29924723Smckusick 30018357Ssam if (ibits & (1<<p)) { 30118357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 30218357Ssam pbp = pibuf; 30318357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 30418357Ssam pcc = 0; 30518357Ssam else if (pcc <= 0) 30618357Ssam break; 30718357Ssam else if (pibuf[0] == 0) 30818357Ssam pbp++, pcc--; 30918357Ssam else { 31018357Ssam if (pkcontrol(pibuf[0])) { 31125423Skarels pibuf[0] |= oobdata[0]; 31218357Ssam send(f, &pibuf[0], 1, MSG_OOB); 31316227Skarels } 31418357Ssam pcc = 0; 3156446Swnj } 31618357Ssam } 31718357Ssam if ((obits & (1<<f)) && pcc > 0) { 31825423Skarels cc = write(f, pbp, pcc); 31925423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 32025423Skarels /* also shouldn't happen */ 32125423Skarels sleep(5); 32225423Skarels continue; 32325423Skarels } 32418357Ssam if (cc > 0) { 32518357Ssam pcc -= cc; 32618357Ssam pbp += cc; 32718357Ssam } 3286446Swnj } 3296446Swnj } 3306446Swnj } 3316446Swnj 3326446Swnj cleanup() 3336446Swnj { 334*35440Sbostic char *p; 335*35440Sbostic 336*35440Sbostic p = line + sizeof("/dev/") - 1; 337*35440Sbostic if (logout(p)) 338*35440Sbostic logwtmp(p, "", ""); 339*35440Sbostic (void)chmod(line, 0666); 340*35440Sbostic (void)chown(line, 0, 0); 341*35440Sbostic *p = 'p'; 342*35440Sbostic (void)chmod(line, 0666); 343*35440Sbostic (void)chown(line, 0, 0); 34410192Ssam shutdown(netf, 2); 3456446Swnj exit(1); 3466446Swnj } 3476446Swnj 3489242Ssam fatal(f, msg) 3499242Ssam int f; 3509242Ssam char *msg; 3519242Ssam { 3529242Ssam char buf[BUFSIZ]; 3539242Ssam 3549242Ssam buf[0] = '\01'; /* error indicator */ 35513554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 3569242Ssam (void) write(f, buf, strlen(buf)); 3579242Ssam exit(1); 3589242Ssam } 3599242Ssam 36034424Sbostic fatalperror(f, msg) 3619242Ssam int f; 3629242Ssam char *msg; 3639242Ssam { 3649242Ssam char buf[BUFSIZ]; 36516227Skarels extern int sys_nerr; 3669242Ssam extern char *sys_errlist[]; 3679242Ssam 36818357Ssam if ((unsigned)errno < sys_nerr) 36916227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 37016227Skarels else 37116227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 3729242Ssam fatal(f, buf); 3739242Ssam } 374