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*24723Smckusick static char sccsid[] = "@(#)rlogind.c 5.2.1.2 (Berkeley) 09/12/85"; 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 43*24723Smckusick # ifndef TIOCPKT_WINDOW 44*24723Smckusick # define TIOCPKT_WINDOW 0x80 45*24723Smckusick # endif TIOCPKT_WINDOW 46*24723Smckusick 476446Swnj extern errno; 4810417Ssam int reapchild(); 496446Swnj struct passwd *getpwnam(); 50*24723Smckusick 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 5916369Skarels fromlen = sizeof (from); 6016369Skarels if (getpeername(0, &from, &fromlen) < 0) { 6116369Skarels fprintf(stderr, "%s: ", argv[0]); 6216369Skarels perror("getpeername"); 6316369Skarels _exit(1); 648380Ssam } 6517156Ssam if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { 6617187Sralph openlog(argv[0], LOG_PID, 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; 776446Swnj 78*24723Smckusick 796446Swnj doit(f, fromp) 806446Swnj int f; 816446Swnj struct sockaddr_in *fromp; 826446Swnj { 8318357Ssam int i, p, t, pid, on = 1; 8418357Ssam register struct hostent *hp; 858380Ssam char c; 866446Swnj 876446Swnj alarm(60); 886446Swnj read(f, &c, 1); 896446Swnj if (c != 0) 906446Swnj exit(1); 916446Swnj alarm(0); 9216227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 938380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 948380Ssam fromp->sin_family); 9511345Ssam if (hp == 0) { 9624722Smckusick char buf[BUFSIZ]; 97*24723Smckusick (void) sprintf(buf, "Host name for your address (%s) unknown", 98*24723Smckusick inet_ntoa(fromp->sin_addr)); 99*24723Smckusick fatal(f, buf); 10011345Ssam } 1016446Swnj if (fromp->sin_family != AF_INET || 10216227Skarels fromp->sin_port >= IPPORT_RESERVED) 1039242Ssam fatal(f, "Permission denied"); 1046446Swnj write(f, "", 1); 1056446Swnj for (c = 'p'; c <= 's'; c++) { 1066446Swnj struct stat stb; 1076446Swnj line = "/dev/ptyXX"; 1086446Swnj line[strlen("/dev/pty")] = c; 1096446Swnj line[strlen("/dev/ptyp")] = '0'; 1106446Swnj if (stat(line, &stb) < 0) 1116446Swnj break; 1126446Swnj for (i = 0; i < 16; i++) { 1136446Swnj line[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; 1146446Swnj p = open(line, 2); 1156446Swnj if (p > 0) 1166446Swnj goto gotpty; 1176446Swnj } 1186446Swnj } 119*24723Smckusick fatal(f, "Out of ptys"); 1209242Ssam /*NOTREACHED*/ 1216446Swnj gotpty: 12216227Skarels netf = f; 1236446Swnj line[strlen("/dev/")] = 't'; 1246446Swnj #ifdef DEBUG 1256446Swnj { int tt = open("/dev/tty", 2); 1266446Swnj if (tt > 0) { 1276446Swnj ioctl(tt, TIOCNOTTY, 0); 1286446Swnj close(tt); 1296446Swnj } 1306446Swnj } 1316446Swnj #endif 1326446Swnj t = open(line, 2); 1339242Ssam if (t < 0) 1349242Ssam fatalperror(f, line, errno); 1356446Swnj { struct sgttyb b; 1366446Swnj gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b); 1376446Swnj } 1389242Ssam pid = fork(); 1399242Ssam if (pid < 0) 1409242Ssam fatalperror(f, "", errno); 14118357Ssam if (pid == 0) { 14218357Ssam close(f), close(p); 14318357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 14416227Skarels close(t); 14518357Ssam execl("/bin/login", "login", "-r", hp->h_name, 0); 14618357Ssam fatalperror(2, "/bin/login", errno); 14718357Ssam /*NOTREACHED*/ 14818357Ssam } 14918357Ssam close(t); 15018357Ssam ioctl(f, FIONBIO, &on); 15118357Ssam ioctl(p, FIONBIO, &on); 15218357Ssam ioctl(p, TIOCPKT, &on); 15318357Ssam signal(SIGTSTP, SIG_IGN); 15418357Ssam signal(SIGCHLD, cleanup); 15518357Ssam protocol(f, p); 15618357Ssam cleanup(); 15718357Ssam } 1589242Ssam 15918357Ssam char magic[2] = { 0377, 0377 }; 16018357Ssam 16118357Ssam /* 16218357Ssam * Handle a "control" request (signaled by magic being present) 16318357Ssam * in the data stream. For now, we are only willing to handle 16418357Ssam * window size changes. 16518357Ssam */ 16618357Ssam control(pty, cp, n) 16718357Ssam int pty; 16818357Ssam char *cp; 16918357Ssam int n; 17018357Ssam { 17118357Ssam struct winsize *wp; 17218357Ssam 17318357Ssam if (n < 4+sizeof (*wp) || cp[2] != 's' || cp[3] != 's') 17418357Ssam return (0); 17518357Ssam wp = (struct winsize *)(cp+4); 17618357Ssam wp->ws_row = ntohs(wp->ws_row); 17718357Ssam wp->ws_col = ntohs(wp->ws_col); 17818357Ssam wp->ws_xpixel = ntohs(wp->ws_xpixel); 17918357Ssam wp->ws_ypixel = ntohs(wp->ws_ypixel); 18018357Ssam (void)ioctl(pty, TIOCSWINSZ, wp); 18118357Ssam return (4+sizeof (*wp)); 18218357Ssam } 18318357Ssam 18418357Ssam /* 18518357Ssam * rlogin "protocol" machine. 18618357Ssam */ 18718357Ssam protocol(f, p) 18818357Ssam int f, p; 18918357Ssam { 19018357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 19118357Ssam register pcc = 0, fcc = 0; 192*24723Smckusick int cc, stop = TIOCPKT_DOSTOP, wsize; 193*24723Smckusick static char oob[] = {TIOCPKT_WINDOW}; 19418357Ssam 19518482Ssam /* 19618484Ssam * Must ignore SIGTTOU, otherwise we'll stop 19718484Ssam * when we try and set slave pty's window shape 19818484Ssam * (our pgrp is that of the master pty). 19918482Ssam */ 20018484Ssam (void) signal(SIGTTOU, SIG_IGN); 201*24723Smckusick send(f, oob, 1, MSG_OOB); /* indicate new rlogin */ 20218357Ssam for (;;) { 20318357Ssam int ibits = 0, obits = 0; 20418357Ssam 20518357Ssam if (fcc) 20618357Ssam obits |= (1<<p); 20718357Ssam else 20818357Ssam ibits |= (1<<f); 20918357Ssam if (pcc >= 0) 21018357Ssam if (pcc) 21118357Ssam obits |= (1<<f); 2129242Ssam else 21318357Ssam ibits |= (1<<p); 21418357Ssam if (select(16, &ibits, &obits, 0, 0) < 0) { 21518357Ssam if (errno == EINTR) 2166446Swnj continue; 21718357Ssam fatalperror(f, "select", errno); 21818357Ssam } 21918357Ssam if (ibits == 0 && obits == 0) { 22018357Ssam /* shouldn't happen... */ 22118357Ssam sleep(5); 22218357Ssam continue; 22318357Ssam } 22418357Ssam if (ibits & (1<<f)) { 22518357Ssam fcc = read(f, fibuf, sizeof (fibuf)); 22618357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 22718357Ssam fcc = 0; 22818357Ssam else { 22918357Ssam register char *cp; 23018357Ssam int left, n; 23118357Ssam 23218357Ssam if (fcc <= 0) 23316227Skarels break; 23418357Ssam fbp = fibuf; 235*24723Smckusick 23618357Ssam top: 23718357Ssam for (cp = fibuf; cp < fibuf+fcc; cp++) 23818357Ssam if (cp[0] == magic[0] && 23918357Ssam cp[1] == magic[1]) { 24018357Ssam left = fcc - (cp-fibuf); 24118357Ssam n = control(p, cp, left); 24218357Ssam if (n) { 24318357Ssam left -= n; 24418357Ssam if (left > 0) 24518357Ssam bcopy(cp, cp+n, left); 24618357Ssam fcc -= n; 24718357Ssam goto top; /* n^2 */ 248*24723Smckusick } /* if (n) */ 249*24723Smckusick } /* for (cp = ) */ 250*24723Smckusick } /* else */ 251*24723Smckusick } /* if (ibits & (1<<f)) */ 252*24723Smckusick 253*24723Smckusick if ((obits & (1<<p)) && fcc > 0) { 254*24723Smckusick wsize = fcc; 255*24723Smckusick do { 256*24723Smckusick cc = write(p, fbp, wsize); 257*24723Smckusick wsize /= 2; 258*24723Smckusick } while (cc<0 && errno==EWOULDBLOCK && wsize); 259*24723Smckusick if (cc > 0) { 260*24723Smckusick fcc -= cc; 261*24723Smckusick fbp += cc; 2626446Swnj } 26318357Ssam } 264*24723Smckusick 26518357Ssam if (ibits & (1<<p)) { 26618357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 26718357Ssam pbp = pibuf; 26818357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 26918357Ssam pcc = 0; 27018357Ssam else if (pcc <= 0) 27118357Ssam break; 27218357Ssam else if (pibuf[0] == 0) 27318357Ssam pbp++, pcc--; 27418357Ssam else { 27518357Ssam #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 276*24723Smckusick int out = FREAD; 277*24723Smckusick 27818357Ssam if (pkcontrol(pibuf[0])) { 27918357Ssam /* The following 3 lines do nothing. */ 28018357Ssam int nstop = pibuf[0] & 28118357Ssam (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP); 28218357Ssam 28318357Ssam if (nstop) 28418357Ssam stop = nstop; 28518357Ssam pibuf[0] |= nstop; 28618357Ssam send(f, &pibuf[0], 1, MSG_OOB); 287*24723Smckusick if (pibuf[0] & TIOCPKT_FLUSHWRITE) 288*24723Smckusick ioctl(p, TIOCFLUSH, (char *)&out); 289*24723Smckusick 29016227Skarels } 29118357Ssam pcc = 0; 2926446Swnj } 29318357Ssam } 29418357Ssam if ((obits & (1<<f)) && pcc > 0) { 295*24723Smckusick wsize = pcc; 296*24723Smckusick do { 297*24723Smckusick cc = write(f, pbp, wsize); 298*24723Smckusick wsize /= 2; 299*24723Smckusick } while (cc<0 && errno==EWOULDBLOCK && wsize); 30018357Ssam if (cc > 0) { 30118357Ssam pcc -= cc; 30218357Ssam pbp += cc; 30318357Ssam } 3046446Swnj } 3056446Swnj } 3066446Swnj } 3076446Swnj 3086446Swnj cleanup() 3096446Swnj { 3106446Swnj 3116446Swnj rmut(); 31210009Ssam vhangup(); /* XXX */ 31310192Ssam shutdown(netf, 2); 3146446Swnj kill(0, SIGKILL); 3156446Swnj exit(1); 3166446Swnj } 3176446Swnj 3189242Ssam fatal(f, msg) 3199242Ssam int f; 3209242Ssam char *msg; 3219242Ssam { 3229242Ssam char buf[BUFSIZ]; 3239242Ssam 3249242Ssam buf[0] = '\01'; /* error indicator */ 32513554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 3269242Ssam (void) write(f, buf, strlen(buf)); 3279242Ssam exit(1); 3289242Ssam } 3299242Ssam 3309242Ssam fatalperror(f, msg, errno) 3319242Ssam int f; 3329242Ssam char *msg; 3339242Ssam int errno; 3349242Ssam { 3359242Ssam char buf[BUFSIZ]; 33616227Skarels extern int sys_nerr; 3379242Ssam extern char *sys_errlist[]; 3389242Ssam 33918357Ssam if ((unsigned)errno < sys_nerr) 34016227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 34116227Skarels else 34216227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 3439242Ssam fatal(f, buf); 3449242Ssam } 3459242Ssam 3466446Swnj #include <utmp.h> 3476446Swnj 3486446Swnj struct utmp wtmp; 3496446Swnj char wtmpf[] = "/usr/adm/wtmp"; 35023566Sbloom char utmpf[] = "/etc/utmp"; 3516446Swnj #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 3526446Swnj #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 3536446Swnj 3546446Swnj rmut() 3556446Swnj { 3566446Swnj register f; 3576446Swnj int found = 0; 35823566Sbloom struct utmp *u, *utmp; 35923566Sbloom int nutmp; 36023566Sbloom struct stat statbf; 3616446Swnj 36223566Sbloom f = open(utmpf, O_RDWR); 3636446Swnj if (f >= 0) { 36423566Sbloom fstat(f, &statbf); 36523566Sbloom utmp = (struct utmp *)malloc(statbf.st_size); 36623566Sbloom if (!utmp) 36723566Sbloom syslog(LOG_ERR, "utmp malloc failed"); 36823566Sbloom if (statbf.st_size && utmp) { 36923566Sbloom nutmp = read(f, utmp, statbf.st_size); 37023566Sbloom nutmp /= sizeof(struct utmp); 37123566Sbloom 37223566Sbloom for (u = utmp ; u < &utmp[nutmp] ; u++) { 37323566Sbloom if (SCMPN(u->ut_line, line+5) || 37423566Sbloom u->ut_name[0]==0) 37523566Sbloom continue; 37623566Sbloom lseek(f, ((long)u)-((long)utmp), L_SET); 37723566Sbloom SCPYN(u->ut_name, ""); 37823566Sbloom SCPYN(u->ut_host, ""); 37923566Sbloom time(&u->ut_time); 38023566Sbloom write(f, (char *)u, sizeof(wtmp)); 38123566Sbloom found++; 38223566Sbloom } 3836446Swnj } 3846446Swnj close(f); 3856446Swnj } 3866446Swnj if (found) { 38723566Sbloom f = open(wtmpf, O_WRONLY|O_APPEND); 3886446Swnj if (f >= 0) { 3896446Swnj SCPYN(wtmp.ut_line, line+5); 3906446Swnj SCPYN(wtmp.ut_name, ""); 39112681Ssam SCPYN(wtmp.ut_host, ""); 3926446Swnj time(&wtmp.ut_time); 3936446Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 3946446Swnj close(f); 3956446Swnj } 3966446Swnj } 3976446Swnj chmod(line, 0666); 3986446Swnj chown(line, 0, 0); 3996446Swnj line[strlen("/dev/")] = 'p'; 4006446Swnj chmod(line, 0666); 4016446Swnj chown(line, 0, 0); 4026446Swnj } 403