16446Swnj #ifndef lint 2*18357Ssam static char sccsid[] = "@(#)rlogind.c 4.23 (Berkeley) 03/17/85"; 36446Swnj #endif 46446Swnj 516369Skarels /* 616369Skarels * remote login server: 716369Skarels * remuser\0 816369Skarels * locuser\0 9*18357Ssam * 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> 18*18357Ssam #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> 29*18357Ssam #include <strings.h> 306446Swnj 316446Swnj extern errno; 3210417Ssam int reapchild(); 336446Swnj struct passwd *getpwnam(); 34*18357Ssam 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 { 66*18357Ssam int i, p, t, pid, on = 1; 67*18357Ssam 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", 82*18357Ssam 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); 124*18357Ssam if (pid == 0) { 125*18357Ssam close(f), close(p); 126*18357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 12716227Skarels close(t); 128*18357Ssam execl("/bin/login", "login", "-r", hp->h_name, 0); 129*18357Ssam fatalperror(2, "/bin/login", errno); 130*18357Ssam /*NOTREACHED*/ 131*18357Ssam } 132*18357Ssam close(t); 133*18357Ssam ioctl(f, FIONBIO, &on); 134*18357Ssam ioctl(p, FIONBIO, &on); 135*18357Ssam ioctl(p, TIOCPKT, &on); 136*18357Ssam signal(SIGTSTP, SIG_IGN); 137*18357Ssam signal(SIGCHLD, cleanup); 138*18357Ssam protocol(f, p); 139*18357Ssam cleanup(); 140*18357Ssam } 1419242Ssam 142*18357Ssam char magic[2] = { 0377, 0377 }; 143*18357Ssam 144*18357Ssam /* 145*18357Ssam * Handle a "control" request (signaled by magic being present) 146*18357Ssam * in the data stream. For now, we are only willing to handle 147*18357Ssam * window size changes. 148*18357Ssam */ 149*18357Ssam control(pty, cp, n) 150*18357Ssam int pty; 151*18357Ssam char *cp; 152*18357Ssam int n; 153*18357Ssam { 154*18357Ssam struct winsize *wp; 155*18357Ssam 156*18357Ssam if (n < 4+sizeof (*wp) || cp[2] != 's' || cp[3] != 's') 157*18357Ssam return (0); 158*18357Ssam wp = (struct winsize *)(cp+4); 159*18357Ssam wp->ws_row = ntohs(wp->ws_row); 160*18357Ssam wp->ws_col = ntohs(wp->ws_col); 161*18357Ssam wp->ws_xpixel = ntohs(wp->ws_xpixel); 162*18357Ssam wp->ws_ypixel = ntohs(wp->ws_ypixel); 163*18357Ssam (void)ioctl(pty, TIOCSWINSZ, wp); 164*18357Ssam return (4+sizeof (*wp)); 165*18357Ssam } 166*18357Ssam 167*18357Ssam /* 168*18357Ssam * rlogin "protocol" machine. 169*18357Ssam */ 170*18357Ssam protocol(f, p) 171*18357Ssam int f, p; 172*18357Ssam { 173*18357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 174*18357Ssam register pcc = 0, fcc = 0; 175*18357Ssam int cc, stop = TIOCPKT_DOSTOP; 176*18357Ssam 177*18357Ssam for (;;) { 178*18357Ssam int ibits = 0, obits = 0; 179*18357Ssam 180*18357Ssam if (fcc) 181*18357Ssam obits |= (1<<p); 182*18357Ssam else 183*18357Ssam ibits |= (1<<f); 184*18357Ssam if (pcc >= 0) 185*18357Ssam if (pcc) 186*18357Ssam obits |= (1<<f); 1879242Ssam else 188*18357Ssam ibits |= (1<<p); 189*18357Ssam if (select(16, &ibits, &obits, 0, 0) < 0) { 190*18357Ssam if (errno == EINTR) 1916446Swnj continue; 192*18357Ssam fatalperror(f, "select", errno); 193*18357Ssam } 194*18357Ssam if (ibits == 0 && obits == 0) { 195*18357Ssam /* shouldn't happen... */ 196*18357Ssam sleep(5); 197*18357Ssam continue; 198*18357Ssam } 199*18357Ssam if (ibits & (1<<f)) { 200*18357Ssam fcc = read(f, fibuf, sizeof (fibuf)); 201*18357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 202*18357Ssam fcc = 0; 203*18357Ssam else { 204*18357Ssam register char *cp; 205*18357Ssam int left, n; 206*18357Ssam 207*18357Ssam if (fcc <= 0) 20816227Skarels break; 209*18357Ssam fbp = fibuf; 210*18357Ssam top: 211*18357Ssam for (cp = fibuf; cp < fibuf+fcc; cp++) 212*18357Ssam if (cp[0] == magic[0] && 213*18357Ssam cp[1] == magic[1]) { 214*18357Ssam left = fcc - (cp-fibuf); 215*18357Ssam n = control(p, cp, left); 216*18357Ssam if (n) { 217*18357Ssam left -= n; 218*18357Ssam if (left > 0) 219*18357Ssam bcopy(cp, cp+n, left); 220*18357Ssam fcc -= n; 221*18357Ssam goto top; /* n^2 */ 222*18357Ssam } 2236446Swnj } 2246446Swnj } 225*18357Ssam } 226*18357Ssam if (ibits & (1<<p)) { 227*18357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 228*18357Ssam pbp = pibuf; 229*18357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 230*18357Ssam pcc = 0; 231*18357Ssam else if (pcc <= 0) 232*18357Ssam break; 233*18357Ssam else if (pibuf[0] == 0) 234*18357Ssam pbp++, pcc--; 235*18357Ssam else { 236*18357Ssam #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 237*18357Ssam if (pkcontrol(pibuf[0])) { 238*18357Ssam /* The following 3 lines do nothing. */ 239*18357Ssam int nstop = pibuf[0] & 240*18357Ssam (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP); 241*18357Ssam 242*18357Ssam if (nstop) 243*18357Ssam stop = nstop; 244*18357Ssam pibuf[0] |= nstop; 245*18357Ssam send(f, &pibuf[0], 1, MSG_OOB); 24616227Skarels } 247*18357Ssam pcc = 0; 2486446Swnj } 249*18357Ssam } 250*18357Ssam if ((obits & (1<<f)) && pcc > 0) { 251*18357Ssam cc = write(f, pbp, pcc); 252*18357Ssam if (cc < 0 && errno == EWOULDBLOCK) { 253*18357Ssam /* also shouldn't happen */ 254*18357Ssam sleep(5); 255*18357Ssam continue; 2566446Swnj } 257*18357Ssam if (cc > 0) { 258*18357Ssam pcc -= cc; 259*18357Ssam pbp += cc; 260*18357Ssam } 2616446Swnj } 262*18357Ssam if ((obits & (1<<p)) && fcc > 0) { 263*18357Ssam cc = write(p, fbp, fcc); 264*18357Ssam if (cc > 0) { 265*18357Ssam fcc -= cc; 266*18357Ssam fbp += cc; 267*18357Ssam } 268*18357Ssam } 2696446Swnj } 2706446Swnj } 2716446Swnj 2726446Swnj cleanup() 2736446Swnj { 2746446Swnj 2756446Swnj rmut(); 27610009Ssam vhangup(); /* XXX */ 27710192Ssam shutdown(netf, 2); 2786446Swnj kill(0, SIGKILL); 2796446Swnj exit(1); 2806446Swnj } 2816446Swnj 2829242Ssam fatal(f, msg) 2839242Ssam int f; 2849242Ssam char *msg; 2859242Ssam { 2869242Ssam char buf[BUFSIZ]; 2879242Ssam 2889242Ssam buf[0] = '\01'; /* error indicator */ 28913554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 2909242Ssam (void) write(f, buf, strlen(buf)); 2919242Ssam exit(1); 2929242Ssam } 2939242Ssam 2949242Ssam fatalperror(f, msg, errno) 2959242Ssam int f; 2969242Ssam char *msg; 2979242Ssam int errno; 2989242Ssam { 2999242Ssam char buf[BUFSIZ]; 30016227Skarels extern int sys_nerr; 3019242Ssam extern char *sys_errlist[]; 3029242Ssam 303*18357Ssam if ((unsigned)errno < sys_nerr) 30416227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 30516227Skarels else 30616227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 3079242Ssam fatal(f, buf); 3089242Ssam } 3099242Ssam 3106446Swnj #include <utmp.h> 3116446Swnj 3126446Swnj struct utmp wtmp; 3136446Swnj char wtmpf[] = "/usr/adm/wtmp"; 3146446Swnj char utmp[] = "/etc/utmp"; 3156446Swnj #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 3166446Swnj #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 3176446Swnj 3186446Swnj rmut() 3196446Swnj { 3206446Swnj register f; 3216446Swnj int found = 0; 3226446Swnj 323*18357Ssam f = open(utmp, O_RDWR); 3246446Swnj if (f >= 0) { 3256446Swnj while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { 3266446Swnj if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0) 3276446Swnj continue; 328*18357Ssam lseek(f, -(long)sizeof(wtmp), L_INCR); 3296446Swnj SCPYN(wtmp.ut_name, ""); 33012681Ssam SCPYN(wtmp.ut_host, ""); 3316446Swnj time(&wtmp.ut_time); 3326446Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 3336446Swnj found++; 3346446Swnj } 3356446Swnj close(f); 3366446Swnj } 3376446Swnj if (found) { 338*18357Ssam f = open(wtmpf, O_WRONLY); 3396446Swnj if (f >= 0) { 3406446Swnj SCPYN(wtmp.ut_line, line+5); 3416446Swnj SCPYN(wtmp.ut_name, ""); 34212681Ssam SCPYN(wtmp.ut_host, ""); 3436446Swnj time(&wtmp.ut_time); 344*18357Ssam lseek(f, (long)0, L_XTND); 3456446Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 3466446Swnj close(f); 3476446Swnj } 3486446Swnj } 3496446Swnj chmod(line, 0666); 3506446Swnj chown(line, 0, 0); 3516446Swnj line[strlen("/dev/")] = 'p'; 3526446Swnj chmod(line, 0666); 3536446Swnj chown(line, 0, 0); 3546446Swnj } 355