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*42956Sbostic static char sccsid[] = "@(#)rlogind.c 5.44 (Berkeley) 06/07/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> 559208Ssam 566446Swnj #include <errno.h> 576446Swnj #include <pwd.h> 588380Ssam #include <netdb.h> 5917187Sralph #include <syslog.h> 6042030Sbostic #include <string.h> 6140917Skarels #include <stdio.h> 6240917Skarels #include <unistd.h> 6340917Skarels #include "pathnames.h" 646446Swnj 6536518Skarels #ifndef TIOCPKT_WINDOW 6636518Skarels #define TIOCPKT_WINDOW 0x80 6736518Skarels #endif 6836518Skarels 6940917Skarels #ifdef KERBEROS 7041761Skfall #include <kerberosIV/des.h> 7140917Skarels #include <kerberosIV/krb.h> 7240917Skarels #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 7340917Skarels 7440917Skarels AUTH_DAT *kdata; 7540917Skarels KTEXT ticket; 7640917Skarels u_char auth_buf[sizeof(AUTH_DAT)]; 7740917Skarels u_char tick_buf[sizeof(KTEXT_ST)]; 7840917Skarels Key_schedule schedule; 7940917Skarels int encrypt = 0, retval, use_kerberos = 0, vacuous = 0; 8040917Skarels 8140917Skarels #define ARGSTR "alnkvx" 8240917Skarels #else 8340917Skarels #define ARGSTR "aln" 8440917Skarels #endif /* KERBEROS */ 8540917Skarels 8636518Skarels char *env[2]; 8736518Skarels #define NMAX 30 8836517Skarels char lusername[NMAX+1], rusername[NMAX+1]; 8936517Skarels static char term[64] = "TERM="; 9036517Skarels #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 9136517Skarels int keepalive = 1; 9239058Skarels int check_all = 0; 9336453Skfall 9434424Sbostic extern int errno; 9510417Ssam int reapchild(); 9636453Skfall struct passwd *getpwnam(), *pwd; 9724723Smckusick char *malloc(); 9816369Skarels 996446Swnj main(argc, argv) 1006446Swnj int argc; 1016446Swnj char **argv; 1026446Swnj { 10340917Skarels extern int opterr, optind; 10440917Skarels extern int _check_rhosts_file; 10536319Sbostic int ch; 10634424Sbostic int on = 1, fromlen; 1076446Swnj struct sockaddr_in from; 1086446Swnj 10936625Skfall openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 11036319Sbostic 11136319Sbostic opterr = 0; 11240917Skarels while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 11336517Skarels switch (ch) { 11439058Skarels case 'a': 11539058Skarels check_all = 1; 11639058Skarels break; 11736319Sbostic case 'l': 11836319Sbostic _check_rhosts_file = 0; 11936319Sbostic break; 12036517Skarels case 'n': 12136517Skarels keepalive = 0; 12236517Skarels break; 12340917Skarels #ifdef KERBEROS 12440917Skarels case 'k': 12540917Skarels use_kerberos = 1; 12640917Skarels break; 12740917Skarels case 'v': 12840917Skarels vacuous = 1; 12940917Skarels break; 13040917Skarels case 'x': 13140917Skarels encrypt = 1; 13240917Skarels break; 13340917Skarels #endif 13436319Sbostic case '?': 13536319Sbostic default: 13640917Skarels usage(); 13736319Sbostic break; 13836319Sbostic } 13936319Sbostic argc -= optind; 14036319Sbostic argv += optind; 14136319Sbostic 14240917Skarels #ifdef KERBEROS 14340917Skarels if (use_kerberos && vacuous) { 14440917Skarels usage(); 14540917Skarels fatal(STDERR_FILENO, "only one of -k and -v allowed", 0); 14640917Skarels } 14740917Skarels #endif 14816369Skarels fromlen = sizeof (from); 14916369Skarels if (getpeername(0, &from, &fromlen) < 0) { 15040917Skarels syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 15140917Skarels fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 1528380Ssam } 15336517Skarels if (keepalive && 15436517Skarels setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 15517187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 15616369Skarels doit(0, &from); 1576446Swnj } 1586446Swnj 1596446Swnj int child; 1606446Swnj int cleanup(); 1616446Swnj int netf; 1626446Swnj char *line; 16340917Skarels int confirmed; 16424724Smckusick extern char *inet_ntoa(); 1656446Swnj 16624889Smckusick struct winsize win = { 0, 0, 0, 0 }; 16724723Smckusick 16824889Smckusick 1696446Swnj doit(f, fromp) 1706446Swnj int f; 1716446Swnj struct sockaddr_in *fromp; 1726446Swnj { 17318357Ssam int i, p, t, pid, on = 1; 17436631Skarels int authenticated = 0, hostok = 0; 17540917Skarels register struct hostent *hp; 17639249Smarc char remotehost[2 * MAXHOSTNAMELEN + 1]; 17724724Smckusick struct hostent hostent; 1788380Ssam char c; 1796446Swnj 1806446Swnj alarm(60); 1816446Swnj read(f, &c, 1); 18240917Skarels 18339249Smarc if (c != 0) 18436715Skfall exit(1); 18540917Skarels #ifdef KERBEROS 18640917Skarels if (vacuous) 18740917Skarels fatal(f, "Remote host requires Kerberos authentication", 0); 18840917Skarels #endif 18936453Skfall 1906446Swnj alarm(0); 19116227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 1928380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 1938380Ssam fromp->sin_family); 19411345Ssam if (hp == 0) { 19524724Smckusick /* 19624724Smckusick * Only the name is used below. 19724724Smckusick */ 19824724Smckusick hp = &hostent; 19924724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 20036635Skarels hostok++; 20140917Skarels } else if (check_all || local_domain(hp->h_name)) { 20236635Skarels /* 20336635Skarels * If name returned by gethostbyaddr is in our domain, 20436635Skarels * attempt to verify that we haven't been fooled by someone 20536635Skarels * in a remote net; look up the name and check that this 20636635Skarels * address corresponds to the name. 20736635Skarels */ 20836635Skarels strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 20936635Skarels remotehost[sizeof(remotehost) - 1] = 0; 21036635Skarels hp = gethostbyname(remotehost); 21136635Skarels if (hp) 21236635Skarels for (; hp->h_addr_list[0]; hp->h_addr_list++) 21336635Skarels if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 21436635Skarels sizeof(fromp->sin_addr))) { 21536635Skarels hostok++; 21636635Skarels break; 21736635Skarels } 21836633Skarels } else 21936635Skarels hostok++; 22036711Skfall 22140917Skarels #ifdef KERBEROS 22240917Skarels if (use_kerberos) { 22342264Sbostic if (!hostok) 22442264Sbostic fatal(f, "krlogind: Host address mismatch.", 0); 22540917Skarels retval = do_krb_login(hp->h_name, fromp, encrypt); 22642264Sbostic if (retval == 0) 22740917Skarels authenticated++; 22840917Skarels else if (retval > 0) 22940917Skarels fatal(f, krb_err_txt[retval], 0); 23040917Skarels write(f, &c, 1); 23140917Skarels confirmed = 1; /* we sent the null! */ 23240917Skarels } else 23340917Skarels #endif 23440917Skarels { 23540917Skarels if (fromp->sin_family != AF_INET || 23640917Skarels fromp->sin_port >= IPPORT_RESERVED || 23740917Skarels fromp->sin_port < IPPORT_RESERVED/2) { 23840917Skarels syslog(LOG_NOTICE, "Connection from %s on illegal port", 23940917Skarels inet_ntoa(fromp->sin_addr)); 24040917Skarels fatal(f, "Permission denied", 0); 24140917Skarels } 24236702Skarels #ifdef IP_OPTIONS 24340917Skarels { 24440917Skarels u_char optbuf[BUFSIZ/3], *cp; 24540917Skarels char lbuf[BUFSIZ], *lp; 24640917Skarels int optsize = sizeof(optbuf), ipproto; 24740917Skarels struct protoent *ip; 24836702Skarels 24940917Skarels if ((ip = getprotobyname("ip")) != NULL) 25040917Skarels ipproto = ip->p_proto; 25140917Skarels else 25240917Skarels ipproto = IPPROTO_IP; 25340917Skarels if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 25440917Skarels &optsize) == 0 && optsize != 0) { 25540917Skarels lp = lbuf; 25640917Skarels for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 25740917Skarels sprintf(lp, " %2.2x", *cp); 25840917Skarels syslog(LOG_NOTICE, 25940917Skarels "Connection received using IP options (ignored):%s", 26040917Skarels lbuf); 26140917Skarels if (setsockopt(0, ipproto, IP_OPTIONS, 26240917Skarels (char *)NULL, &optsize) != 0) { 26340917Skarels syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 26440917Skarels exit(1); 26540917Skarels } 26640917Skarels } 26740917Skarels } 26836702Skarels #endif 26940917Skarels if (do_rlogin(hp->h_name) == 0 && hostok) 27039249Smarc authenticated++; 27136631Skarels } 27236636Skarels 2736446Swnj for (c = 'p'; c <= 's'; c++) { 2746446Swnj struct stat stb; 2756446Swnj line = "/dev/ptyXX"; 2766446Swnj line[strlen("/dev/pty")] = c; 2776446Swnj line[strlen("/dev/ptyp")] = '0'; 2786446Swnj if (stat(line, &stb) < 0) 2796446Swnj break; 2806446Swnj for (i = 0; i < 16; i++) { 28134424Sbostic line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 28234424Sbostic p = open(line, O_RDWR); 2836446Swnj if (p > 0) 2846446Swnj goto gotpty; 2856446Swnj } 2866446Swnj } 28740917Skarels fatal(f, "Out of ptys", 0); 2889242Ssam /*NOTREACHED*/ 2896446Swnj gotpty: 29024889Smckusick (void) ioctl(p, TIOCSWINSZ, &win); 29116227Skarels netf = f; 29240917Skarels line[sizeof(_PATH_DEV) - 1] = 't'; 29334424Sbostic t = open(line, O_RDWR); 29434424Sbostic if (t < 0) 29540917Skarels fatal(f, line, 1); 29634424Sbostic if (fchmod(t, 0)) 29740917Skarels fatal(f, line, 1); 29834424Sbostic (void)signal(SIGHUP, SIG_IGN); 29934424Sbostic vhangup(); 30034424Sbostic (void)signal(SIGHUP, SIG_DFL); 30134424Sbostic t = open(line, O_RDWR); 30234424Sbostic if (t < 0) 30340917Skarels fatal(f, line, 1); 30436453Skfall setup_term(t); 30540917Skarels if (confirmed == 0) { 30640917Skarels write(f, "", 1); 30740917Skarels confirmed = 1; /* we sent the null! */ 30839249Smarc } 30940917Skarels #ifdef KERBEROS 31040917Skarels if (encrypt) 31140917Skarels (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 31240917Skarels 31340917Skarels if (use_kerberos == 0) 31439249Smarc #endif 31540917Skarels if (!authenticated && !hostok) 31640917Skarels write(f, "rlogind: Host address mismatch.\r\n", 31740917Skarels sizeof("rlogind: Host address mismatch.\r\n") - 1); 31840917Skarels 3199242Ssam pid = fork(); 3209242Ssam if (pid < 0) 32140917Skarels fatal(f, "", 1); 32218357Ssam if (pid == 0) { 32336711Skfall if (setsid() < 0) 32440917Skarels fatal(f, "setsid", 1); 32536711Skfall if (ioctl(t, TIOCSCTTY, 0) < 0) 32640917Skarels fatal(f, "ioctl(sctty)", 1); 32740917Skarels (void)close(f); 32840917Skarels (void)close(p); 32940917Skarels dup2(t, STDIN_FILENO); 33040917Skarels dup2(t, STDOUT_FILENO); 33140917Skarels dup2(t, STDERR_FILENO); 33240917Skarels (void)close(t); 33340917Skarels 33436631Skarels if (authenticated) 33540917Skarels execl(_PATH_LOGIN, "login", "-p", 33640917Skarels "-h", hp->h_name, "-f", lusername, 0); 33736525Skfall else 33840917Skarels execl(_PATH_LOGIN, "login", "-p", 33940917Skarels "-h", hp->h_name, lusername, 0); 34040917Skarels fatal(STDERR_FILENO, _PATH_LOGIN, 1); 34118357Ssam /*NOTREACHED*/ 34218357Ssam } 34318357Ssam close(t); 34436453Skfall 34540917Skarels #ifdef KERBEROS 34640917Skarels /* 34740917Skarels * If encrypted, don't turn on NBIO or the des read/write 34840917Skarels * routines will croak. 34940917Skarels */ 35040917Skarels 35140917Skarels if (!encrypt) 35240917Skarels #endif 35340917Skarels ioctl(f, FIONBIO, &on); 35418357Ssam ioctl(p, FIONBIO, &on); 35518357Ssam ioctl(p, TIOCPKT, &on); 35618357Ssam signal(SIGCHLD, cleanup); 35718357Ssam protocol(f, p); 35830600Smckusick signal(SIGCHLD, SIG_IGN); 35918357Ssam cleanup(); 36018357Ssam } 3619242Ssam 36218357Ssam char magic[2] = { 0377, 0377 }; 36325423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 36418357Ssam 36518357Ssam /* 36618357Ssam * Handle a "control" request (signaled by magic being present) 36718357Ssam * in the data stream. For now, we are only willing to handle 36818357Ssam * window size changes. 36918357Ssam */ 37018357Ssam control(pty, cp, n) 37118357Ssam int pty; 37218357Ssam char *cp; 37318357Ssam int n; 37418357Ssam { 37528705Smckusick struct winsize w; 37618357Ssam 37728705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 37818357Ssam return (0); 37925423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 38028705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 38128705Smckusick w.ws_row = ntohs(w.ws_row); 38228705Smckusick w.ws_col = ntohs(w.ws_col); 38328705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 38428705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 38528705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 38628705Smckusick return (4+sizeof (w)); 38718357Ssam } 38818357Ssam 38918357Ssam /* 39018357Ssam * rlogin "protocol" machine. 39118357Ssam */ 39218357Ssam protocol(f, p) 39340917Skarels register int f, p; 39418357Ssam { 39540917Skarels char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 39618357Ssam register pcc = 0, fcc = 0; 39740917Skarels int cc, nfd, n; 39825740Skarels char cntl; 39918357Ssam 40018482Ssam /* 40118484Ssam * Must ignore SIGTTOU, otherwise we'll stop 40218484Ssam * when we try and set slave pty's window shape 40325423Skarels * (our controlling tty is the master pty). 40418482Ssam */ 40518484Ssam (void) signal(SIGTTOU, SIG_IGN); 40625423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 40736517Skarels if (f > p) 40836517Skarels nfd = f + 1; 40936517Skarels else 41036517Skarels nfd = p + 1; 41140917Skarels if (nfd > FD_SETSIZE) { 41240917Skarels syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 41340917Skarels fatal(f, "internal error (select mask too small)", 0); 41440917Skarels } 41518357Ssam for (;;) { 41640917Skarels fd_set ibits, obits, ebits, *omask; 41718357Ssam 418*42956Sbostic FD_ZERO(&ebits); 41940917Skarels FD_ZERO(&ibits); 42040917Skarels FD_ZERO(&obits); 42140917Skarels omask = (fd_set *)NULL; 42240917Skarels if (fcc) { 42340917Skarels FD_SET(p, &obits); 42440917Skarels omask = &obits; 42540917Skarels } else 42640917Skarels FD_SET(f, &ibits); 42718357Ssam if (pcc >= 0) 42840917Skarels if (pcc) { 42940917Skarels FD_SET(f, &obits); 43040917Skarels omask = &obits; 43140917Skarels } else 43240917Skarels FD_SET(p, &ibits); 43340917Skarels FD_SET(p, &ebits); 43440917Skarels if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 43518357Ssam if (errno == EINTR) 4366446Swnj continue; 43740917Skarels fatal(f, "select", 1); 43818357Ssam } 43940917Skarels if (n == 0) { 44018357Ssam /* shouldn't happen... */ 44118357Ssam sleep(5); 44218357Ssam continue; 44318357Ssam } 44425740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 44540917Skarels if (FD_ISSET(p, &ebits)) { 44625740Skarels cc = read(p, &cntl, 1); 44725740Skarels if (cc == 1 && pkcontrol(cntl)) { 44825740Skarels cntl |= oobdata[0]; 44925740Skarels send(f, &cntl, 1, MSG_OOB); 45025740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 45125740Skarels pcc = 0; 45240917Skarels FD_CLR(p, &ibits); 45325740Skarels } 45425740Skarels } 45525740Skarels } 45640917Skarels if (FD_ISSET(f, &ibits)) { 45740917Skarels #ifdef KERBEROS 45840917Skarels if (encrypt) 45940917Skarels fcc = des_read(f, fibuf, sizeof(fibuf)); 46040917Skarels else 46140917Skarels #endif 46240917Skarels fcc = read(f, fibuf, sizeof(fibuf)); 46318357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 46418357Ssam fcc = 0; 46518357Ssam else { 46618357Ssam register char *cp; 46718357Ssam int left, n; 46818357Ssam 46918357Ssam if (fcc <= 0) 47016227Skarels break; 47118357Ssam fbp = fibuf; 47224723Smckusick 47318357Ssam top: 47425423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 47518357Ssam if (cp[0] == magic[0] && 47618357Ssam cp[1] == magic[1]) { 47718357Ssam left = fcc - (cp-fibuf); 47818357Ssam n = control(p, cp, left); 47918357Ssam if (n) { 48018357Ssam left -= n; 48118357Ssam if (left > 0) 48225423Skarels bcopy(cp+n, cp, left); 48318357Ssam fcc -= n; 48418357Ssam goto top; /* n^2 */ 48525423Skarels } 48625423Skarels } 48740917Skarels FD_SET(p, &obits); /* try write */ 48825423Skarels } 48925423Skarels } 49024723Smckusick 49140917Skarels if (FD_ISSET(p, &obits) && fcc > 0) { 49225423Skarels cc = write(p, fbp, fcc); 49324723Smckusick if (cc > 0) { 49424723Smckusick fcc -= cc; 49524723Smckusick fbp += cc; 4966446Swnj } 49718357Ssam } 49824723Smckusick 49940917Skarels if (FD_ISSET(p, &ibits)) { 50018357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 50118357Ssam pbp = pibuf; 50218357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 50318357Ssam pcc = 0; 50418357Ssam else if (pcc <= 0) 50518357Ssam break; 50636517Skarels else if (pibuf[0] == 0) { 50718357Ssam pbp++, pcc--; 50840917Skarels #ifdef KERBEROS 50940917Skarels if (!encrypt) 51040917Skarels #endif 51140917Skarels FD_SET(f, &obits); /* try write */ 51236517Skarels } else { 51318357Ssam if (pkcontrol(pibuf[0])) { 51425423Skarels pibuf[0] |= oobdata[0]; 51518357Ssam send(f, &pibuf[0], 1, MSG_OOB); 51616227Skarels } 51718357Ssam pcc = 0; 5186446Swnj } 51918357Ssam } 52040917Skarels if ((FD_ISSET(f, &obits)) && pcc > 0) { 52140917Skarels #ifdef KERBEROS 52240917Skarels if (encrypt) 52340917Skarels cc = des_write(f, pbp, pcc); 52440917Skarels else 52540917Skarels #endif 52640917Skarels cc = write(f, pbp, pcc); 52725423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 52840917Skarels /* 52940917Skarels * This happens when we try write after read 53040917Skarels * from p, but some old kernels balk at large 53140917Skarels * writes even when select returns true. 53240917Skarels */ 53340917Skarels if (!FD_ISSET(p, &ibits)) 53440917Skarels sleep(5); 53525423Skarels continue; 53625423Skarels } 53718357Ssam if (cc > 0) { 53818357Ssam pcc -= cc; 53918357Ssam pbp += cc; 54018357Ssam } 5416446Swnj } 5426446Swnj } 5436446Swnj } 5446446Swnj 5456446Swnj cleanup() 5466446Swnj { 54735440Sbostic char *p; 54835440Sbostic 54940917Skarels p = line + sizeof(_PATH_DEV) - 1; 55035440Sbostic if (logout(p)) 55135440Sbostic logwtmp(p, "", ""); 55235440Sbostic (void)chmod(line, 0666); 55335440Sbostic (void)chown(line, 0, 0); 55435440Sbostic *p = 'p'; 55535440Sbostic (void)chmod(line, 0666); 55635440Sbostic (void)chown(line, 0, 0); 55710192Ssam shutdown(netf, 2); 5586446Swnj exit(1); 5596446Swnj } 5606446Swnj 56140917Skarels fatal(f, msg, syserr) 56240917Skarels int f, syserr; 5639242Ssam char *msg; 5649242Ssam { 56540917Skarels int len; 56640917Skarels char buf[BUFSIZ], *bp = buf; 5679242Ssam 56840917Skarels /* 56940917Skarels * Prepend binary one to message if we haven't sent 57040917Skarels * the magic null as confirmation. 57140917Skarels */ 57240917Skarels if (!confirmed) 57340917Skarels *bp++ = '\01'; /* error indicator */ 57440917Skarels if (syserr) 57540917Skarels len = sprintf(bp, "rlogind: %s: %s.\r\n", 57640917Skarels msg, strerror(errno)); 57740917Skarels else 57840917Skarels len = sprintf(bp, "rlogind: %s.\r\n", msg); 57940917Skarels (void) write(f, buf, bp + len - buf); 5809242Ssam exit(1); 5819242Ssam } 5829242Ssam 58336453Skfall do_rlogin(host) 58436518Skarels char *host; 58536453Skfall { 58636518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 58736518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 58836518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 58936518Skarels 59036453Skfall pwd = getpwnam(lusername); 59136518Skarels if (pwd == NULL) 59236453Skfall return(-1); 59342264Sbostic if (pwd->pw_uid == 0) 59442264Sbostic return(-1); 59542264Sbostic return(ruserok(host, 0, rusername, lusername)); 59636453Skfall } 59736453Skfall 59836453Skfall 59936518Skarels getstr(buf, cnt, errmsg) 60036518Skarels char *buf; 60136518Skarels int cnt; 60236518Skarels char *errmsg; 60336453Skfall { 60436518Skarels char c; 60536518Skarels 60636453Skfall do { 60736518Skarels if (read(0, &c, 1) != 1) 60836453Skfall exit(1); 60936518Skarels if (--cnt < 0) 61040917Skarels fatal(STDOUT_FILENO, errmsg, 0); 61136453Skfall *buf++ = c; 61236518Skarels } while (c != 0); 61336453Skfall } 61436453Skfall 61536518Skarels extern char **environ; 61636453Skfall 61736519Skarels setup_term(fd) 61836519Skarels int fd; 61936519Skarels { 62040917Skarels register char *cp = index(term+ENVSIZE, '/'); 62136519Skarels char *speed; 62239118Skarels struct termios tt; 62336519Skarels 62440917Skarels #ifndef notyet 62536711Skfall tcgetattr(fd, &tt); 62636519Skarels if (cp) { 62736519Skarels *cp++ = '\0'; 62836519Skarels speed = cp; 62936519Skarels cp = index(speed, '/'); 63036519Skarels if (cp) 63136519Skarels *cp++ = '\0'; 63236711Skfall cfsetspeed(&tt, atoi(speed)); 63336519Skarels } 63438710Skfall 63539118Skarels tt.c_iflag = TTYDEF_IFLAG; 63639118Skarels tt.c_oflag = TTYDEF_OFLAG; 63739118Skarels tt.c_lflag = TTYDEF_LFLAG; 63839118Skarels tcsetattr(fd, TCSADFLUSH, &tt); 63939118Skarels #else 64039118Skarels if (cp) { 64139118Skarels *cp++ = '\0'; 64239118Skarels speed = cp; 64339118Skarels cp = index(speed, '/'); 64439118Skarels if (cp) 64539118Skarels *cp++ = '\0'; 64640917Skarels tcgetattr(fd, &tt); 64740917Skarels cfsetspeed(&tt, atoi(speed)); 64840917Skarels tcsetattr(fd, TCSADFLUSH, &tt); 64938710Skfall } 65038710Skfall #endif 65136519Skarels 65236519Skarels env[0] = term; 65336519Skarels env[1] = 0; 65436519Skarels environ = env; 65536519Skarels } 65636609Skfall 65740917Skarels #ifdef KERBEROS 65840917Skarels #define VERSION_SIZE 9 65940917Skarels 66036609Skfall /* 66140917Skarels * Do the remote kerberos login to the named host with the 66240917Skarels * given inet address 66340917Skarels * 66440917Skarels * Return 0 on valid authorization 66540917Skarels * Return -1 on valid authentication, no authorization 66640917Skarels * Return >0 for error conditions 66740917Skarels */ 66840917Skarels do_krb_login(host, dest, encrypt) 66940917Skarels char *host; 67040917Skarels struct sockaddr_in *dest; 67140917Skarels int encrypt; 67240917Skarels { 67340917Skarels int rc; 67440917Skarels char instance[INST_SZ], version[VERSION_SIZE]; 67540917Skarels long authopts = 0L; /* !mutual */ 67640917Skarels struct sockaddr_in faddr; 67740917Skarels 67840917Skarels kdata = (AUTH_DAT *) auth_buf; 67940917Skarels ticket = (KTEXT) tick_buf; 68040917Skarels 68142264Sbostic instance[0] = '*'; 68242264Sbostic instance[1] = '\0'; 68342264Sbostic 68440917Skarels if (encrypt) { 68540917Skarels rc = sizeof(faddr); 68640917Skarels if (getsockname(0, &faddr, &rc)) 68740917Skarels return(-1); 68840917Skarels authopts = KOPT_DO_MUTUAL; 68940917Skarels rc = krb_recvauth( 69040917Skarels authopts, 0, 69140917Skarels ticket, "rcmd", 69240917Skarels instance, dest, &faddr, 69340917Skarels kdata, "", schedule, version); 69440917Skarels des_set_key(kdata->session, schedule); 69540917Skarels 69640917Skarels } else { 69740917Skarels rc = krb_recvauth( 69840917Skarels authopts, 0, 69940917Skarels ticket, "rcmd", 70040917Skarels instance, dest, (struct sockaddr_in *) 0, 70140917Skarels kdata, "", (bit_64 *) 0, version); 70240917Skarels } 70340917Skarels 70440917Skarels if (rc != KSUCCESS) 70540917Skarels return(rc); 70640917Skarels 70740917Skarels getstr(lusername, sizeof(lusername), "locuser"); 70840917Skarels /* get the "cmd" in the rcmd protocol */ 70940917Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 71040917Skarels 71140917Skarels pwd = getpwnam(lusername); 71240917Skarels if (pwd == NULL) 71340917Skarels return(-1); 71440917Skarels 71540917Skarels /* returns nonzero for no access */ 71640917Skarels if (kuserok(kdata,lusername) != 0) 71740917Skarels return(-1); 71840917Skarels 71940917Skarels return(0); 72040917Skarels 72140917Skarels } 72240917Skarels #endif /* KERBEROS */ 72340917Skarels 72440917Skarels usage() 72540917Skarels { 72640917Skarels #ifdef KERBEROS 72740917Skarels syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]"); 72840917Skarels #else 72940917Skarels syslog(LOG_ERR, "usage: rlogind [-aln]"); 73040917Skarels #endif 73140917Skarels } 73240917Skarels 73340917Skarels /* 73436631Skarels * Check whether host h is in our local domain, 73539058Skarels * defined as sharing the last two components of the domain part, 73639058Skarels * or the entire domain part if the local domain has only one component. 73736631Skarels * If either name is unqualified (contains no '.'), 73836631Skarels * assume that the host is local, as it will be 73936631Skarels * interpreted as such. 74036631Skarels */ 74136631Skarels local_domain(h) 74236631Skarels char *h; 74336625Skfall { 74436631Skarels char localhost[MAXHOSTNAMELEN]; 74539058Skarels char *p1, *p2, *topdomain(); 74636631Skarels 74739058Skarels localhost[0] = 0; 74836631Skarels (void) gethostname(localhost, sizeof(localhost)); 74939058Skarels p1 = topdomain(localhost); 75039058Skarels p2 = topdomain(h); 75136631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 75236625Skfall return(1); 75336625Skfall return(0); 75436625Skfall } 75539058Skarels 75639058Skarels char * 75739058Skarels topdomain(h) 75839058Skarels char *h; 75939058Skarels { 76039058Skarels register char *p; 76139058Skarels char *maybe = NULL; 76239058Skarels int dots = 0; 76339058Skarels 76439058Skarels for (p = h + strlen(h); p >= h; p--) { 76539058Skarels if (*p == '.') { 76639058Skarels if (++dots == 2) 76739058Skarels return (p); 76839058Skarels maybe = p; 76939058Skarels } 77039058Skarels } 77139058Skarels return (maybe); 77239058Skarels } 773