#ifndef lint static char sccsid[] = "@(#)rlogind.c 4.24 (Berkeley) 03/23/85"; #endif /* * remote login server: * remuser\0 * locuser\0 * terminal info\0 * data */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern errno; int reapchild(); struct passwd *getpwnam(); char *crypt(), *malloc(); main(argc, argv) int argc; char **argv; { int on = 1, options = 0, fromlen; struct sockaddr_in from; fromlen = sizeof (from); if (getpeername(0, &from, &fromlen) < 0) { fprintf(stderr, "%s: ", argv[0]); perror("getpeername"); _exit(1); } if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { openlog(argv[0], LOG_PID, 0); syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); } doit(0, &from); } int child; int cleanup(); int netf; extern errno; char *line; doit(f, fromp) int f; struct sockaddr_in *fromp; { int i, p, t, pid, on = 1; register struct hostent *hp; char c; alarm(60); read(f, &c, 1); if (c != 0) exit(1); alarm(0); fromp->sin_port = ntohs((u_short)fromp->sin_port); hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), fromp->sin_family); if (hp == 0) { char buf[BUFSIZ]; fatal(f, sprintf(buf, "Host name for your address (%s) unknown", inet_ntoa(fromp->sin_addr))); } if (fromp->sin_family != AF_INET || fromp->sin_port >= IPPORT_RESERVED) fatal(f, "Permission denied"); write(f, "", 1); for (c = 'p'; c <= 's'; c++) { struct stat stb; line = "/dev/ptyXX"; line[strlen("/dev/pty")] = c; line[strlen("/dev/ptyp")] = '0'; if (stat(line, &stb) < 0) break; for (i = 0; i < 16; i++) { line[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; p = open(line, 2); if (p > 0) goto gotpty; } } fatal(f, "All network ports in use"); /*NOTREACHED*/ gotpty: netf = f; line[strlen("/dev/")] = 't'; #ifdef DEBUG { int tt = open("/dev/tty", 2); if (tt > 0) { ioctl(tt, TIOCNOTTY, 0); close(tt); } } #endif t = open(line, 2); if (t < 0) fatalperror(f, line, errno); { struct sgttyb b; gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b); } pid = fork(); if (pid < 0) fatalperror(f, "", errno); if (pid == 0) { close(f), close(p); dup2(t, 0), dup2(t, 1), dup2(t, 2); close(t); execl("/bin/login", "login", "-r", hp->h_name, 0); fatalperror(2, "/bin/login", errno); /*NOTREACHED*/ } close(t); ioctl(f, FIONBIO, &on); ioctl(p, FIONBIO, &on); ioctl(p, TIOCPKT, &on); signal(SIGTSTP, SIG_IGN); signal(SIGCHLD, cleanup); protocol(f, p); cleanup(); } char magic[2] = { 0377, 0377 }; /* * Handle a "control" request (signaled by magic being present) * in the data stream. For now, we are only willing to handle * window size changes. */ control(pty, cp, n) int pty; char *cp; int n; { struct winsize *wp; if (n < 4+sizeof (*wp) || cp[2] != 's' || cp[3] != 's') return (0); wp = (struct winsize *)(cp+4); wp->ws_row = ntohs(wp->ws_row); wp->ws_col = ntohs(wp->ws_col); wp->ws_xpixel = ntohs(wp->ws_xpixel); wp->ws_ypixel = ntohs(wp->ws_ypixel); (void)ioctl(pty, TIOCSWINSZ, wp); return (4+sizeof (*wp)); } /* * rlogin "protocol" machine. */ protocol(f, p) int f, p; { char pibuf[1024], fibuf[1024], *pbp, *fbp; register pcc = 0, fcc = 0; int cc, stop = TIOCPKT_DOSTOP; /* * This is a hack for the TIOCSWINSZ calls * (csh pgrp manipulation appears to cause * trouble). */ (void) signal(SIGTTOU, SIG_IGN); /* XXX */ for (;;) { int ibits = 0, obits = 0; if (fcc) obits |= (1<= 0) if (pcc) obits |= (1< 0) bcopy(cp, cp+n, left); fcc -= n; goto top; /* n^2 */ } } } } if (ibits & (1< 0) { cc = write(f, pbp, pcc); if (cc < 0 && errno == EWOULDBLOCK) { /* also shouldn't happen */ sleep(5); continue; } if (cc > 0) { pcc -= cc; pbp += cc; } } if ((obits & (1< 0) { cc = write(p, fbp, fcc); if (cc > 0) { fcc -= cc; fbp += cc; } } } } cleanup() { rmut(); vhangup(); /* XXX */ shutdown(netf, 2); kill(0, SIGKILL); exit(1); } fatal(f, msg) int f; char *msg; { char buf[BUFSIZ]; buf[0] = '\01'; /* error indicator */ (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); (void) write(f, buf, strlen(buf)); exit(1); } fatalperror(f, msg, errno) int f; char *msg; int errno; { char buf[BUFSIZ]; extern int sys_nerr; extern char *sys_errlist[]; if ((unsigned)errno < sys_nerr) (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); else (void) sprintf(buf, "%s: Error %d", msg, errno); fatal(f, buf); } #include struct utmp wtmp; char wtmpf[] = "/usr/adm/wtmp"; char utmp[] = "/etc/utmp"; #define SCPYN(a, b) strncpy(a, b, sizeof(a)) #define SCMPN(a, b) strncmp(a, b, sizeof(a)) rmut() { register f; int found = 0; f = open(utmp, O_RDWR); if (f >= 0) { while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0) continue; lseek(f, -(long)sizeof(wtmp), L_INCR); SCPYN(wtmp.ut_name, ""); SCPYN(wtmp.ut_host, ""); time(&wtmp.ut_time); write(f, (char *)&wtmp, sizeof(wtmp)); found++; } close(f); } if (found) { f = open(wtmpf, O_WRONLY); if (f >= 0) { SCPYN(wtmp.ut_line, line+5); SCPYN(wtmp.ut_name, ""); SCPYN(wtmp.ut_host, ""); time(&wtmp.ut_time); lseek(f, (long)0, L_XTND); write(f, (char *)&wtmp, sizeof(wtmp)); close(f); } } chmod(line, 0666); chown(line, 0, 0); line[strlen("/dev/")] = 'p'; chmod(line, 0666); chown(line, 0, 0); }