16446Swnj #ifndef lint 2*18482Ssam static char sccsid[] = "@(#)rlogind.c 4.24 (Berkeley) 03/23/85"; 36446Swnj #endif 46446Swnj 516369Skarels /* 616369Skarels * remote login server: 716369Skarels * remuser\0 816369Skarels * locuser\0 918357Ssam * terminal info\0 1016369Skarels * data 1116369Skarels */ 1216369Skarels 136446Swnj #include <stdio.h> 146446Swnj #include <sys/types.h> 156446Swnj #include <sys/stat.h> 166446Swnj #include <sys/socket.h> 1713554Ssam #include <sys/wait.h> 1818357Ssam #include <sys/file.h> 199208Ssam 209208Ssam #include <netinet/in.h> 219208Ssam 226446Swnj #include <errno.h> 236446Swnj #include <pwd.h> 246446Swnj #include <signal.h> 256446Swnj #include <sgtty.h> 266446Swnj #include <stdio.h> 278380Ssam #include <netdb.h> 2817187Sralph #include <syslog.h> 2918357Ssam #include <strings.h> 306446Swnj 316446Swnj extern errno; 3210417Ssam int reapchild(); 336446Swnj struct passwd *getpwnam(); 3418357Ssam char *crypt(), *malloc(); 3516369Skarels 366446Swnj main(argc, argv) 376446Swnj int argc; 386446Swnj char **argv; 396446Swnj { 4017156Ssam int on = 1, options = 0, fromlen; 416446Swnj struct sockaddr_in from; 426446Swnj 4316369Skarels fromlen = sizeof (from); 4416369Skarels if (getpeername(0, &from, &fromlen) < 0) { 4516369Skarels fprintf(stderr, "%s: ", argv[0]); 4616369Skarels perror("getpeername"); 4716369Skarels _exit(1); 488380Ssam } 4917156Ssam if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { 5017187Sralph openlog(argv[0], LOG_PID, 0); 5117187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 526446Swnj } 5316369Skarels doit(0, &from); 546446Swnj } 556446Swnj 566446Swnj int child; 576446Swnj int cleanup(); 586446Swnj int netf; 596446Swnj extern errno; 606446Swnj char *line; 616446Swnj 626446Swnj doit(f, fromp) 636446Swnj int f; 646446Swnj struct sockaddr_in *fromp; 656446Swnj { 6618357Ssam int i, p, t, pid, on = 1; 6718357Ssam register struct hostent *hp; 688380Ssam char c; 696446Swnj 706446Swnj alarm(60); 716446Swnj read(f, &c, 1); 726446Swnj if (c != 0) 736446Swnj exit(1); 746446Swnj alarm(0); 7516227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 768380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 778380Ssam fromp->sin_family); 7811345Ssam if (hp == 0) { 7916227Skarels char buf[BUFSIZ]; 8011345Ssam 8111345Ssam fatal(f, sprintf(buf, "Host name for your address (%s) unknown", 8218357Ssam inet_ntoa(fromp->sin_addr))); 8311345Ssam } 846446Swnj if (fromp->sin_family != AF_INET || 8516227Skarels fromp->sin_port >= IPPORT_RESERVED) 869242Ssam fatal(f, "Permission denied"); 876446Swnj write(f, "", 1); 886446Swnj for (c = 'p'; c <= 's'; c++) { 896446Swnj struct stat stb; 906446Swnj line = "/dev/ptyXX"; 916446Swnj line[strlen("/dev/pty")] = c; 926446Swnj line[strlen("/dev/ptyp")] = '0'; 936446Swnj if (stat(line, &stb) < 0) 946446Swnj break; 956446Swnj for (i = 0; i < 16; i++) { 966446Swnj line[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; 976446Swnj p = open(line, 2); 986446Swnj if (p > 0) 996446Swnj goto gotpty; 1006446Swnj } 1016446Swnj } 1029242Ssam fatal(f, "All network ports in use"); 1039242Ssam /*NOTREACHED*/ 1046446Swnj gotpty: 10516227Skarels netf = f; 1066446Swnj line[strlen("/dev/")] = 't'; 1076446Swnj #ifdef DEBUG 1086446Swnj { int tt = open("/dev/tty", 2); 1096446Swnj if (tt > 0) { 1106446Swnj ioctl(tt, TIOCNOTTY, 0); 1116446Swnj close(tt); 1126446Swnj } 1136446Swnj } 1146446Swnj #endif 1156446Swnj t = open(line, 2); 1169242Ssam if (t < 0) 1179242Ssam fatalperror(f, line, errno); 1186446Swnj { struct sgttyb b; 1196446Swnj gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b); 1206446Swnj } 1219242Ssam pid = fork(); 1229242Ssam if (pid < 0) 1239242Ssam fatalperror(f, "", errno); 12418357Ssam if (pid == 0) { 12518357Ssam close(f), close(p); 12618357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 12716227Skarels close(t); 12818357Ssam execl("/bin/login", "login", "-r", hp->h_name, 0); 12918357Ssam fatalperror(2, "/bin/login", errno); 13018357Ssam /*NOTREACHED*/ 13118357Ssam } 13218357Ssam close(t); 13318357Ssam ioctl(f, FIONBIO, &on); 13418357Ssam ioctl(p, FIONBIO, &on); 13518357Ssam ioctl(p, TIOCPKT, &on); 13618357Ssam signal(SIGTSTP, SIG_IGN); 13718357Ssam signal(SIGCHLD, cleanup); 13818357Ssam protocol(f, p); 13918357Ssam cleanup(); 14018357Ssam } 1419242Ssam 14218357Ssam char magic[2] = { 0377, 0377 }; 14318357Ssam 14418357Ssam /* 14518357Ssam * Handle a "control" request (signaled by magic being present) 14618357Ssam * in the data stream. For now, we are only willing to handle 14718357Ssam * window size changes. 14818357Ssam */ 14918357Ssam control(pty, cp, n) 15018357Ssam int pty; 15118357Ssam char *cp; 15218357Ssam int n; 15318357Ssam { 15418357Ssam struct winsize *wp; 15518357Ssam 15618357Ssam if (n < 4+sizeof (*wp) || cp[2] != 's' || cp[3] != 's') 15718357Ssam return (0); 15818357Ssam wp = (struct winsize *)(cp+4); 15918357Ssam wp->ws_row = ntohs(wp->ws_row); 16018357Ssam wp->ws_col = ntohs(wp->ws_col); 16118357Ssam wp->ws_xpixel = ntohs(wp->ws_xpixel); 16218357Ssam wp->ws_ypixel = ntohs(wp->ws_ypixel); 16318357Ssam (void)ioctl(pty, TIOCSWINSZ, wp); 16418357Ssam return (4+sizeof (*wp)); 16518357Ssam } 16618357Ssam 16718357Ssam /* 16818357Ssam * rlogin "protocol" machine. 16918357Ssam */ 17018357Ssam protocol(f, p) 17118357Ssam int f, p; 17218357Ssam { 17318357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 17418357Ssam register pcc = 0, fcc = 0; 17518357Ssam int cc, stop = TIOCPKT_DOSTOP; 17618357Ssam 177*18482Ssam /* 178*18482Ssam * This is a hack for the TIOCSWINSZ calls 179*18482Ssam * (csh pgrp manipulation appears to cause 180*18482Ssam * trouble). 181*18482Ssam */ 182*18482Ssam (void) signal(SIGTTOU, SIG_IGN); /* XXX */ 18318357Ssam for (;;) { 18418357Ssam int ibits = 0, obits = 0; 18518357Ssam 18618357Ssam if (fcc) 18718357Ssam obits |= (1<<p); 18818357Ssam else 18918357Ssam ibits |= (1<<f); 19018357Ssam if (pcc >= 0) 19118357Ssam if (pcc) 19218357Ssam obits |= (1<<f); 1939242Ssam else 19418357Ssam ibits |= (1<<p); 19518357Ssam if (select(16, &ibits, &obits, 0, 0) < 0) { 19618357Ssam if (errno == EINTR) 1976446Swnj continue; 19818357Ssam fatalperror(f, "select", errno); 19918357Ssam } 20018357Ssam if (ibits == 0 && obits == 0) { 20118357Ssam /* shouldn't happen... */ 20218357Ssam sleep(5); 20318357Ssam continue; 20418357Ssam } 20518357Ssam if (ibits & (1<<f)) { 20618357Ssam fcc = read(f, fibuf, sizeof (fibuf)); 20718357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 20818357Ssam fcc = 0; 20918357Ssam else { 21018357Ssam register char *cp; 21118357Ssam int left, n; 21218357Ssam 21318357Ssam if (fcc <= 0) 21416227Skarels break; 21518357Ssam fbp = fibuf; 21618357Ssam top: 21718357Ssam for (cp = fibuf; cp < fibuf+fcc; cp++) 21818357Ssam if (cp[0] == magic[0] && 21918357Ssam cp[1] == magic[1]) { 22018357Ssam left = fcc - (cp-fibuf); 22118357Ssam n = control(p, cp, left); 22218357Ssam if (n) { 22318357Ssam left -= n; 22418357Ssam if (left > 0) 22518357Ssam bcopy(cp, cp+n, left); 22618357Ssam fcc -= n; 22718357Ssam goto top; /* n^2 */ 22818357Ssam } 2296446Swnj } 2306446Swnj } 23118357Ssam } 23218357Ssam if (ibits & (1<<p)) { 23318357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 23418357Ssam pbp = pibuf; 23518357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 23618357Ssam pcc = 0; 23718357Ssam else if (pcc <= 0) 23818357Ssam break; 23918357Ssam else if (pibuf[0] == 0) 24018357Ssam pbp++, pcc--; 24118357Ssam else { 24218357Ssam #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 24318357Ssam if (pkcontrol(pibuf[0])) { 24418357Ssam /* The following 3 lines do nothing. */ 24518357Ssam int nstop = pibuf[0] & 24618357Ssam (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP); 24718357Ssam 24818357Ssam if (nstop) 24918357Ssam stop = nstop; 25018357Ssam pibuf[0] |= nstop; 25118357Ssam send(f, &pibuf[0], 1, MSG_OOB); 25216227Skarels } 25318357Ssam pcc = 0; 2546446Swnj } 25518357Ssam } 25618357Ssam if ((obits & (1<<f)) && pcc > 0) { 25718357Ssam cc = write(f, pbp, pcc); 25818357Ssam if (cc < 0 && errno == EWOULDBLOCK) { 25918357Ssam /* also shouldn't happen */ 26018357Ssam sleep(5); 26118357Ssam continue; 2626446Swnj } 26318357Ssam if (cc > 0) { 26418357Ssam pcc -= cc; 26518357Ssam pbp += cc; 26618357Ssam } 2676446Swnj } 26818357Ssam if ((obits & (1<<p)) && fcc > 0) { 26918357Ssam cc = write(p, fbp, fcc); 27018357Ssam if (cc > 0) { 27118357Ssam fcc -= cc; 27218357Ssam fbp += cc; 27318357Ssam } 27418357Ssam } 2756446Swnj } 2766446Swnj } 2776446Swnj 2786446Swnj cleanup() 2796446Swnj { 2806446Swnj 2816446Swnj rmut(); 28210009Ssam vhangup(); /* XXX */ 28310192Ssam shutdown(netf, 2); 2846446Swnj kill(0, SIGKILL); 2856446Swnj exit(1); 2866446Swnj } 2876446Swnj 2889242Ssam fatal(f, msg) 2899242Ssam int f; 2909242Ssam char *msg; 2919242Ssam { 2929242Ssam char buf[BUFSIZ]; 2939242Ssam 2949242Ssam buf[0] = '\01'; /* error indicator */ 29513554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 2969242Ssam (void) write(f, buf, strlen(buf)); 2979242Ssam exit(1); 2989242Ssam } 2999242Ssam 3009242Ssam fatalperror(f, msg, errno) 3019242Ssam int f; 3029242Ssam char *msg; 3039242Ssam int errno; 3049242Ssam { 3059242Ssam char buf[BUFSIZ]; 30616227Skarels extern int sys_nerr; 3079242Ssam extern char *sys_errlist[]; 3089242Ssam 30918357Ssam if ((unsigned)errno < sys_nerr) 31016227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 31116227Skarels else 31216227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 3139242Ssam fatal(f, buf); 3149242Ssam } 3159242Ssam 3166446Swnj #include <utmp.h> 3176446Swnj 3186446Swnj struct utmp wtmp; 3196446Swnj char wtmpf[] = "/usr/adm/wtmp"; 3206446Swnj char utmp[] = "/etc/utmp"; 3216446Swnj #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 3226446Swnj #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 3236446Swnj 3246446Swnj rmut() 3256446Swnj { 3266446Swnj register f; 3276446Swnj int found = 0; 3286446Swnj 32918357Ssam f = open(utmp, O_RDWR); 3306446Swnj if (f >= 0) { 3316446Swnj while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { 3326446Swnj if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0) 3336446Swnj continue; 33418357Ssam lseek(f, -(long)sizeof(wtmp), L_INCR); 3356446Swnj SCPYN(wtmp.ut_name, ""); 33612681Ssam SCPYN(wtmp.ut_host, ""); 3376446Swnj time(&wtmp.ut_time); 3386446Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 3396446Swnj found++; 3406446Swnj } 3416446Swnj close(f); 3426446Swnj } 3436446Swnj if (found) { 34418357Ssam f = open(wtmpf, O_WRONLY); 3456446Swnj if (f >= 0) { 3466446Swnj SCPYN(wtmp.ut_line, line+5); 3476446Swnj SCPYN(wtmp.ut_name, ""); 34812681Ssam SCPYN(wtmp.ut_host, ""); 3496446Swnj time(&wtmp.ut_time); 35018357Ssam lseek(f, (long)0, L_XTND); 3516446Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 3526446Swnj close(f); 3536446Swnj } 3546446Swnj } 3556446Swnj chmod(line, 0666); 3566446Swnj chown(line, 0, 0); 3576446Swnj line[strlen("/dev/")] = 'p'; 3586446Swnj chmod(line, 0666); 3596446Swnj chown(line, 0, 0); 3606446Swnj } 361