16446Swnj #ifndef lint 2*16227Skarels static char sccsid[] = "@(#)rlogind.c 4.19 84/03/22"; 36446Swnj #endif 46446Swnj 56446Swnj #include <stdio.h> 66446Swnj #include <sys/types.h> 76446Swnj #include <sys/stat.h> 86446Swnj #include <sys/socket.h> 913554Ssam #include <sys/wait.h> 109208Ssam 119208Ssam #include <netinet/in.h> 129208Ssam 136446Swnj #include <errno.h> 146446Swnj #include <pwd.h> 156446Swnj #include <signal.h> 166446Swnj #include <sgtty.h> 176446Swnj #include <stdio.h> 188380Ssam #include <netdb.h> 196446Swnj 206446Swnj extern errno; 2110417Ssam int reapchild(); 226446Swnj struct passwd *getpwnam(); 2311345Ssam char *crypt(), *rindex(), *index(), *malloc(), *ntoa(); 248380Ssam struct sockaddr_in sin = { AF_INET }; 256446Swnj /* 266446Swnj * remote login server: 276446Swnj * remuser\0 286446Swnj * locuser\0 296446Swnj * terminal type\0 306446Swnj * data 316446Swnj */ 326446Swnj main(argc, argv) 336446Swnj int argc; 346446Swnj char **argv; 356446Swnj { 3612216Ssam int f, options = 0; 376446Swnj struct sockaddr_in from; 388380Ssam struct servent *sp; 396446Swnj 408380Ssam sp = getservbyname("login", "tcp"); 418380Ssam if (sp == 0) { 428380Ssam fprintf(stderr, "rlogind: tcp/rlogin: unknown service\n"); 438380Ssam exit(1); 448380Ssam } 456446Swnj #ifndef DEBUG 466446Swnj if (fork()) 476446Swnj exit(0); 486446Swnj for (f = 0; f < 10; f++) 496446Swnj (void) close(f); 506446Swnj (void) open("/", 0); 516446Swnj (void) dup2(0, 1); 526446Swnj (void) dup2(0, 2); 536446Swnj { int tt = open("/dev/tty", 2); 546446Swnj if (tt > 0) { 556446Swnj ioctl(tt, TIOCNOTTY, 0); 566446Swnj close(tt); 576446Swnj } 586446Swnj } 596446Swnj #endif 609961Ssam sin.sin_port = sp->s_port; 616446Swnj argc--, argv++; 629208Ssam if (argc > 0 && !strcmp(argv[0], "-d")) { 6310417Ssam options |= SO_DEBUG; 6410417Ssam argc--, argv++; 6510417Ssam } 6610417Ssam if (argc > 0) { 678380Ssam int port = atoi(argv[0]); 688380Ssam 698380Ssam if (port < 0) { 708380Ssam fprintf(stderr, "%s: bad port #\n", argv[0]); 718380Ssam exit(1); 728380Ssam } 739961Ssam sin.sin_port = htons((u_short)port); 748380Ssam argv++, argc--; 758380Ssam } 769259Ssam f = socket(AF_INET, SOCK_STREAM, 0, 0); 779208Ssam if (f < 0) { 789208Ssam perror("rlogind: socket"); 799208Ssam exit(1); 809208Ssam } 8110417Ssam if (options & SO_DEBUG) 8210417Ssam if (setsockopt(f, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 8310417Ssam perror("rlogind: setsockopt (SO_DEBUG)"); 8410417Ssam if (setsockopt(f, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0) 8512216Ssam perror("rlogind: setsockopt (SO_KEEPALIVE)"); 869208Ssam if (bind(f, &sin, sizeof (sin), 0) < 0) { 879208Ssam perror("rlogind: bind"); 889208Ssam exit(1); 899208Ssam } 9013024Ssam signal(SIGCHLD, reapchild); 919208Ssam listen(f, 10); 926446Swnj for (;;) { 939208Ssam int s, len = sizeof (from); 949208Ssam 959208Ssam s = accept(f, &from, &len, 0); 969208Ssam if (s < 0) { 9710417Ssam if (errno == EINTR) 9810417Ssam continue; 999242Ssam perror("rlogind: accept"); 1006446Swnj continue; 1016446Swnj } 10211222Ssam if (fork() == 0) { 10311222Ssam signal(SIGCHLD, SIG_IGN); 10413267Ssam close(f); 1059208Ssam doit(s, &from); 10611222Ssam } 1079208Ssam close(s); 1086446Swnj } 1096446Swnj } 1106446Swnj 11110417Ssam reapchild() 11210417Ssam { 11310417Ssam union wait status; 11410417Ssam 11510417Ssam while (wait3(&status, WNOHANG, 0) > 0) 11610417Ssam ; 11710417Ssam } 11810417Ssam 1196446Swnj char locuser[32], remuser[32]; 1206446Swnj char buf[BUFSIZ]; 1216446Swnj int child; 1226446Swnj int cleanup(); 1236446Swnj int netf; 1246446Swnj extern errno; 1256446Swnj char *line; 1266446Swnj 1276446Swnj doit(f, fromp) 1286446Swnj int f; 1296446Swnj struct sockaddr_in *fromp; 1306446Swnj { 1318380Ssam char c; 1329242Ssam int i, p, cc, t, pid; 1336446Swnj int stop = TIOCPKT_DOSTOP; 1348380Ssam register struct hostent *hp; 1356446Swnj 1366446Swnj alarm(60); 1376446Swnj read(f, &c, 1); 1386446Swnj if (c != 0) 1396446Swnj exit(1); 1406446Swnj alarm(0); 141*16227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 1428380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 1438380Ssam fromp->sin_family); 14411345Ssam if (hp == 0) { 145*16227Skarels char buf[BUFSIZ]; 14611345Ssam 14711345Ssam fatal(f, sprintf(buf, "Host name for your address (%s) unknown", 14811345Ssam ntoa(fromp->sin_addr))); 14911345Ssam } 1506446Swnj if (fromp->sin_family != AF_INET || 151*16227Skarels fromp->sin_port >= IPPORT_RESERVED) 1529242Ssam fatal(f, "Permission denied"); 1536446Swnj write(f, "", 1); 1546446Swnj for (c = 'p'; c <= 's'; c++) { 1556446Swnj struct stat stb; 1566446Swnj line = "/dev/ptyXX"; 1576446Swnj line[strlen("/dev/pty")] = c; 1586446Swnj line[strlen("/dev/ptyp")] = '0'; 1596446Swnj if (stat(line, &stb) < 0) 1606446Swnj break; 1616446Swnj for (i = 0; i < 16; i++) { 1626446Swnj line[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; 1636446Swnj p = open(line, 2); 1646446Swnj if (p > 0) 1656446Swnj goto gotpty; 1666446Swnj } 1676446Swnj } 1689242Ssam fatal(f, "All network ports in use"); 1699242Ssam /*NOTREACHED*/ 1706446Swnj gotpty: 171*16227Skarels netf = f; 1726446Swnj line[strlen("/dev/")] = 't'; 1736446Swnj #ifdef DEBUG 1746446Swnj { int tt = open("/dev/tty", 2); 1756446Swnj if (tt > 0) { 1766446Swnj ioctl(tt, TIOCNOTTY, 0); 1776446Swnj close(tt); 1786446Swnj } 1796446Swnj } 1806446Swnj #endif 1816446Swnj t = open(line, 2); 1829242Ssam if (t < 0) 1839242Ssam fatalperror(f, line, errno); 1846446Swnj { struct sgttyb b; 1856446Swnj gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b); 1866446Swnj } 1879242Ssam pid = fork(); 1889242Ssam if (pid < 0) 1899242Ssam fatalperror(f, "", errno); 1909242Ssam if (pid) { 1916446Swnj char pibuf[1024], fibuf[1024], *pbp, *fbp; 192*16227Skarels register pcc = 0, fcc = 0; 193*16227Skarels int on = 1; 1946446Swnj /* FILE *console = fopen("/dev/console", "w"); */ 1956446Swnj /* setbuf(console, 0); */ 1966446Swnj 1976446Swnj /* fprintf(console, "f %d p %d\r\n", f, p); */ 198*16227Skarels close(t); 1996446Swnj ioctl(f, FIONBIO, &on); 2006446Swnj ioctl(p, FIONBIO, &on); 2016446Swnj ioctl(p, TIOCPKT, &on); 2026446Swnj signal(SIGTSTP, SIG_IGN); 20313024Ssam signal(SIGCHLD, cleanup); 2046446Swnj for (;;) { 2056446Swnj int ibits = 0, obits = 0; 2069242Ssam 2079242Ssam if (fcc) 2089242Ssam obits |= (1<<p); 2099242Ssam else 2109242Ssam ibits |= (1<<f); 2116446Swnj if (pcc >= 0) 2129242Ssam if (pcc) 2139242Ssam obits |= (1<<f); 2149242Ssam else 2159242Ssam ibits |= (1<<p); 2166446Swnj /* fprintf(console, "ibits from %d obits from %d\r\n", ibits, obits); */ 217*16227Skarels if (select(16, &ibits, &obits, 0, 0) < 0) { 218*16227Skarels if (errno == EINTR) 219*16227Skarels continue; 220*16227Skarels fatalperror(f, "select", errno); 221*16227Skarels } 2226446Swnj /* fprintf(console, "ibits %d obits %d\r\n", ibits, obits); */ 2236446Swnj if (ibits == 0 && obits == 0) { 224*16227Skarels /* shouldn't happen... */ 2256446Swnj sleep(5); 2266446Swnj continue; 2276446Swnj } 2286446Swnj if (ibits & (1<<f)) { 2296446Swnj fcc = read(f, fibuf, sizeof (fibuf)); 2306446Swnj /* fprintf(console, "%d from f\r\n", fcc); */ 2316446Swnj if (fcc < 0 && errno == EWOULDBLOCK) 2326446Swnj fcc = 0; 2336446Swnj else { 2346446Swnj if (fcc <= 0) 2356446Swnj break; 2366446Swnj fbp = fibuf; 2376446Swnj } 2386446Swnj } 2396446Swnj if (ibits & (1<<p)) { 2406446Swnj pcc = read(p, pibuf, sizeof (pibuf)); 2416446Swnj /* fprintf(console, "%d from p, buf[0] %x, errno %d\r\n", pcc, buf[0], errno); */ 2426446Swnj pbp = pibuf; 2436446Swnj if (pcc < 0 && errno == EWOULDBLOCK) 2446446Swnj pcc = 0; 2456446Swnj else if (pcc <= 0) 246*16227Skarels break; 2476446Swnj else if (pibuf[0] == 0) 2486446Swnj pbp++, pcc--; 2496446Swnj else { 2506446Swnj if (pibuf[0]&(TIOCPKT_FLUSHWRITE| 2516446Swnj TIOCPKT_NOSTOP| 2526446Swnj TIOCPKT_DOSTOP)) { 253*16227Skarels /* The following 3 lines do nothing. */ 2546446Swnj int nstop = pibuf[0] & 2556446Swnj (TIOCPKT_NOSTOP| 2566446Swnj TIOCPKT_DOSTOP); 2576446Swnj if (nstop) 2586446Swnj stop = nstop; 2596446Swnj pibuf[0] |= nstop; 26012898Ssam send(f,&pibuf[0],1,MSG_OOB); 2616446Swnj } 2626446Swnj pcc = 0; 2636446Swnj } 2646446Swnj } 2656446Swnj if ((obits & (1<<f)) && pcc > 0) { 2666446Swnj cc = write(f, pbp, pcc); 267*16227Skarels if (cc < 0 && errno == EWOULDBLOCK) { 268*16227Skarels /* also shouldn't happen */ 269*16227Skarels sleep(5); 270*16227Skarels continue; 271*16227Skarels } 2726446Swnj /* fprintf(console, "%d of %d to f\r\n", cc, pcc); */ 2736446Swnj if (cc > 0) { 2746446Swnj pcc -= cc; 2756446Swnj pbp += cc; 2766446Swnj } 2776446Swnj } 2786446Swnj if ((obits & (1<<p)) && fcc > 0) { 2796446Swnj cc = write(p, fbp, fcc); 2806446Swnj /* fprintf(console, "%d of %d to p\r\n", cc, fcc); */ 2816446Swnj if (cc > 0) { 2826446Swnj fcc -= cc; 2836446Swnj fbp += cc; 2846446Swnj } 2856446Swnj } 2866446Swnj } 2876446Swnj cleanup(); 2886446Swnj } 2896446Swnj close(f); 2906446Swnj close(p); 2916446Swnj dup2(t, 0); 2926446Swnj dup2(t, 1); 2936446Swnj dup2(t, 2); 2946446Swnj close(t); 2958380Ssam execl("/bin/login", "login", "-r", hp->h_name, 0); 2969242Ssam fatalperror(2, "/bin/login", errno); 2979242Ssam /*NOTREACHED*/ 2986446Swnj } 2996446Swnj 3006446Swnj cleanup() 3016446Swnj { 3026446Swnj 3036446Swnj rmut(); 30410009Ssam vhangup(); /* XXX */ 30510192Ssam shutdown(netf, 2); 3066446Swnj kill(0, SIGKILL); 3076446Swnj exit(1); 3086446Swnj } 3096446Swnj 3109242Ssam fatal(f, msg) 3119242Ssam int f; 3129242Ssam char *msg; 3139242Ssam { 3149242Ssam char buf[BUFSIZ]; 3159242Ssam 3169242Ssam buf[0] = '\01'; /* error indicator */ 31713554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 3189242Ssam (void) write(f, buf, strlen(buf)); 3199242Ssam exit(1); 3209242Ssam } 3219242Ssam 3229242Ssam fatalperror(f, msg, errno) 3239242Ssam int f; 3249242Ssam char *msg; 3259242Ssam int errno; 3269242Ssam { 3279242Ssam char buf[BUFSIZ]; 328*16227Skarels extern int sys_nerr; 3299242Ssam extern char *sys_errlist[]; 3309242Ssam 331*16227Skarels if ((unsigned) errno < sys_nerr) 332*16227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 333*16227Skarels else 334*16227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 3359242Ssam fatal(f, buf); 3369242Ssam } 3379242Ssam 3386446Swnj #include <utmp.h> 3396446Swnj 3406446Swnj struct utmp wtmp; 3416446Swnj char wtmpf[] = "/usr/adm/wtmp"; 3426446Swnj char utmp[] = "/etc/utmp"; 3436446Swnj #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 3446446Swnj #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 3456446Swnj 3466446Swnj rmut() 3476446Swnj { 3486446Swnj register f; 3496446Swnj int found = 0; 3506446Swnj 3516446Swnj f = open(utmp, 2); 3526446Swnj if (f >= 0) { 3536446Swnj while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { 3546446Swnj if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0) 3556446Swnj continue; 3566446Swnj lseek(f, -(long)sizeof(wtmp), 1); 3576446Swnj SCPYN(wtmp.ut_name, ""); 35812681Ssam SCPYN(wtmp.ut_host, ""); 3596446Swnj time(&wtmp.ut_time); 3606446Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 3616446Swnj found++; 3626446Swnj } 3636446Swnj close(f); 3646446Swnj } 3656446Swnj if (found) { 3666446Swnj f = open(wtmpf, 1); 3676446Swnj if (f >= 0) { 3686446Swnj SCPYN(wtmp.ut_line, line+5); 3696446Swnj SCPYN(wtmp.ut_name, ""); 37012681Ssam SCPYN(wtmp.ut_host, ""); 3716446Swnj time(&wtmp.ut_time); 3726446Swnj lseek(f, (long)0, 2); 3736446Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 3746446Swnj close(f); 3756446Swnj } 3766446Swnj } 3776446Swnj chmod(line, 0666); 3786446Swnj chown(line, 0, 0); 3796446Swnj line[strlen("/dev/")] = 'p'; 3806446Swnj chmod(line, 0666); 3816446Swnj chown(line, 0, 0); 3826446Swnj } 38311345Ssam 38411345Ssam /* 38511345Ssam * Convert network-format internet address 38611345Ssam * to base 256 d.d.d.d representation. 38711345Ssam */ 38811345Ssam char * 38911345Ssam ntoa(in) 39011345Ssam struct in_addr in; 39111345Ssam { 39211345Ssam static char b[18]; 39311345Ssam register char *p; 39411345Ssam 39511345Ssam p = (char *)∈ 39611345Ssam #define UC(b) (((int)b)&0xff) 39711345Ssam sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3])); 39811345Ssam return (b); 39911345Ssam } 400