121174Sdist /* 240917Skarels * Copyright (c) 1983, 1988, 1989 The Regents of the University of California. 335441Sbostic * All rights reserved. 435441Sbostic * 535441Sbostic * Redistribution and use in source and binary forms are permitted 635441Sbostic * provided that the above copyright notice and this paragraph are 735441Sbostic * duplicated in all such forms and that any documentation, 835441Sbostic * advertising materials, and other materials related to such 935441Sbostic * distribution and use acknowledge that the software was developed 1035441Sbostic * by the University of California, Berkeley. The name of the 1135441Sbostic * University may not be used to endorse or promote products derived 1235441Sbostic * from this software without specific prior written permission. 1335441Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435441Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535441Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621174Sdist */ 1721174Sdist 186446Swnj #ifndef lint 1921174Sdist char copyright[] = 2040917Skarels "@(#) Copyright (c) 1983, 1988, 1989 The Regents of the University of California.\n\ 2121174Sdist All rights reserved.\n"; 2235441Sbostic #endif /* not lint */ 236446Swnj 2421174Sdist #ifndef lint 25*44347Skarels static char sccsid[] = "@(#)rlogind.c 5.47 (Berkeley) 06/27/90"; 2635441Sbostic #endif /* not lint */ 2721174Sdist 2840917Skarels #ifdef KERBEROS 2940917Skarels /* From: 3040917Skarels * $Source: /mit/kerberos/ucb/mit/rlogind/RCS/rlogind.c,v $ 3140917Skarels * $Header: rlogind.c,v 5.0 89/06/26 18:31:01 kfall Locked $ 3240917Skarels */ 3340917Skarels #endif 3440917Skarels 3516369Skarels /* 3616369Skarels * remote login server: 3736453Skfall * \0 3816369Skarels * remuser\0 3916369Skarels * locuser\0 4036453Skfall * terminal_type/speed\0 4136518Skarels * data 4216369Skarels */ 4316369Skarels 4440917Skarels #define FD_SETSIZE 16 /* don't need many bits for select */ 4537290Sbostic #include <sys/param.h> 466446Swnj #include <sys/stat.h> 476446Swnj #include <sys/socket.h> 4813554Ssam #include <sys/wait.h> 4918357Ssam #include <sys/file.h> 5040917Skarels #include <sys/signal.h> 5137290Sbostic #include <sys/ioctl.h> 5237290Sbostic #include <sys/termios.h> 539208Ssam 549208Ssam #include <netinet/in.h> 55*44347Skarels #include <netinet/in_systm.h> 56*44347Skarels #include <netinet/ip.h> 579208Ssam 586446Swnj #include <errno.h> 596446Swnj #include <pwd.h> 608380Ssam #include <netdb.h> 6117187Sralph #include <syslog.h> 6242030Sbostic #include <string.h> 6340917Skarels #include <stdio.h> 6440917Skarels #include <unistd.h> 6540917Skarels #include "pathnames.h" 666446Swnj 6736518Skarels #ifndef TIOCPKT_WINDOW 6836518Skarels #define TIOCPKT_WINDOW 0x80 6936518Skarels #endif 7036518Skarels 7140917Skarels #ifdef KERBEROS 7241761Skfall #include <kerberosIV/des.h> 7340917Skarels #include <kerberosIV/krb.h> 7440917Skarels #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 7540917Skarels 7640917Skarels AUTH_DAT *kdata; 7740917Skarels KTEXT ticket; 7840917Skarels u_char auth_buf[sizeof(AUTH_DAT)]; 7940917Skarels u_char tick_buf[sizeof(KTEXT_ST)]; 8040917Skarels Key_schedule schedule; 8140917Skarels int encrypt = 0, retval, use_kerberos = 0, vacuous = 0; 8240917Skarels 8340917Skarels #define ARGSTR "alnkvx" 8440917Skarels #else 8540917Skarels #define ARGSTR "aln" 8640917Skarels #endif /* KERBEROS */ 8740917Skarels 8836518Skarels char *env[2]; 8936518Skarels #define NMAX 30 9036517Skarels char lusername[NMAX+1], rusername[NMAX+1]; 9136517Skarels static char term[64] = "TERM="; 9236517Skarels #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 9336517Skarels int keepalive = 1; 9439058Skarels int check_all = 0; 9536453Skfall 9634424Sbostic extern int errno; 9710417Ssam int reapchild(); 9836453Skfall struct passwd *getpwnam(), *pwd; 9924723Smckusick char *malloc(); 10016369Skarels 1016446Swnj main(argc, argv) 1026446Swnj int argc; 1036446Swnj char **argv; 1046446Swnj { 10540917Skarels extern int opterr, optind; 10640917Skarels extern int _check_rhosts_file; 10736319Sbostic int ch; 10834424Sbostic int on = 1, fromlen; 1096446Swnj struct sockaddr_in from; 1106446Swnj 11136625Skfall openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 11236319Sbostic 11336319Sbostic opterr = 0; 11440917Skarels while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 11536517Skarels switch (ch) { 11639058Skarels case 'a': 11739058Skarels check_all = 1; 11839058Skarels break; 11936319Sbostic case 'l': 12036319Sbostic _check_rhosts_file = 0; 12136319Sbostic break; 12236517Skarels case 'n': 12336517Skarels keepalive = 0; 12436517Skarels break; 12540917Skarels #ifdef KERBEROS 12640917Skarels case 'k': 12740917Skarels use_kerberos = 1; 12840917Skarels break; 12940917Skarels case 'v': 13040917Skarels vacuous = 1; 13140917Skarels break; 13240917Skarels case 'x': 13340917Skarels encrypt = 1; 13440917Skarels break; 13540917Skarels #endif 13636319Sbostic case '?': 13736319Sbostic default: 13840917Skarels usage(); 13936319Sbostic break; 14036319Sbostic } 14136319Sbostic argc -= optind; 14236319Sbostic argv += optind; 14336319Sbostic 14440917Skarels #ifdef KERBEROS 14540917Skarels if (use_kerberos && vacuous) { 14640917Skarels usage(); 14740917Skarels fatal(STDERR_FILENO, "only one of -k and -v allowed", 0); 14840917Skarels } 14940917Skarels #endif 15016369Skarels fromlen = sizeof (from); 15116369Skarels if (getpeername(0, &from, &fromlen) < 0) { 15240917Skarels syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 15340917Skarels fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 1548380Ssam } 15536517Skarels if (keepalive && 15636517Skarels setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 15717187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 158*44347Skarels on = IPTOS_LOWDELAY; 159*44347Skarels if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 160*44347Skarels syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 16116369Skarels doit(0, &from); 1626446Swnj } 1636446Swnj 1646446Swnj int child; 1656446Swnj int cleanup(); 1666446Swnj int netf; 1676446Swnj char *line; 16840917Skarels int confirmed; 16924724Smckusick extern char *inet_ntoa(); 1706446Swnj 17124889Smckusick struct winsize win = { 0, 0, 0, 0 }; 17224723Smckusick 17324889Smckusick 1746446Swnj doit(f, fromp) 1756446Swnj int f; 1766446Swnj struct sockaddr_in *fromp; 1776446Swnj { 17818357Ssam int i, p, t, pid, on = 1; 17936631Skarels int authenticated = 0, hostok = 0; 18040917Skarels register struct hostent *hp; 18139249Smarc char remotehost[2 * MAXHOSTNAMELEN + 1]; 18224724Smckusick struct hostent hostent; 1838380Ssam char c; 1846446Swnj 1856446Swnj alarm(60); 1866446Swnj read(f, &c, 1); 18740917Skarels 18839249Smarc if (c != 0) 18936715Skfall exit(1); 19040917Skarels #ifdef KERBEROS 19140917Skarels if (vacuous) 19240917Skarels fatal(f, "Remote host requires Kerberos authentication", 0); 19340917Skarels #endif 19436453Skfall 1956446Swnj alarm(0); 19616227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 1978380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 1988380Ssam fromp->sin_family); 19911345Ssam if (hp == 0) { 20024724Smckusick /* 20124724Smckusick * Only the name is used below. 20224724Smckusick */ 20324724Smckusick hp = &hostent; 20424724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 20536635Skarels hostok++; 20640917Skarels } else if (check_all || local_domain(hp->h_name)) { 20736635Skarels /* 20836635Skarels * If name returned by gethostbyaddr is in our domain, 20936635Skarels * attempt to verify that we haven't been fooled by someone 21036635Skarels * in a remote net; look up the name and check that this 21136635Skarels * address corresponds to the name. 21236635Skarels */ 21336635Skarels strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 21436635Skarels remotehost[sizeof(remotehost) - 1] = 0; 21536635Skarels hp = gethostbyname(remotehost); 21636635Skarels if (hp) 21736635Skarels for (; hp->h_addr_list[0]; hp->h_addr_list++) 21836635Skarels if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 21936635Skarels sizeof(fromp->sin_addr))) { 22036635Skarels hostok++; 22136635Skarels break; 22236635Skarels } 22336633Skarels } else 22436635Skarels hostok++; 22536711Skfall 22640917Skarels #ifdef KERBEROS 22740917Skarels if (use_kerberos) { 22842264Sbostic if (!hostok) 229*44347Skarels fatal(f, "rlogind: Host address mismatch.", 0); 23040917Skarels retval = do_krb_login(hp->h_name, fromp, encrypt); 23142264Sbostic if (retval == 0) 23240917Skarels authenticated++; 23340917Skarels else if (retval > 0) 23440917Skarels fatal(f, krb_err_txt[retval], 0); 23540917Skarels write(f, &c, 1); 23640917Skarels confirmed = 1; /* we sent the null! */ 23740917Skarels } else 23840917Skarels #endif 23940917Skarels { 24040917Skarels if (fromp->sin_family != AF_INET || 24140917Skarels fromp->sin_port >= IPPORT_RESERVED || 24240917Skarels fromp->sin_port < IPPORT_RESERVED/2) { 24340917Skarels syslog(LOG_NOTICE, "Connection from %s on illegal port", 24440917Skarels inet_ntoa(fromp->sin_addr)); 24540917Skarels fatal(f, "Permission denied", 0); 24640917Skarels } 24736702Skarels #ifdef IP_OPTIONS 24840917Skarels { 24940917Skarels u_char optbuf[BUFSIZ/3], *cp; 25040917Skarels char lbuf[BUFSIZ], *lp; 25140917Skarels int optsize = sizeof(optbuf), ipproto; 25240917Skarels struct protoent *ip; 25336702Skarels 25440917Skarels if ((ip = getprotobyname("ip")) != NULL) 25540917Skarels ipproto = ip->p_proto; 25640917Skarels else 25740917Skarels ipproto = IPPROTO_IP; 25840917Skarels if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 25940917Skarels &optsize) == 0 && optsize != 0) { 26040917Skarels lp = lbuf; 26140917Skarels for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 26240917Skarels sprintf(lp, " %2.2x", *cp); 26340917Skarels syslog(LOG_NOTICE, 26440917Skarels "Connection received using IP options (ignored):%s", 26540917Skarels lbuf); 26640917Skarels if (setsockopt(0, ipproto, IP_OPTIONS, 26740917Skarels (char *)NULL, &optsize) != 0) { 26840917Skarels syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 26940917Skarels exit(1); 27040917Skarels } 27140917Skarels } 27240917Skarels } 27336702Skarels #endif 27440917Skarels if (do_rlogin(hp->h_name) == 0 && hostok) 27539249Smarc authenticated++; 27636631Skarels } 27736636Skarels 2786446Swnj for (c = 'p'; c <= 's'; c++) { 2796446Swnj struct stat stb; 2806446Swnj line = "/dev/ptyXX"; 2816446Swnj line[strlen("/dev/pty")] = c; 2826446Swnj line[strlen("/dev/ptyp")] = '0'; 2836446Swnj if (stat(line, &stb) < 0) 2846446Swnj break; 2856446Swnj for (i = 0; i < 16; i++) { 28634424Sbostic line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 28734424Sbostic p = open(line, O_RDWR); 2886446Swnj if (p > 0) 2896446Swnj goto gotpty; 2906446Swnj } 2916446Swnj } 29240917Skarels fatal(f, "Out of ptys", 0); 2939242Ssam /*NOTREACHED*/ 2946446Swnj gotpty: 29524889Smckusick (void) ioctl(p, TIOCSWINSZ, &win); 29616227Skarels netf = f; 29740917Skarels line[sizeof(_PATH_DEV) - 1] = 't'; 29834424Sbostic t = open(line, O_RDWR); 29934424Sbostic if (t < 0) 30040917Skarels fatal(f, line, 1); 30134424Sbostic if (fchmod(t, 0)) 30240917Skarels fatal(f, line, 1); 30334424Sbostic (void)signal(SIGHUP, SIG_IGN); 30443363Skfall #ifdef notdef 30543363Skfall vhangup(); 30643363Skfall #endif 30734424Sbostic (void)signal(SIGHUP, SIG_DFL); 30834424Sbostic t = open(line, O_RDWR); 30934424Sbostic if (t < 0) 31040917Skarels fatal(f, line, 1); 31136453Skfall setup_term(t); 31240917Skarels if (confirmed == 0) { 31340917Skarels write(f, "", 1); 31440917Skarels confirmed = 1; /* we sent the null! */ 31539249Smarc } 31640917Skarels #ifdef KERBEROS 31740917Skarels if (encrypt) 31840917Skarels (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 31940917Skarels 32040917Skarels if (use_kerberos == 0) 32139249Smarc #endif 32240917Skarels if (!authenticated && !hostok) 32340917Skarels write(f, "rlogind: Host address mismatch.\r\n", 32440917Skarels sizeof("rlogind: Host address mismatch.\r\n") - 1); 32540917Skarels 3269242Ssam pid = fork(); 3279242Ssam if (pid < 0) 32840917Skarels fatal(f, "", 1); 32918357Ssam if (pid == 0) { 33036711Skfall if (setsid() < 0) 33140917Skarels fatal(f, "setsid", 1); 33236711Skfall if (ioctl(t, TIOCSCTTY, 0) < 0) 33340917Skarels fatal(f, "ioctl(sctty)", 1); 33440917Skarels (void)close(f); 33540917Skarels (void)close(p); 33640917Skarels dup2(t, STDIN_FILENO); 33740917Skarels dup2(t, STDOUT_FILENO); 33840917Skarels dup2(t, STDERR_FILENO); 33940917Skarels (void)close(t); 34040917Skarels 34143363Skfall if (authenticated) { 342*44347Skarels #ifdef KERBEROS 34343363Skfall if (use_kerberos && (pwd->pw_uid == 0)) 34443363Skfall syslog(LOG_INFO|LOG_AUTH, 34543363Skfall "ROOT Kerberos login from %s.%s@%s on %s\n", 34643363Skfall kdata->pname, kdata->pinst, kdata->prealm, 34743363Skfall hp->h_name); 348*44347Skarels #endif 34943363Skfall 35040917Skarels execl(_PATH_LOGIN, "login", "-p", 35140917Skarels "-h", hp->h_name, "-f", lusername, 0); 35243363Skfall } else 35340917Skarels execl(_PATH_LOGIN, "login", "-p", 35440917Skarels "-h", hp->h_name, lusername, 0); 35540917Skarels fatal(STDERR_FILENO, _PATH_LOGIN, 1); 35618357Ssam /*NOTREACHED*/ 35718357Ssam } 35818357Ssam close(t); 35936453Skfall 36040917Skarels #ifdef KERBEROS 36140917Skarels /* 36240917Skarels * If encrypted, don't turn on NBIO or the des read/write 36340917Skarels * routines will croak. 36440917Skarels */ 36540917Skarels 36640917Skarels if (!encrypt) 36740917Skarels #endif 36840917Skarels ioctl(f, FIONBIO, &on); 36918357Ssam ioctl(p, FIONBIO, &on); 37018357Ssam ioctl(p, TIOCPKT, &on); 37118357Ssam signal(SIGCHLD, cleanup); 37218357Ssam protocol(f, p); 37330600Smckusick signal(SIGCHLD, SIG_IGN); 37418357Ssam cleanup(); 37518357Ssam } 3769242Ssam 37718357Ssam char magic[2] = { 0377, 0377 }; 37825423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 37918357Ssam 38018357Ssam /* 38118357Ssam * Handle a "control" request (signaled by magic being present) 38218357Ssam * in the data stream. For now, we are only willing to handle 38318357Ssam * window size changes. 38418357Ssam */ 38518357Ssam control(pty, cp, n) 38618357Ssam int pty; 38718357Ssam char *cp; 38818357Ssam int n; 38918357Ssam { 39028705Smckusick struct winsize w; 39118357Ssam 39228705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 39318357Ssam return (0); 39425423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 39528705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 39628705Smckusick w.ws_row = ntohs(w.ws_row); 39728705Smckusick w.ws_col = ntohs(w.ws_col); 39828705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 39928705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 40028705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 40128705Smckusick return (4+sizeof (w)); 40218357Ssam } 40318357Ssam 40418357Ssam /* 40518357Ssam * rlogin "protocol" machine. 40618357Ssam */ 40718357Ssam protocol(f, p) 40840917Skarels register int f, p; 40918357Ssam { 41040917Skarels char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 41118357Ssam register pcc = 0, fcc = 0; 41240917Skarels int cc, nfd, n; 41325740Skarels char cntl; 41418357Ssam 41518482Ssam /* 41618484Ssam * Must ignore SIGTTOU, otherwise we'll stop 41718484Ssam * when we try and set slave pty's window shape 41825423Skarels * (our controlling tty is the master pty). 41918482Ssam */ 42018484Ssam (void) signal(SIGTTOU, SIG_IGN); 42125423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 42236517Skarels if (f > p) 42336517Skarels nfd = f + 1; 42436517Skarels else 42536517Skarels nfd = p + 1; 42640917Skarels if (nfd > FD_SETSIZE) { 42740917Skarels syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 42840917Skarels fatal(f, "internal error (select mask too small)", 0); 42940917Skarels } 43018357Ssam for (;;) { 43140917Skarels fd_set ibits, obits, ebits, *omask; 43218357Ssam 43342956Sbostic FD_ZERO(&ebits); 43440917Skarels FD_ZERO(&ibits); 43540917Skarels FD_ZERO(&obits); 43640917Skarels omask = (fd_set *)NULL; 43740917Skarels if (fcc) { 43840917Skarels FD_SET(p, &obits); 43940917Skarels omask = &obits; 44040917Skarels } else 44140917Skarels FD_SET(f, &ibits); 44218357Ssam if (pcc >= 0) 44340917Skarels if (pcc) { 44440917Skarels FD_SET(f, &obits); 44540917Skarels omask = &obits; 44640917Skarels } else 44740917Skarels FD_SET(p, &ibits); 44840917Skarels FD_SET(p, &ebits); 44940917Skarels if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 45018357Ssam if (errno == EINTR) 4516446Swnj continue; 45240917Skarels fatal(f, "select", 1); 45318357Ssam } 45440917Skarels if (n == 0) { 45518357Ssam /* shouldn't happen... */ 45618357Ssam sleep(5); 45718357Ssam continue; 45818357Ssam } 45925740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 46040917Skarels if (FD_ISSET(p, &ebits)) { 46125740Skarels cc = read(p, &cntl, 1); 46225740Skarels if (cc == 1 && pkcontrol(cntl)) { 46325740Skarels cntl |= oobdata[0]; 46425740Skarels send(f, &cntl, 1, MSG_OOB); 46525740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 46625740Skarels pcc = 0; 46740917Skarels FD_CLR(p, &ibits); 46825740Skarels } 46925740Skarels } 47025740Skarels } 47140917Skarels if (FD_ISSET(f, &ibits)) { 47240917Skarels #ifdef KERBEROS 47340917Skarels if (encrypt) 47440917Skarels fcc = des_read(f, fibuf, sizeof(fibuf)); 47540917Skarels else 47640917Skarels #endif 47740917Skarels fcc = read(f, fibuf, sizeof(fibuf)); 47818357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 47918357Ssam fcc = 0; 48018357Ssam else { 48118357Ssam register char *cp; 48218357Ssam int left, n; 48318357Ssam 48418357Ssam if (fcc <= 0) 48516227Skarels break; 48618357Ssam fbp = fibuf; 48724723Smckusick 48818357Ssam top: 48925423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 49018357Ssam if (cp[0] == magic[0] && 49118357Ssam cp[1] == magic[1]) { 49218357Ssam left = fcc - (cp-fibuf); 49318357Ssam n = control(p, cp, left); 49418357Ssam if (n) { 49518357Ssam left -= n; 49618357Ssam if (left > 0) 49725423Skarels bcopy(cp+n, cp, left); 49818357Ssam fcc -= n; 49918357Ssam goto top; /* n^2 */ 50025423Skarels } 50125423Skarels } 50240917Skarels FD_SET(p, &obits); /* try write */ 50325423Skarels } 50425423Skarels } 50524723Smckusick 50640917Skarels if (FD_ISSET(p, &obits) && fcc > 0) { 50725423Skarels cc = write(p, fbp, fcc); 50824723Smckusick if (cc > 0) { 50924723Smckusick fcc -= cc; 51024723Smckusick fbp += cc; 5116446Swnj } 51218357Ssam } 51324723Smckusick 51440917Skarels if (FD_ISSET(p, &ibits)) { 51518357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 51618357Ssam pbp = pibuf; 51718357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 51818357Ssam pcc = 0; 51918357Ssam else if (pcc <= 0) 52018357Ssam break; 52136517Skarels else if (pibuf[0] == 0) { 52218357Ssam pbp++, pcc--; 52340917Skarels #ifdef KERBEROS 52440917Skarels if (!encrypt) 52540917Skarels #endif 52640917Skarels FD_SET(f, &obits); /* try write */ 52736517Skarels } else { 52818357Ssam if (pkcontrol(pibuf[0])) { 52925423Skarels pibuf[0] |= oobdata[0]; 53018357Ssam send(f, &pibuf[0], 1, MSG_OOB); 53116227Skarels } 53218357Ssam pcc = 0; 5336446Swnj } 53418357Ssam } 53540917Skarels if ((FD_ISSET(f, &obits)) && pcc > 0) { 53640917Skarels #ifdef KERBEROS 53740917Skarels if (encrypt) 53840917Skarels cc = des_write(f, pbp, pcc); 53940917Skarels else 54040917Skarels #endif 54140917Skarels cc = write(f, pbp, pcc); 54225423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 54340917Skarels /* 54440917Skarels * This happens when we try write after read 54540917Skarels * from p, but some old kernels balk at large 54640917Skarels * writes even when select returns true. 54740917Skarels */ 54840917Skarels if (!FD_ISSET(p, &ibits)) 54940917Skarels sleep(5); 55025423Skarels continue; 55125423Skarels } 55218357Ssam if (cc > 0) { 55318357Ssam pcc -= cc; 55418357Ssam pbp += cc; 55518357Ssam } 5566446Swnj } 5576446Swnj } 5586446Swnj } 5596446Swnj 5606446Swnj cleanup() 5616446Swnj { 56235440Sbostic char *p; 56335440Sbostic 56440917Skarels p = line + sizeof(_PATH_DEV) - 1; 56535440Sbostic if (logout(p)) 56635440Sbostic logwtmp(p, "", ""); 56735440Sbostic (void)chmod(line, 0666); 56835440Sbostic (void)chown(line, 0, 0); 56935440Sbostic *p = 'p'; 57035440Sbostic (void)chmod(line, 0666); 57135440Sbostic (void)chown(line, 0, 0); 57210192Ssam shutdown(netf, 2); 5736446Swnj exit(1); 5746446Swnj } 5756446Swnj 57640917Skarels fatal(f, msg, syserr) 57740917Skarels int f, syserr; 5789242Ssam char *msg; 5799242Ssam { 58040917Skarels int len; 58140917Skarels char buf[BUFSIZ], *bp = buf; 5829242Ssam 58340917Skarels /* 58440917Skarels * Prepend binary one to message if we haven't sent 58540917Skarels * the magic null as confirmation. 58640917Skarels */ 58740917Skarels if (!confirmed) 58840917Skarels *bp++ = '\01'; /* error indicator */ 58940917Skarels if (syserr) 59040917Skarels len = sprintf(bp, "rlogind: %s: %s.\r\n", 59140917Skarels msg, strerror(errno)); 59240917Skarels else 59340917Skarels len = sprintf(bp, "rlogind: %s.\r\n", msg); 59440917Skarels (void) write(f, buf, bp + len - buf); 5959242Ssam exit(1); 5969242Ssam } 5979242Ssam 59836453Skfall do_rlogin(host) 59936518Skarels char *host; 60036453Skfall { 60136518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 60236518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 60336518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 60436518Skarels 60536453Skfall pwd = getpwnam(lusername); 60636518Skarels if (pwd == NULL) 60736453Skfall return(-1); 60842264Sbostic if (pwd->pw_uid == 0) 60942264Sbostic return(-1); 61042264Sbostic return(ruserok(host, 0, rusername, lusername)); 61136453Skfall } 61236453Skfall 61336453Skfall 61436518Skarels getstr(buf, cnt, errmsg) 61536518Skarels char *buf; 61636518Skarels int cnt; 61736518Skarels char *errmsg; 61836453Skfall { 61936518Skarels char c; 62036518Skarels 62136453Skfall do { 62236518Skarels if (read(0, &c, 1) != 1) 62336453Skfall exit(1); 62436518Skarels if (--cnt < 0) 62540917Skarels fatal(STDOUT_FILENO, errmsg, 0); 62636453Skfall *buf++ = c; 62736518Skarels } while (c != 0); 62836453Skfall } 62936453Skfall 63036518Skarels extern char **environ; 63136453Skfall 63236519Skarels setup_term(fd) 63336519Skarels int fd; 63436519Skarels { 63540917Skarels register char *cp = index(term+ENVSIZE, '/'); 63636519Skarels char *speed; 63739118Skarels struct termios tt; 63836519Skarels 63940917Skarels #ifndef notyet 64036711Skfall tcgetattr(fd, &tt); 64136519Skarels if (cp) { 64236519Skarels *cp++ = '\0'; 64336519Skarels speed = cp; 64436519Skarels cp = index(speed, '/'); 64536519Skarels if (cp) 64636519Skarels *cp++ = '\0'; 64736711Skfall cfsetspeed(&tt, atoi(speed)); 64836519Skarels } 64938710Skfall 65039118Skarels tt.c_iflag = TTYDEF_IFLAG; 65139118Skarels tt.c_oflag = TTYDEF_OFLAG; 65239118Skarels tt.c_lflag = TTYDEF_LFLAG; 65343272Sbostic tcsetattr(fd, TCSAFLUSH, &tt); 65439118Skarels #else 65539118Skarels if (cp) { 65639118Skarels *cp++ = '\0'; 65739118Skarels speed = cp; 65839118Skarels cp = index(speed, '/'); 65939118Skarels if (cp) 66039118Skarels *cp++ = '\0'; 66140917Skarels tcgetattr(fd, &tt); 66240917Skarels cfsetspeed(&tt, atoi(speed)); 66343272Sbostic tcsetattr(fd, TCSAFLUSH, &tt); 66438710Skfall } 66538710Skfall #endif 66636519Skarels 66736519Skarels env[0] = term; 66836519Skarels env[1] = 0; 66936519Skarels environ = env; 67036519Skarels } 67136609Skfall 67240917Skarels #ifdef KERBEROS 67340917Skarels #define VERSION_SIZE 9 67440917Skarels 67536609Skfall /* 67640917Skarels * Do the remote kerberos login to the named host with the 67740917Skarels * given inet address 67840917Skarels * 67940917Skarels * Return 0 on valid authorization 68040917Skarels * Return -1 on valid authentication, no authorization 68140917Skarels * Return >0 for error conditions 68240917Skarels */ 68340917Skarels do_krb_login(host, dest, encrypt) 68440917Skarels char *host; 68540917Skarels struct sockaddr_in *dest; 68640917Skarels int encrypt; 68740917Skarels { 68840917Skarels int rc; 68940917Skarels char instance[INST_SZ], version[VERSION_SIZE]; 69040917Skarels long authopts = 0L; /* !mutual */ 69140917Skarels struct sockaddr_in faddr; 69240917Skarels 69340917Skarels kdata = (AUTH_DAT *) auth_buf; 69440917Skarels ticket = (KTEXT) tick_buf; 69540917Skarels 69642264Sbostic instance[0] = '*'; 69742264Sbostic instance[1] = '\0'; 69842264Sbostic 69940917Skarels if (encrypt) { 70040917Skarels rc = sizeof(faddr); 70140917Skarels if (getsockname(0, &faddr, &rc)) 70240917Skarels return(-1); 70340917Skarels authopts = KOPT_DO_MUTUAL; 70440917Skarels rc = krb_recvauth( 70540917Skarels authopts, 0, 70640917Skarels ticket, "rcmd", 70740917Skarels instance, dest, &faddr, 70840917Skarels kdata, "", schedule, version); 70940917Skarels des_set_key(kdata->session, schedule); 71040917Skarels 71140917Skarels } else { 71240917Skarels rc = krb_recvauth( 71340917Skarels authopts, 0, 71440917Skarels ticket, "rcmd", 71540917Skarels instance, dest, (struct sockaddr_in *) 0, 71640917Skarels kdata, "", (bit_64 *) 0, version); 71740917Skarels } 71840917Skarels 71940917Skarels if (rc != KSUCCESS) 72040917Skarels return(rc); 72140917Skarels 72240917Skarels getstr(lusername, sizeof(lusername), "locuser"); 72340917Skarels /* get the "cmd" in the rcmd protocol */ 72440917Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 72540917Skarels 72640917Skarels pwd = getpwnam(lusername); 72740917Skarels if (pwd == NULL) 72840917Skarels return(-1); 72940917Skarels 73040917Skarels /* returns nonzero for no access */ 73140917Skarels if (kuserok(kdata,lusername) != 0) 73240917Skarels return(-1); 73340917Skarels 73440917Skarels return(0); 73540917Skarels 73640917Skarels } 73740917Skarels #endif /* KERBEROS */ 73840917Skarels 73940917Skarels usage() 74040917Skarels { 74140917Skarels #ifdef KERBEROS 74240917Skarels syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]"); 74340917Skarels #else 74440917Skarels syslog(LOG_ERR, "usage: rlogind [-aln]"); 74540917Skarels #endif 74640917Skarels } 74740917Skarels 74840917Skarels /* 74936631Skarels * Check whether host h is in our local domain, 75039058Skarels * defined as sharing the last two components of the domain part, 75139058Skarels * or the entire domain part if the local domain has only one component. 75236631Skarels * If either name is unqualified (contains no '.'), 75336631Skarels * assume that the host is local, as it will be 75436631Skarels * interpreted as such. 75536631Skarels */ 75636631Skarels local_domain(h) 75736631Skarels char *h; 75836625Skfall { 75936631Skarels char localhost[MAXHOSTNAMELEN]; 76039058Skarels char *p1, *p2, *topdomain(); 76136631Skarels 76239058Skarels localhost[0] = 0; 76336631Skarels (void) gethostname(localhost, sizeof(localhost)); 76439058Skarels p1 = topdomain(localhost); 76539058Skarels p2 = topdomain(h); 76636631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 76736625Skfall return(1); 76836625Skfall return(0); 76936625Skfall } 77039058Skarels 77139058Skarels char * 77239058Skarels topdomain(h) 77339058Skarels char *h; 77439058Skarels { 77539058Skarels register char *p; 77639058Skarels char *maybe = NULL; 77739058Skarels int dots = 0; 77839058Skarels 77939058Skarels for (p = h + strlen(h); p >= h; p--) { 78039058Skarels if (*p == '.') { 78139058Skarels if (++dots == 2) 78239058Skarels return (p); 78339058Skarels maybe = p; 78439058Skarels } 78539058Skarels } 78639058Skarels return (maybe); 78739058Skarels } 788