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*32116Skarels static char sccsid[] = "@(#)rlogind.c 5.13 (Berkeley) 09/09/87"; 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 476446Swnj extern errno; 4810417Ssam int reapchild(); 496446Swnj struct passwd *getpwnam(); 5024723Smckusick char *malloc(); 5116369Skarels 526446Swnj main(argc, argv) 536446Swnj int argc; 546446Swnj char **argv; 556446Swnj { 5617156Ssam int on = 1, options = 0, fromlen; 576446Swnj struct sockaddr_in from; 586446Swnj 5924855Seric openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH); 6016369Skarels fromlen = sizeof (from); 6116369Skarels if (getpeername(0, &from, &fromlen) < 0) { 6216369Skarels fprintf(stderr, "%s: ", argv[0]); 6316369Skarels perror("getpeername"); 6416369Skarels _exit(1); 658380Ssam } 6617156Ssam if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { 6717187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 686446Swnj } 6916369Skarels doit(0, &from); 706446Swnj } 716446Swnj 726446Swnj int child; 736446Swnj int cleanup(); 746446Swnj int netf; 756446Swnj extern errno; 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 || 107*32116Skarels fromp->sin_port >= IPPORT_RESERVED || 108*32116Skarels 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++) { 1196446Swnj line[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; 1206446Swnj p = open(line, 2); 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'; 1316446Swnj #ifdef DEBUG 1326446Swnj { int tt = open("/dev/tty", 2); 1336446Swnj if (tt > 0) { 1346446Swnj ioctl(tt, TIOCNOTTY, 0); 1356446Swnj close(tt); 1366446Swnj } 1376446Swnj } 1386446Swnj #endif 1396446Swnj t = open(line, 2); 1409242Ssam if (t < 0) 1419242Ssam fatalperror(f, line, errno); 1426446Swnj { struct sgttyb b; 1436446Swnj gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b); 1446446Swnj } 1459242Ssam pid = fork(); 1469242Ssam if (pid < 0) 1479242Ssam fatalperror(f, "", errno); 14818357Ssam if (pid == 0) { 14918357Ssam close(f), close(p); 15018357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 15116227Skarels close(t); 15218357Ssam execl("/bin/login", "login", "-r", hp->h_name, 0); 15318357Ssam fatalperror(2, "/bin/login", errno); 15418357Ssam /*NOTREACHED*/ 15518357Ssam } 15618357Ssam close(t); 15718357Ssam ioctl(f, FIONBIO, &on); 15818357Ssam ioctl(p, FIONBIO, &on); 15918357Ssam ioctl(p, TIOCPKT, &on); 16018357Ssam signal(SIGTSTP, SIG_IGN); 16118357Ssam signal(SIGCHLD, cleanup); 16224724Smckusick setpgrp(0, 0); 16318357Ssam protocol(f, p); 16430600Smckusick signal(SIGCHLD, SIG_IGN); 16518357Ssam cleanup(); 16618357Ssam } 1679242Ssam 16818357Ssam char magic[2] = { 0377, 0377 }; 16925423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 17018357Ssam 17118357Ssam /* 17218357Ssam * Handle a "control" request (signaled by magic being present) 17318357Ssam * in the data stream. For now, we are only willing to handle 17418357Ssam * window size changes. 17518357Ssam */ 17618357Ssam control(pty, cp, n) 17718357Ssam int pty; 17818357Ssam char *cp; 17918357Ssam int n; 18018357Ssam { 18128705Smckusick struct winsize w; 18218357Ssam 18328705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 18418357Ssam return (0); 18525423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 18628705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 18728705Smckusick w.ws_row = ntohs(w.ws_row); 18828705Smckusick w.ws_col = ntohs(w.ws_col); 18928705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 19028705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 19128705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 19228705Smckusick return (4+sizeof (w)); 19318357Ssam } 19418357Ssam 19518357Ssam /* 19618357Ssam * rlogin "protocol" machine. 19718357Ssam */ 19818357Ssam protocol(f, p) 19918357Ssam int f, p; 20018357Ssam { 20118357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 20218357Ssam register pcc = 0, fcc = 0; 20325423Skarels int cc; 20425740Skarels char cntl; 20518357Ssam 20618482Ssam /* 20718484Ssam * Must ignore SIGTTOU, otherwise we'll stop 20818484Ssam * when we try and set slave pty's window shape 20925423Skarels * (our controlling tty is the master pty). 21018482Ssam */ 21118484Ssam (void) signal(SIGTTOU, SIG_IGN); 21225423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 21318357Ssam for (;;) { 21425740Skarels int ibits, obits, ebits; 21518357Ssam 21625740Skarels ibits = 0; 21725740Skarels obits = 0; 21818357Ssam if (fcc) 21918357Ssam obits |= (1<<p); 22018357Ssam else 22118357Ssam ibits |= (1<<f); 22218357Ssam if (pcc >= 0) 22318357Ssam if (pcc) 22418357Ssam obits |= (1<<f); 2259242Ssam else 22618357Ssam ibits |= (1<<p); 22725740Skarels ebits = (1<<p); 22825740Skarels if (select(16, &ibits, &obits, &ebits, 0) < 0) { 22918357Ssam if (errno == EINTR) 2306446Swnj continue; 23118357Ssam fatalperror(f, "select", errno); 23218357Ssam } 23325740Skarels if (ibits == 0 && obits == 0 && ebits == 0) { 23418357Ssam /* shouldn't happen... */ 23518357Ssam sleep(5); 23618357Ssam continue; 23718357Ssam } 23825740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 23925740Skarels if (ebits & (1<<p)) { 24025740Skarels cc = read(p, &cntl, 1); 24125740Skarels if (cc == 1 && pkcontrol(cntl)) { 24225740Skarels cntl |= oobdata[0]; 24325740Skarels send(f, &cntl, 1, MSG_OOB); 24425740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 24525740Skarels pcc = 0; 24625740Skarels ibits &= ~(1<<p); 24725740Skarels } 24825740Skarels } 24925740Skarels } 25018357Ssam if (ibits & (1<<f)) { 25118357Ssam fcc = read(f, fibuf, sizeof (fibuf)); 25218357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 25318357Ssam fcc = 0; 25418357Ssam else { 25518357Ssam register char *cp; 25618357Ssam int left, n; 25718357Ssam 25818357Ssam if (fcc <= 0) 25916227Skarels break; 26018357Ssam fbp = fibuf; 26124723Smckusick 26218357Ssam top: 26325423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 26418357Ssam if (cp[0] == magic[0] && 26518357Ssam cp[1] == magic[1]) { 26618357Ssam left = fcc - (cp-fibuf); 26718357Ssam n = control(p, cp, left); 26818357Ssam if (n) { 26918357Ssam left -= n; 27018357Ssam if (left > 0) 27125423Skarels bcopy(cp+n, cp, left); 27218357Ssam fcc -= n; 27318357Ssam goto top; /* n^2 */ 27425423Skarels } 27525423Skarels } 27625423Skarels } 27725423Skarels } 27824723Smckusick 27924723Smckusick if ((obits & (1<<p)) && fcc > 0) { 28025423Skarels cc = write(p, fbp, fcc); 28124723Smckusick if (cc > 0) { 28224723Smckusick fcc -= cc; 28324723Smckusick fbp += cc; 2846446Swnj } 28518357Ssam } 28624723Smckusick 28718357Ssam if (ibits & (1<<p)) { 28818357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 28918357Ssam pbp = pibuf; 29018357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 29118357Ssam pcc = 0; 29218357Ssam else if (pcc <= 0) 29318357Ssam break; 29418357Ssam else if (pibuf[0] == 0) 29518357Ssam pbp++, pcc--; 29618357Ssam else { 29718357Ssam if (pkcontrol(pibuf[0])) { 29825423Skarels pibuf[0] |= oobdata[0]; 29918357Ssam send(f, &pibuf[0], 1, MSG_OOB); 30016227Skarels } 30118357Ssam pcc = 0; 3026446Swnj } 30318357Ssam } 30418357Ssam if ((obits & (1<<f)) && pcc > 0) { 30525423Skarels cc = write(f, pbp, pcc); 30625423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 30725423Skarels /* also shouldn't happen */ 30825423Skarels sleep(5); 30925423Skarels continue; 31025423Skarels } 31118357Ssam if (cc > 0) { 31218357Ssam pcc -= cc; 31318357Ssam pbp += cc; 31418357Ssam } 3156446Swnj } 3166446Swnj } 3176446Swnj } 3186446Swnj 3196446Swnj cleanup() 3206446Swnj { 3216446Swnj 3226446Swnj rmut(); 32310009Ssam vhangup(); /* XXX */ 32410192Ssam shutdown(netf, 2); 3256446Swnj exit(1); 3266446Swnj } 3276446Swnj 3289242Ssam fatal(f, msg) 3299242Ssam int f; 3309242Ssam char *msg; 3319242Ssam { 3329242Ssam char buf[BUFSIZ]; 3339242Ssam 3349242Ssam buf[0] = '\01'; /* error indicator */ 33513554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 3369242Ssam (void) write(f, buf, strlen(buf)); 3379242Ssam exit(1); 3389242Ssam } 3399242Ssam 3409242Ssam fatalperror(f, msg, errno) 3419242Ssam int f; 3429242Ssam char *msg; 3439242Ssam int errno; 3449242Ssam { 3459242Ssam char buf[BUFSIZ]; 34616227Skarels extern int sys_nerr; 3479242Ssam extern char *sys_errlist[]; 3489242Ssam 34918357Ssam if ((unsigned)errno < sys_nerr) 35016227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 35116227Skarels else 35216227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 3539242Ssam fatal(f, buf); 3549242Ssam } 3559242Ssam 3566446Swnj #include <utmp.h> 3576446Swnj 3586446Swnj struct utmp wtmp; 3596446Swnj char wtmpf[] = "/usr/adm/wtmp"; 36023566Sbloom char utmpf[] = "/etc/utmp"; 3616446Swnj #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 3626446Swnj #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 3636446Swnj 3646446Swnj rmut() 3656446Swnj { 3666446Swnj register f; 3676446Swnj int found = 0; 36823566Sbloom struct utmp *u, *utmp; 36923566Sbloom int nutmp; 37023566Sbloom struct stat statbf; 3716446Swnj 37223566Sbloom f = open(utmpf, O_RDWR); 3736446Swnj if (f >= 0) { 37423566Sbloom fstat(f, &statbf); 37523566Sbloom utmp = (struct utmp *)malloc(statbf.st_size); 37623566Sbloom if (!utmp) 37723566Sbloom syslog(LOG_ERR, "utmp malloc failed"); 37823566Sbloom if (statbf.st_size && utmp) { 37923566Sbloom nutmp = read(f, utmp, statbf.st_size); 38023566Sbloom nutmp /= sizeof(struct utmp); 38123566Sbloom 38223566Sbloom for (u = utmp ; u < &utmp[nutmp] ; u++) { 38323566Sbloom if (SCMPN(u->ut_line, line+5) || 38423566Sbloom u->ut_name[0]==0) 38523566Sbloom continue; 38623566Sbloom lseek(f, ((long)u)-((long)utmp), L_SET); 38723566Sbloom SCPYN(u->ut_name, ""); 38823566Sbloom SCPYN(u->ut_host, ""); 38923566Sbloom time(&u->ut_time); 39023566Sbloom write(f, (char *)u, sizeof(wtmp)); 39123566Sbloom found++; 39223566Sbloom } 3936446Swnj } 3946446Swnj close(f); 3956446Swnj } 3966446Swnj if (found) { 39723566Sbloom f = open(wtmpf, O_WRONLY|O_APPEND); 3986446Swnj if (f >= 0) { 3996446Swnj SCPYN(wtmp.ut_line, line+5); 4006446Swnj SCPYN(wtmp.ut_name, ""); 40112681Ssam SCPYN(wtmp.ut_host, ""); 4026446Swnj time(&wtmp.ut_time); 4036446Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 4046446Swnj close(f); 4056446Swnj } 4066446Swnj } 4076446Swnj chmod(line, 0666); 4086446Swnj chown(line, 0, 0); 4096446Swnj line[strlen("/dev/")] = 'p'; 4106446Swnj chmod(line, 0666); 4116446Swnj chown(line, 0, 0); 4126446Swnj } 413