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*24722Smckusick static char sccsid[] = "@(#)rlogind.c 5.2.1.1 (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 436446Swnj extern errno; 4410417Ssam int reapchild(); 456446Swnj struct passwd *getpwnam(); 4618357Ssam char *crypt(), *malloc(); 4716369Skarels 486446Swnj main(argc, argv) 496446Swnj int argc; 506446Swnj char **argv; 516446Swnj { 5217156Ssam int on = 1, options = 0, fromlen; 536446Swnj struct sockaddr_in from; 546446Swnj 5516369Skarels fromlen = sizeof (from); 5616369Skarels if (getpeername(0, &from, &fromlen) < 0) { 5716369Skarels fprintf(stderr, "%s: ", argv[0]); 5816369Skarels perror("getpeername"); 5916369Skarels _exit(1); 608380Ssam } 6117156Ssam if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { 6217187Sralph openlog(argv[0], LOG_PID, 0); 6317187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 646446Swnj } 6516369Skarels doit(0, &from); 666446Swnj } 676446Swnj 686446Swnj int child; 696446Swnj int cleanup(); 706446Swnj int netf; 716446Swnj extern errno; 726446Swnj char *line; 736446Swnj 746446Swnj doit(f, fromp) 756446Swnj int f; 766446Swnj struct sockaddr_in *fromp; 776446Swnj { 7818357Ssam int i, p, t, pid, on = 1; 7918357Ssam register struct hostent *hp; 808380Ssam char c; 816446Swnj 826446Swnj alarm(60); 836446Swnj read(f, &c, 1); 846446Swnj if (c != 0) 856446Swnj exit(1); 866446Swnj alarm(0); 8716227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 888380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 898380Ssam fromp->sin_family); 9011345Ssam if (hp == 0) { 91*24722Smckusick char buf[BUFSIZ]; 92*24722Smckusick 93*24722Smckusick fatal(f, sprintf(buf, "Host name for your address (%s) unknown", 94*24722Smckusick inet_ntoa(fromp->sin_addr))); 9511345Ssam } 966446Swnj if (fromp->sin_family != AF_INET || 9716227Skarels fromp->sin_port >= IPPORT_RESERVED) 989242Ssam fatal(f, "Permission denied"); 996446Swnj write(f, "", 1); 1006446Swnj for (c = 'p'; c <= 's'; c++) { 1016446Swnj struct stat stb; 1026446Swnj line = "/dev/ptyXX"; 1036446Swnj line[strlen("/dev/pty")] = c; 1046446Swnj line[strlen("/dev/ptyp")] = '0'; 1056446Swnj if (stat(line, &stb) < 0) 1066446Swnj break; 1076446Swnj for (i = 0; i < 16; i++) { 1086446Swnj line[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; 1096446Swnj p = open(line, 2); 1106446Swnj if (p > 0) 1116446Swnj goto gotpty; 1126446Swnj } 1136446Swnj } 1149242Ssam fatal(f, "All network ports in use"); 1159242Ssam /*NOTREACHED*/ 1166446Swnj gotpty: 11716227Skarels netf = f; 1186446Swnj line[strlen("/dev/")] = 't'; 1196446Swnj #ifdef DEBUG 1206446Swnj { int tt = open("/dev/tty", 2); 1216446Swnj if (tt > 0) { 1226446Swnj ioctl(tt, TIOCNOTTY, 0); 1236446Swnj close(tt); 1246446Swnj } 1256446Swnj } 1266446Swnj #endif 1276446Swnj t = open(line, 2); 1289242Ssam if (t < 0) 1299242Ssam fatalperror(f, line, errno); 1306446Swnj { struct sgttyb b; 1316446Swnj gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b); 1326446Swnj } 1339242Ssam pid = fork(); 1349242Ssam if (pid < 0) 1359242Ssam fatalperror(f, "", errno); 13618357Ssam if (pid == 0) { 13718357Ssam close(f), close(p); 13818357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 13916227Skarels close(t); 14018357Ssam execl("/bin/login", "login", "-r", hp->h_name, 0); 14118357Ssam fatalperror(2, "/bin/login", errno); 14218357Ssam /*NOTREACHED*/ 14318357Ssam } 14418357Ssam close(t); 14518357Ssam ioctl(f, FIONBIO, &on); 14618357Ssam ioctl(p, FIONBIO, &on); 14718357Ssam ioctl(p, TIOCPKT, &on); 14818357Ssam signal(SIGTSTP, SIG_IGN); 14918357Ssam signal(SIGCHLD, cleanup); 15018357Ssam protocol(f, p); 15118357Ssam cleanup(); 15218357Ssam } 1539242Ssam 15418357Ssam char magic[2] = { 0377, 0377 }; 15518357Ssam 15618357Ssam /* 15718357Ssam * Handle a "control" request (signaled by magic being present) 15818357Ssam * in the data stream. For now, we are only willing to handle 15918357Ssam * window size changes. 16018357Ssam */ 16118357Ssam control(pty, cp, n) 16218357Ssam int pty; 16318357Ssam char *cp; 16418357Ssam int n; 16518357Ssam { 16618357Ssam struct winsize *wp; 16718357Ssam 16818357Ssam if (n < 4+sizeof (*wp) || cp[2] != 's' || cp[3] != 's') 16918357Ssam return (0); 17018357Ssam wp = (struct winsize *)(cp+4); 17118357Ssam wp->ws_row = ntohs(wp->ws_row); 17218357Ssam wp->ws_col = ntohs(wp->ws_col); 17318357Ssam wp->ws_xpixel = ntohs(wp->ws_xpixel); 17418357Ssam wp->ws_ypixel = ntohs(wp->ws_ypixel); 17518357Ssam (void)ioctl(pty, TIOCSWINSZ, wp); 17618357Ssam return (4+sizeof (*wp)); 17718357Ssam } 17818357Ssam 17918357Ssam /* 18018357Ssam * rlogin "protocol" machine. 18118357Ssam */ 18218357Ssam protocol(f, p) 18318357Ssam int f, p; 18418357Ssam { 18518357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 18618357Ssam register pcc = 0, fcc = 0; 18718357Ssam int cc, stop = TIOCPKT_DOSTOP; 18818357Ssam 18918482Ssam /* 19018484Ssam * Must ignore SIGTTOU, otherwise we'll stop 19118484Ssam * when we try and set slave pty's window shape 19218484Ssam * (our pgrp is that of the master pty). 19318482Ssam */ 19418484Ssam (void) signal(SIGTTOU, SIG_IGN); 19518357Ssam for (;;) { 19618357Ssam int ibits = 0, obits = 0; 19718357Ssam 19818357Ssam if (fcc) 19918357Ssam obits |= (1<<p); 20018357Ssam else 20118357Ssam ibits |= (1<<f); 20218357Ssam if (pcc >= 0) 20318357Ssam if (pcc) 20418357Ssam obits |= (1<<f); 2059242Ssam else 20618357Ssam ibits |= (1<<p); 20718357Ssam if (select(16, &ibits, &obits, 0, 0) < 0) { 20818357Ssam if (errno == EINTR) 2096446Swnj continue; 21018357Ssam fatalperror(f, "select", errno); 21118357Ssam } 21218357Ssam if (ibits == 0 && obits == 0) { 21318357Ssam /* shouldn't happen... */ 21418357Ssam sleep(5); 21518357Ssam continue; 21618357Ssam } 21718357Ssam if (ibits & (1<<f)) { 21818357Ssam fcc = read(f, fibuf, sizeof (fibuf)); 21918357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 22018357Ssam fcc = 0; 22118357Ssam else { 22218357Ssam register char *cp; 22318357Ssam int left, n; 22418357Ssam 22518357Ssam if (fcc <= 0) 22616227Skarels break; 22718357Ssam fbp = fibuf; 22818357Ssam top: 22918357Ssam for (cp = fibuf; cp < fibuf+fcc; cp++) 23018357Ssam if (cp[0] == magic[0] && 23118357Ssam cp[1] == magic[1]) { 23218357Ssam left = fcc - (cp-fibuf); 23318357Ssam n = control(p, cp, left); 23418357Ssam if (n) { 23518357Ssam left -= n; 23618357Ssam if (left > 0) 23718357Ssam bcopy(cp, cp+n, left); 23818357Ssam fcc -= n; 23918357Ssam goto top; /* n^2 */ 24018357Ssam } 2416446Swnj } 2426446Swnj } 24318357Ssam } 24418357Ssam if (ibits & (1<<p)) { 24518357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 24618357Ssam pbp = pibuf; 24718357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 24818357Ssam pcc = 0; 24918357Ssam else if (pcc <= 0) 25018357Ssam break; 25118357Ssam else if (pibuf[0] == 0) 25218357Ssam pbp++, pcc--; 25318357Ssam else { 25418357Ssam #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 25518357Ssam if (pkcontrol(pibuf[0])) { 25618357Ssam /* The following 3 lines do nothing. */ 25718357Ssam int nstop = pibuf[0] & 25818357Ssam (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP); 25918357Ssam 26018357Ssam if (nstop) 26118357Ssam stop = nstop; 26218357Ssam pibuf[0] |= nstop; 26318357Ssam send(f, &pibuf[0], 1, MSG_OOB); 26416227Skarels } 26518357Ssam pcc = 0; 2666446Swnj } 26718357Ssam } 26818357Ssam if ((obits & (1<<f)) && pcc > 0) { 26918357Ssam cc = write(f, pbp, pcc); 27018357Ssam if (cc < 0 && errno == EWOULDBLOCK) { 27118357Ssam /* also shouldn't happen */ 27218357Ssam sleep(5); 27318357Ssam continue; 2746446Swnj } 27518357Ssam if (cc > 0) { 27618357Ssam pcc -= cc; 27718357Ssam pbp += cc; 27818357Ssam } 2796446Swnj } 28018357Ssam if ((obits & (1<<p)) && fcc > 0) { 28118357Ssam cc = write(p, fbp, fcc); 28218357Ssam if (cc > 0) { 28318357Ssam fcc -= cc; 28418357Ssam fbp += cc; 28518357Ssam } 28618357Ssam } 2876446Swnj } 2886446Swnj } 2896446Swnj 2906446Swnj cleanup() 2916446Swnj { 2926446Swnj 2936446Swnj rmut(); 29410009Ssam vhangup(); /* XXX */ 29510192Ssam shutdown(netf, 2); 2966446Swnj kill(0, SIGKILL); 2976446Swnj exit(1); 2986446Swnj } 2996446Swnj 3009242Ssam fatal(f, msg) 3019242Ssam int f; 3029242Ssam char *msg; 3039242Ssam { 3049242Ssam char buf[BUFSIZ]; 3059242Ssam 3069242Ssam buf[0] = '\01'; /* error indicator */ 30713554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 3089242Ssam (void) write(f, buf, strlen(buf)); 3099242Ssam exit(1); 3109242Ssam } 3119242Ssam 3129242Ssam fatalperror(f, msg, errno) 3139242Ssam int f; 3149242Ssam char *msg; 3159242Ssam int errno; 3169242Ssam { 3179242Ssam char buf[BUFSIZ]; 31816227Skarels extern int sys_nerr; 3199242Ssam extern char *sys_errlist[]; 3209242Ssam 32118357Ssam if ((unsigned)errno < sys_nerr) 32216227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 32316227Skarels else 32416227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 3259242Ssam fatal(f, buf); 3269242Ssam } 3279242Ssam 3286446Swnj #include <utmp.h> 3296446Swnj 3306446Swnj struct utmp wtmp; 3316446Swnj char wtmpf[] = "/usr/adm/wtmp"; 33223566Sbloom char utmpf[] = "/etc/utmp"; 3336446Swnj #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 3346446Swnj #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 3356446Swnj 3366446Swnj rmut() 3376446Swnj { 3386446Swnj register f; 3396446Swnj int found = 0; 34023566Sbloom struct utmp *u, *utmp; 34123566Sbloom int nutmp; 34223566Sbloom struct stat statbf; 3436446Swnj 34423566Sbloom f = open(utmpf, O_RDWR); 3456446Swnj if (f >= 0) { 34623566Sbloom fstat(f, &statbf); 34723566Sbloom utmp = (struct utmp *)malloc(statbf.st_size); 34823566Sbloom if (!utmp) 34923566Sbloom syslog(LOG_ERR, "utmp malloc failed"); 35023566Sbloom if (statbf.st_size && utmp) { 35123566Sbloom nutmp = read(f, utmp, statbf.st_size); 35223566Sbloom nutmp /= sizeof(struct utmp); 35323566Sbloom 35423566Sbloom for (u = utmp ; u < &utmp[nutmp] ; u++) { 35523566Sbloom if (SCMPN(u->ut_line, line+5) || 35623566Sbloom u->ut_name[0]==0) 35723566Sbloom continue; 35823566Sbloom lseek(f, ((long)u)-((long)utmp), L_SET); 35923566Sbloom SCPYN(u->ut_name, ""); 36023566Sbloom SCPYN(u->ut_host, ""); 36123566Sbloom time(&u->ut_time); 36223566Sbloom write(f, (char *)u, sizeof(wtmp)); 36323566Sbloom found++; 36423566Sbloom } 3656446Swnj } 3666446Swnj close(f); 3676446Swnj } 3686446Swnj if (found) { 36923566Sbloom f = open(wtmpf, O_WRONLY|O_APPEND); 3706446Swnj if (f >= 0) { 3716446Swnj SCPYN(wtmp.ut_line, line+5); 3726446Swnj SCPYN(wtmp.ut_name, ""); 37312681Ssam SCPYN(wtmp.ut_host, ""); 3746446Swnj time(&wtmp.ut_time); 3756446Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 3766446Swnj close(f); 3776446Swnj } 3786446Swnj } 3796446Swnj chmod(line, 0666); 3806446Swnj chown(line, 0, 0); 3816446Swnj line[strlen("/dev/")] = 'p'; 3826446Swnj chmod(line, 0666); 3836446Swnj chown(line, 0, 0); 3846446Swnj } 385