121174Sdist /* 2*35441Sbostic * Copyright (c) 1983 The Regents of the University of California. 3*35441Sbostic * All rights reserved. 4*35441Sbostic * 5*35441Sbostic * Redistribution and use in source and binary forms are permitted 6*35441Sbostic * provided that the above copyright notice and this paragraph are 7*35441Sbostic * duplicated in all such forms and that any documentation, 8*35441Sbostic * advertising materials, and other materials related to such 9*35441Sbostic * distribution and use acknowledge that the software was developed 10*35441Sbostic * by the University of California, Berkeley. The name of the 11*35441Sbostic * University may not be used to endorse or promote products derived 12*35441Sbostic * from this software without specific prior written permission. 13*35441Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*35441Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*35441Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621174Sdist */ 1721174Sdist 186446Swnj #ifndef lint 1921174Sdist char copyright[] = 20*35441Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ 2121174Sdist All rights reserved.\n"; 22*35441Sbostic #endif /* not lint */ 236446Swnj 2421174Sdist #ifndef lint 25*35441Sbostic static char sccsid[] = "@(#)rlogind.c 5.17 (Berkeley) 08/31/88"; 26*35441Sbostic #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 { 6834424Sbostic int on = 1, fromlen; 696446Swnj struct sockaddr_in from; 706446Swnj 7124855Seric openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH); 7216369Skarels fromlen = sizeof (from); 7316369Skarels if (getpeername(0, &from, &fromlen) < 0) { 7416369Skarels fprintf(stderr, "%s: ", argv[0]); 7516369Skarels perror("getpeername"); 7616369Skarels _exit(1); 778380Ssam } 7817156Ssam if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { 7917187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 806446Swnj } 8116369Skarels doit(0, &from); 826446Swnj } 836446Swnj 846446Swnj int child; 856446Swnj int cleanup(); 866446Swnj int netf; 876446Swnj char *line; 8824724Smckusick extern char *inet_ntoa(); 896446Swnj 9024889Smckusick struct winsize win = { 0, 0, 0, 0 }; 9124723Smckusick 9224889Smckusick 936446Swnj doit(f, fromp) 946446Swnj int f; 956446Swnj struct sockaddr_in *fromp; 966446Swnj { 9718357Ssam int i, p, t, pid, on = 1; 9818357Ssam register struct hostent *hp; 9924724Smckusick struct hostent hostent; 1008380Ssam char c; 1016446Swnj 1026446Swnj alarm(60); 1036446Swnj read(f, &c, 1); 1046446Swnj if (c != 0) 1056446Swnj exit(1); 1066446Swnj alarm(0); 10716227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 1088380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 1098380Ssam fromp->sin_family); 11011345Ssam if (hp == 0) { 11124724Smckusick /* 11224724Smckusick * Only the name is used below. 11324724Smckusick */ 11424724Smckusick hp = &hostent; 11524724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 11611345Ssam } 1176446Swnj if (fromp->sin_family != AF_INET || 11832116Skarels fromp->sin_port >= IPPORT_RESERVED || 11932116Skarels fromp->sin_port < IPPORT_RESERVED/2) 1209242Ssam fatal(f, "Permission denied"); 1216446Swnj write(f, "", 1); 1226446Swnj for (c = 'p'; c <= 's'; c++) { 1236446Swnj struct stat stb; 1246446Swnj line = "/dev/ptyXX"; 1256446Swnj line[strlen("/dev/pty")] = c; 1266446Swnj line[strlen("/dev/ptyp")] = '0'; 1276446Swnj if (stat(line, &stb) < 0) 1286446Swnj break; 1296446Swnj for (i = 0; i < 16; i++) { 13034424Sbostic line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 13134424Sbostic p = open(line, O_RDWR); 1326446Swnj if (p > 0) 1336446Swnj goto gotpty; 1346446Swnj } 1356446Swnj } 13624723Smckusick fatal(f, "Out of ptys"); 1379242Ssam /*NOTREACHED*/ 1386446Swnj gotpty: 13924889Smckusick (void) ioctl(p, TIOCSWINSZ, &win); 14016227Skarels netf = f; 1416446Swnj line[strlen("/dev/")] = 't'; 14234424Sbostic t = open(line, O_RDWR); 14334424Sbostic if (t < 0) 14434424Sbostic fatalperror(f, line); 14534424Sbostic if (fchmod(t, 0)) 14634424Sbostic fatalperror(f, line); 14734424Sbostic (void)signal(SIGHUP, SIG_IGN); 14834424Sbostic vhangup(); 14934424Sbostic (void)signal(SIGHUP, SIG_DFL); 15034424Sbostic t = open(line, O_RDWR); 15134424Sbostic if (t < 0) 15234424Sbostic fatalperror(f, line); 15334424Sbostic { 15434424Sbostic struct sgttyb b; 15534424Sbostic 15634424Sbostic (void)ioctl(t, TIOCGETP, &b); 15734424Sbostic b.sg_flags = RAW|ANYP; 15834424Sbostic (void)ioctl(t, TIOCSETP, &b); 15934424Sbostic } 1606446Swnj #ifdef DEBUG 16134424Sbostic { 16234424Sbostic int tt = open("/dev/tty", O_RDWR); 16334424Sbostic if (tt > 0) { 16434424Sbostic (void)ioctl(tt, TIOCNOTTY, 0); 16534424Sbostic (void)close(tt); 16634424Sbostic } 1676446Swnj } 1686446Swnj #endif 1699242Ssam pid = fork(); 1709242Ssam if (pid < 0) 17134424Sbostic fatalperror(f, ""); 17218357Ssam if (pid == 0) { 17318357Ssam close(f), close(p); 17418357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 17516227Skarels close(t); 17618357Ssam execl("/bin/login", "login", "-r", hp->h_name, 0); 17734424Sbostic fatalperror(2, "/bin/login"); 17818357Ssam /*NOTREACHED*/ 17918357Ssam } 18018357Ssam close(t); 18118357Ssam ioctl(f, FIONBIO, &on); 18218357Ssam ioctl(p, FIONBIO, &on); 18318357Ssam ioctl(p, TIOCPKT, &on); 18418357Ssam signal(SIGTSTP, SIG_IGN); 18518357Ssam signal(SIGCHLD, cleanup); 18624724Smckusick setpgrp(0, 0); 18718357Ssam protocol(f, p); 18830600Smckusick signal(SIGCHLD, SIG_IGN); 18918357Ssam cleanup(); 19018357Ssam } 1919242Ssam 19218357Ssam char magic[2] = { 0377, 0377 }; 19325423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 19418357Ssam 19518357Ssam /* 19618357Ssam * Handle a "control" request (signaled by magic being present) 19718357Ssam * in the data stream. For now, we are only willing to handle 19818357Ssam * window size changes. 19918357Ssam */ 20018357Ssam control(pty, cp, n) 20118357Ssam int pty; 20218357Ssam char *cp; 20318357Ssam int n; 20418357Ssam { 20528705Smckusick struct winsize w; 20618357Ssam 20728705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 20818357Ssam return (0); 20925423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 21028705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 21128705Smckusick w.ws_row = ntohs(w.ws_row); 21228705Smckusick w.ws_col = ntohs(w.ws_col); 21328705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 21428705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 21528705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 21628705Smckusick return (4+sizeof (w)); 21718357Ssam } 21818357Ssam 21918357Ssam /* 22018357Ssam * rlogin "protocol" machine. 22118357Ssam */ 22218357Ssam protocol(f, p) 22318357Ssam int f, p; 22418357Ssam { 22518357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 22618357Ssam register pcc = 0, fcc = 0; 22725423Skarels int cc; 22825740Skarels char cntl; 22918357Ssam 23018482Ssam /* 23118484Ssam * Must ignore SIGTTOU, otherwise we'll stop 23218484Ssam * when we try and set slave pty's window shape 23325423Skarels * (our controlling tty is the master pty). 23418482Ssam */ 23518484Ssam (void) signal(SIGTTOU, SIG_IGN); 23625423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 23718357Ssam for (;;) { 23825740Skarels int ibits, obits, ebits; 23918357Ssam 24025740Skarels ibits = 0; 24125740Skarels obits = 0; 24218357Ssam if (fcc) 24318357Ssam obits |= (1<<p); 24418357Ssam else 24518357Ssam ibits |= (1<<f); 24618357Ssam if (pcc >= 0) 24718357Ssam if (pcc) 24818357Ssam obits |= (1<<f); 2499242Ssam else 25018357Ssam ibits |= (1<<p); 25125740Skarels ebits = (1<<p); 25225740Skarels if (select(16, &ibits, &obits, &ebits, 0) < 0) { 25318357Ssam if (errno == EINTR) 2546446Swnj continue; 25534424Sbostic fatalperror(f, "select"); 25618357Ssam } 25725740Skarels if (ibits == 0 && obits == 0 && ebits == 0) { 25818357Ssam /* shouldn't happen... */ 25918357Ssam sleep(5); 26018357Ssam continue; 26118357Ssam } 26225740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 26325740Skarels if (ebits & (1<<p)) { 26425740Skarels cc = read(p, &cntl, 1); 26525740Skarels if (cc == 1 && pkcontrol(cntl)) { 26625740Skarels cntl |= oobdata[0]; 26725740Skarels send(f, &cntl, 1, MSG_OOB); 26825740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 26925740Skarels pcc = 0; 27025740Skarels ibits &= ~(1<<p); 27125740Skarels } 27225740Skarels } 27325740Skarels } 27418357Ssam if (ibits & (1<<f)) { 27518357Ssam fcc = read(f, fibuf, sizeof (fibuf)); 27618357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 27718357Ssam fcc = 0; 27818357Ssam else { 27918357Ssam register char *cp; 28018357Ssam int left, n; 28118357Ssam 28218357Ssam if (fcc <= 0) 28316227Skarels break; 28418357Ssam fbp = fibuf; 28524723Smckusick 28618357Ssam top: 28725423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 28818357Ssam if (cp[0] == magic[0] && 28918357Ssam cp[1] == magic[1]) { 29018357Ssam left = fcc - (cp-fibuf); 29118357Ssam n = control(p, cp, left); 29218357Ssam if (n) { 29318357Ssam left -= n; 29418357Ssam if (left > 0) 29525423Skarels bcopy(cp+n, cp, left); 29618357Ssam fcc -= n; 29718357Ssam goto top; /* n^2 */ 29825423Skarels } 29925423Skarels } 30025423Skarels } 30125423Skarels } 30224723Smckusick 30324723Smckusick if ((obits & (1<<p)) && fcc > 0) { 30425423Skarels cc = write(p, fbp, fcc); 30524723Smckusick if (cc > 0) { 30624723Smckusick fcc -= cc; 30724723Smckusick fbp += cc; 3086446Swnj } 30918357Ssam } 31024723Smckusick 31118357Ssam if (ibits & (1<<p)) { 31218357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 31318357Ssam pbp = pibuf; 31418357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 31518357Ssam pcc = 0; 31618357Ssam else if (pcc <= 0) 31718357Ssam break; 31818357Ssam else if (pibuf[0] == 0) 31918357Ssam pbp++, pcc--; 32018357Ssam else { 32118357Ssam if (pkcontrol(pibuf[0])) { 32225423Skarels pibuf[0] |= oobdata[0]; 32318357Ssam send(f, &pibuf[0], 1, MSG_OOB); 32416227Skarels } 32518357Ssam pcc = 0; 3266446Swnj } 32718357Ssam } 32818357Ssam if ((obits & (1<<f)) && pcc > 0) { 32925423Skarels cc = write(f, pbp, pcc); 33025423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 33125423Skarels /* also shouldn't happen */ 33225423Skarels sleep(5); 33325423Skarels continue; 33425423Skarels } 33518357Ssam if (cc > 0) { 33618357Ssam pcc -= cc; 33718357Ssam pbp += cc; 33818357Ssam } 3396446Swnj } 3406446Swnj } 3416446Swnj } 3426446Swnj 3436446Swnj cleanup() 3446446Swnj { 34535440Sbostic char *p; 34635440Sbostic 34735440Sbostic p = line + sizeof("/dev/") - 1; 34835440Sbostic if (logout(p)) 34935440Sbostic logwtmp(p, "", ""); 35035440Sbostic (void)chmod(line, 0666); 35135440Sbostic (void)chown(line, 0, 0); 35235440Sbostic *p = 'p'; 35335440Sbostic (void)chmod(line, 0666); 35435440Sbostic (void)chown(line, 0, 0); 35510192Ssam shutdown(netf, 2); 3566446Swnj exit(1); 3576446Swnj } 3586446Swnj 3599242Ssam fatal(f, msg) 3609242Ssam int f; 3619242Ssam char *msg; 3629242Ssam { 3639242Ssam char buf[BUFSIZ]; 3649242Ssam 3659242Ssam buf[0] = '\01'; /* error indicator */ 36613554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 3679242Ssam (void) write(f, buf, strlen(buf)); 3689242Ssam exit(1); 3699242Ssam } 3709242Ssam 37134424Sbostic fatalperror(f, msg) 3729242Ssam int f; 3739242Ssam char *msg; 3749242Ssam { 3759242Ssam char buf[BUFSIZ]; 37616227Skarels extern int sys_nerr; 3779242Ssam extern char *sys_errlist[]; 3789242Ssam 37918357Ssam if ((unsigned)errno < sys_nerr) 38016227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 38116227Skarels else 38216227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 3839242Ssam fatal(f, buf); 3849242Ssam } 385