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*42030Sbostic static char sccsid[] = "@(#)rlogind.c 5.42 (Berkeley) 05/15/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> 60*42030Sbostic #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 int do_krb_login(); 8140917Skarels 8240917Skarels #define ARGSTR "alnkvx" 8340917Skarels #else 8440917Skarels #define ARGSTR "aln" 8540917Skarels #endif /* KERBEROS */ 8640917Skarels 8736518Skarels char *env[2]; 8836518Skarels #define NMAX 30 8936517Skarels char lusername[NMAX+1], rusername[NMAX+1]; 9036517Skarels static char term[64] = "TERM="; 9136517Skarels #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 9236517Skarels int keepalive = 1; 9339058Skarels int check_all = 0; 9436453Skfall 9536453Skfall #define SUPERUSER(pwd) ((pwd)->pw_uid == 0) 9636453Skfall 9734424Sbostic extern int errno; 9810417Ssam int reapchild(); 9936453Skfall struct passwd *getpwnam(), *pwd; 10024723Smckusick char *malloc(); 10116369Skarels 1026446Swnj main(argc, argv) 1036446Swnj int argc; 1046446Swnj char **argv; 1056446Swnj { 10640917Skarels extern int opterr, optind; 10740917Skarels extern int _check_rhosts_file; 10836319Sbostic int ch; 10934424Sbostic int on = 1, fromlen; 1106446Swnj struct sockaddr_in from; 1116446Swnj 11236625Skfall openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 11336319Sbostic 11436319Sbostic opterr = 0; 11540917Skarels while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 11636517Skarels switch (ch) { 11739058Skarels case 'a': 11839058Skarels check_all = 1; 11939058Skarels break; 12036319Sbostic case 'l': 12136319Sbostic _check_rhosts_file = 0; 12236319Sbostic break; 12336517Skarels case 'n': 12436517Skarels keepalive = 0; 12536517Skarels break; 12640917Skarels #ifdef KERBEROS 12740917Skarels case 'k': 12840917Skarels use_kerberos = 1; 12940917Skarels break; 13040917Skarels case 'v': 13140917Skarels vacuous = 1; 13240917Skarels break; 13340917Skarels case 'x': 13440917Skarels encrypt = 1; 13540917Skarels break; 13640917Skarels #endif 13736319Sbostic case '?': 13836319Sbostic default: 13940917Skarels usage(); 14036319Sbostic break; 14136319Sbostic } 14236319Sbostic argc -= optind; 14336319Sbostic argv += optind; 14436319Sbostic 14540917Skarels #ifdef KERBEROS 14640917Skarels if (use_kerberos && vacuous) { 14740917Skarels usage(); 14840917Skarels fatal(STDERR_FILENO, "only one of -k and -v allowed", 0); 14940917Skarels } 15040917Skarels #endif 15116369Skarels fromlen = sizeof (from); 15216369Skarels if (getpeername(0, &from, &fromlen) < 0) { 15340917Skarels syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 15440917Skarels fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 1558380Ssam } 15636517Skarels if (keepalive && 15736517Skarels setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 15817187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 15916369Skarels doit(0, &from); 1606446Swnj } 1616446Swnj 1626446Swnj int child; 1636446Swnj int cleanup(); 1646446Swnj int netf; 1656446Swnj char *line; 16640917Skarels int confirmed; 16724724Smckusick extern char *inet_ntoa(); 1686446Swnj 16924889Smckusick struct winsize win = { 0, 0, 0, 0 }; 17024723Smckusick 17124889Smckusick 1726446Swnj doit(f, fromp) 1736446Swnj int f; 1746446Swnj struct sockaddr_in *fromp; 1756446Swnj { 17618357Ssam int i, p, t, pid, on = 1; 17736631Skarels int authenticated = 0, hostok = 0; 17840917Skarels register struct hostent *hp; 17939249Smarc char remotehost[2 * MAXHOSTNAMELEN + 1]; 18024724Smckusick struct hostent hostent; 1818380Ssam char c; 1826446Swnj 1836446Swnj alarm(60); 1846446Swnj read(f, &c, 1); 18540917Skarels 18639249Smarc if (c != 0) 18736715Skfall exit(1); 18840917Skarels #ifdef KERBEROS 18940917Skarels if (vacuous) 19040917Skarels fatal(f, "Remote host requires Kerberos authentication", 0); 19140917Skarels #endif 19236453Skfall 1936446Swnj alarm(0); 19416227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 1958380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 1968380Ssam fromp->sin_family); 19711345Ssam if (hp == 0) { 19824724Smckusick /* 19924724Smckusick * Only the name is used below. 20024724Smckusick */ 20124724Smckusick hp = &hostent; 20224724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 20336635Skarels hostok++; 20440917Skarels } else if (check_all || local_domain(hp->h_name)) { 20536635Skarels /* 20636635Skarels * If name returned by gethostbyaddr is in our domain, 20736635Skarels * attempt to verify that we haven't been fooled by someone 20836635Skarels * in a remote net; look up the name and check that this 20936635Skarels * address corresponds to the name. 21036635Skarels */ 21136635Skarels strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 21236635Skarels remotehost[sizeof(remotehost) - 1] = 0; 21336635Skarels hp = gethostbyname(remotehost); 21436635Skarels if (hp) 21536635Skarels for (; hp->h_addr_list[0]; hp->h_addr_list++) 21636635Skarels if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 21736635Skarels sizeof(fromp->sin_addr))) { 21836635Skarels hostok++; 21936635Skarels break; 22036635Skarels } 22136633Skarels } else 22236635Skarels hostok++; 22336711Skfall 22440917Skarels #ifdef KERBEROS 22540917Skarels if (use_kerberos) { 22640917Skarels retval = do_krb_login(hp->h_name, fromp, encrypt); 22740917Skarels if (retval == 0 && hostok) 22840917Skarels authenticated++; 22940917Skarels else if (retval > 0) 23040917Skarels fatal(f, krb_err_txt[retval], 0); 23140917Skarels else if (!hostok) 23240917Skarels fatal(f, "krlogind: Host address mismatch.", 0); 23340917Skarels write(f, &c, 1); 23440917Skarels confirmed = 1; /* we sent the null! */ 23540917Skarels } else 23640917Skarels #endif 23740917Skarels { 23840917Skarels if (fromp->sin_family != AF_INET || 23940917Skarels fromp->sin_port >= IPPORT_RESERVED || 24040917Skarels fromp->sin_port < IPPORT_RESERVED/2) { 24140917Skarels syslog(LOG_NOTICE, "Connection from %s on illegal port", 24240917Skarels inet_ntoa(fromp->sin_addr)); 24340917Skarels fatal(f, "Permission denied", 0); 24440917Skarels } 24536702Skarels #ifdef IP_OPTIONS 24640917Skarels { 24740917Skarels u_char optbuf[BUFSIZ/3], *cp; 24840917Skarels char lbuf[BUFSIZ], *lp; 24940917Skarels int optsize = sizeof(optbuf), ipproto; 25040917Skarels struct protoent *ip; 25136702Skarels 25240917Skarels if ((ip = getprotobyname("ip")) != NULL) 25340917Skarels ipproto = ip->p_proto; 25440917Skarels else 25540917Skarels ipproto = IPPROTO_IP; 25640917Skarels if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 25740917Skarels &optsize) == 0 && optsize != 0) { 25840917Skarels lp = lbuf; 25940917Skarels for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 26040917Skarels sprintf(lp, " %2.2x", *cp); 26140917Skarels syslog(LOG_NOTICE, 26240917Skarels "Connection received using IP options (ignored):%s", 26340917Skarels lbuf); 26440917Skarels if (setsockopt(0, ipproto, IP_OPTIONS, 26540917Skarels (char *)NULL, &optsize) != 0) { 26640917Skarels syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 26740917Skarels exit(1); 26840917Skarels } 26940917Skarels } 27040917Skarels } 27136702Skarels #endif 27240917Skarels if (do_rlogin(hp->h_name) == 0 && hostok) 27339249Smarc authenticated++; 27436631Skarels } 27536636Skarels 2766446Swnj for (c = 'p'; c <= 's'; c++) { 2776446Swnj struct stat stb; 2786446Swnj line = "/dev/ptyXX"; 2796446Swnj line[strlen("/dev/pty")] = c; 2806446Swnj line[strlen("/dev/ptyp")] = '0'; 2816446Swnj if (stat(line, &stb) < 0) 2826446Swnj break; 2836446Swnj for (i = 0; i < 16; i++) { 28434424Sbostic line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 28534424Sbostic p = open(line, O_RDWR); 2866446Swnj if (p > 0) 2876446Swnj goto gotpty; 2886446Swnj } 2896446Swnj } 29040917Skarels fatal(f, "Out of ptys", 0); 2919242Ssam /*NOTREACHED*/ 2926446Swnj gotpty: 29324889Smckusick (void) ioctl(p, TIOCSWINSZ, &win); 29416227Skarels netf = f; 29540917Skarels line[sizeof(_PATH_DEV) - 1] = 't'; 29634424Sbostic t = open(line, O_RDWR); 29734424Sbostic if (t < 0) 29840917Skarels fatal(f, line, 1); 29934424Sbostic if (fchmod(t, 0)) 30040917Skarels fatal(f, line, 1); 30134424Sbostic (void)signal(SIGHUP, SIG_IGN); 30234424Sbostic vhangup(); 30334424Sbostic (void)signal(SIGHUP, SIG_DFL); 30434424Sbostic t = open(line, O_RDWR); 30534424Sbostic if (t < 0) 30640917Skarels fatal(f, line, 1); 30736453Skfall setup_term(t); 30840917Skarels if (confirmed == 0) { 30940917Skarels write(f, "", 1); 31040917Skarels confirmed = 1; /* we sent the null! */ 31139249Smarc } 31240917Skarels #ifdef KERBEROS 31340917Skarels if (encrypt) 31440917Skarels (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 31540917Skarels 31640917Skarels if (use_kerberos == 0) 31739249Smarc #endif 31840917Skarels if (!authenticated && !hostok) 31940917Skarels write(f, "rlogind: Host address mismatch.\r\n", 32040917Skarels sizeof("rlogind: Host address mismatch.\r\n") - 1); 32140917Skarels 3229242Ssam pid = fork(); 3239242Ssam if (pid < 0) 32440917Skarels fatal(f, "", 1); 32518357Ssam if (pid == 0) { 32636711Skfall if (setsid() < 0) 32740917Skarels fatal(f, "setsid", 1); 32836711Skfall if (ioctl(t, TIOCSCTTY, 0) < 0) 32940917Skarels fatal(f, "ioctl(sctty)", 1); 33040917Skarels (void)close(f); 33140917Skarels (void)close(p); 33240917Skarels dup2(t, STDIN_FILENO); 33340917Skarels dup2(t, STDOUT_FILENO); 33440917Skarels dup2(t, STDERR_FILENO); 33540917Skarels (void)close(t); 33640917Skarels 33736631Skarels if (authenticated) 33840917Skarels execl(_PATH_LOGIN, "login", "-p", 33940917Skarels "-h", hp->h_name, "-f", lusername, 0); 34036525Skfall else 34140917Skarels execl(_PATH_LOGIN, "login", "-p", 34240917Skarels "-h", hp->h_name, lusername, 0); 34340917Skarels fatal(STDERR_FILENO, _PATH_LOGIN, 1); 34418357Ssam /*NOTREACHED*/ 34518357Ssam } 34618357Ssam close(t); 34736453Skfall 34840917Skarels #ifdef KERBEROS 34940917Skarels /* 35040917Skarels * If encrypted, don't turn on NBIO or the des read/write 35140917Skarels * routines will croak. 35240917Skarels */ 35340917Skarels 35440917Skarels if (!encrypt) 35540917Skarels #endif 35640917Skarels ioctl(f, FIONBIO, &on); 35718357Ssam ioctl(p, FIONBIO, &on); 35818357Ssam ioctl(p, TIOCPKT, &on); 35918357Ssam signal(SIGCHLD, cleanup); 36018357Ssam protocol(f, p); 36130600Smckusick signal(SIGCHLD, SIG_IGN); 36218357Ssam cleanup(); 36318357Ssam } 3649242Ssam 36518357Ssam char magic[2] = { 0377, 0377 }; 36625423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 36718357Ssam 36818357Ssam /* 36918357Ssam * Handle a "control" request (signaled by magic being present) 37018357Ssam * in the data stream. For now, we are only willing to handle 37118357Ssam * window size changes. 37218357Ssam */ 37318357Ssam control(pty, cp, n) 37418357Ssam int pty; 37518357Ssam char *cp; 37618357Ssam int n; 37718357Ssam { 37828705Smckusick struct winsize w; 37918357Ssam 38028705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 38118357Ssam return (0); 38225423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 38328705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 38428705Smckusick w.ws_row = ntohs(w.ws_row); 38528705Smckusick w.ws_col = ntohs(w.ws_col); 38628705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 38728705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 38828705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 38928705Smckusick return (4+sizeof (w)); 39018357Ssam } 39118357Ssam 39218357Ssam /* 39318357Ssam * rlogin "protocol" machine. 39418357Ssam */ 39518357Ssam protocol(f, p) 39640917Skarels register int f, p; 39718357Ssam { 39840917Skarels char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 39918357Ssam register pcc = 0, fcc = 0; 40040917Skarels int cc, nfd, n; 40125740Skarels char cntl; 40218357Ssam 40318482Ssam /* 40418484Ssam * Must ignore SIGTTOU, otherwise we'll stop 40518484Ssam * when we try and set slave pty's window shape 40625423Skarels * (our controlling tty is the master pty). 40718482Ssam */ 40818484Ssam (void) signal(SIGTTOU, SIG_IGN); 40925423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 41036517Skarels if (f > p) 41136517Skarels nfd = f + 1; 41236517Skarels else 41336517Skarels nfd = p + 1; 41440917Skarels if (nfd > FD_SETSIZE) { 41540917Skarels syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 41640917Skarels fatal(f, "internal error (select mask too small)", 0); 41740917Skarels } 41818357Ssam for (;;) { 41940917Skarels fd_set ibits, obits, ebits, *omask; 42018357Ssam 42140917Skarels FD_ZERO(&ibits); 42240917Skarels FD_ZERO(&obits); 42340917Skarels omask = (fd_set *)NULL; 42440917Skarels if (fcc) { 42540917Skarels FD_SET(p, &obits); 42640917Skarels omask = &obits; 42740917Skarels } else 42840917Skarels FD_SET(f, &ibits); 42918357Ssam if (pcc >= 0) 43040917Skarels if (pcc) { 43140917Skarels FD_SET(f, &obits); 43240917Skarels omask = &obits; 43340917Skarels } else 43440917Skarels FD_SET(p, &ibits); 43540917Skarels FD_SET(p, &ebits); 43640917Skarels if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 43718357Ssam if (errno == EINTR) 4386446Swnj continue; 43940917Skarels fatal(f, "select", 1); 44018357Ssam } 44140917Skarels if (n == 0) { 44218357Ssam /* shouldn't happen... */ 44318357Ssam sleep(5); 44418357Ssam continue; 44518357Ssam } 44625740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 44740917Skarels if (FD_ISSET(p, &ebits)) { 44825740Skarels cc = read(p, &cntl, 1); 44925740Skarels if (cc == 1 && pkcontrol(cntl)) { 45025740Skarels cntl |= oobdata[0]; 45125740Skarels send(f, &cntl, 1, MSG_OOB); 45225740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 45325740Skarels pcc = 0; 45440917Skarels FD_CLR(p, &ibits); 45525740Skarels } 45625740Skarels } 45725740Skarels } 45840917Skarels if (FD_ISSET(f, &ibits)) { 45940917Skarels #ifdef KERBEROS 46040917Skarels if (encrypt) 46140917Skarels fcc = des_read(f, fibuf, sizeof(fibuf)); 46240917Skarels else 46340917Skarels #endif 46440917Skarels fcc = read(f, fibuf, sizeof(fibuf)); 46518357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 46618357Ssam fcc = 0; 46718357Ssam else { 46818357Ssam register char *cp; 46918357Ssam int left, n; 47018357Ssam 47118357Ssam if (fcc <= 0) 47216227Skarels break; 47318357Ssam fbp = fibuf; 47424723Smckusick 47518357Ssam top: 47625423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 47718357Ssam if (cp[0] == magic[0] && 47818357Ssam cp[1] == magic[1]) { 47918357Ssam left = fcc - (cp-fibuf); 48018357Ssam n = control(p, cp, left); 48118357Ssam if (n) { 48218357Ssam left -= n; 48318357Ssam if (left > 0) 48425423Skarels bcopy(cp+n, cp, left); 48518357Ssam fcc -= n; 48618357Ssam goto top; /* n^2 */ 48725423Skarels } 48825423Skarels } 48940917Skarels FD_SET(p, &obits); /* try write */ 49025423Skarels } 49125423Skarels } 49224723Smckusick 49340917Skarels if (FD_ISSET(p, &obits) && fcc > 0) { 49425423Skarels cc = write(p, fbp, fcc); 49524723Smckusick if (cc > 0) { 49624723Smckusick fcc -= cc; 49724723Smckusick fbp += cc; 4986446Swnj } 49918357Ssam } 50024723Smckusick 50140917Skarels if (FD_ISSET(p, &ibits)) { 50218357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 50318357Ssam pbp = pibuf; 50418357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 50518357Ssam pcc = 0; 50618357Ssam else if (pcc <= 0) 50718357Ssam break; 50836517Skarels else if (pibuf[0] == 0) { 50918357Ssam pbp++, pcc--; 51040917Skarels #ifdef KERBEROS 51140917Skarels if (!encrypt) 51240917Skarels #endif 51340917Skarels FD_SET(f, &obits); /* try write */ 51436517Skarels } else { 51518357Ssam if (pkcontrol(pibuf[0])) { 51625423Skarels pibuf[0] |= oobdata[0]; 51718357Ssam send(f, &pibuf[0], 1, MSG_OOB); 51816227Skarels } 51918357Ssam pcc = 0; 5206446Swnj } 52118357Ssam } 52240917Skarels if ((FD_ISSET(f, &obits)) && pcc > 0) { 52340917Skarels #ifdef KERBEROS 52440917Skarels if (encrypt) 52540917Skarels cc = des_write(f, pbp, pcc); 52640917Skarels else 52740917Skarels #endif 52840917Skarels cc = write(f, pbp, pcc); 52925423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 53040917Skarels /* 53140917Skarels * This happens when we try write after read 53240917Skarels * from p, but some old kernels balk at large 53340917Skarels * writes even when select returns true. 53440917Skarels */ 53540917Skarels if (!FD_ISSET(p, &ibits)) 53640917Skarels sleep(5); 53725423Skarels continue; 53825423Skarels } 53918357Ssam if (cc > 0) { 54018357Ssam pcc -= cc; 54118357Ssam pbp += cc; 54218357Ssam } 5436446Swnj } 5446446Swnj } 5456446Swnj } 5466446Swnj 5476446Swnj cleanup() 5486446Swnj { 54935440Sbostic char *p; 55035440Sbostic 55140917Skarels p = line + sizeof(_PATH_DEV) - 1; 55235440Sbostic if (logout(p)) 55335440Sbostic logwtmp(p, "", ""); 55435440Sbostic (void)chmod(line, 0666); 55535440Sbostic (void)chown(line, 0, 0); 55635440Sbostic *p = 'p'; 55735440Sbostic (void)chmod(line, 0666); 55835440Sbostic (void)chown(line, 0, 0); 55910192Ssam shutdown(netf, 2); 5606446Swnj exit(1); 5616446Swnj } 5626446Swnj 56340917Skarels fatal(f, msg, syserr) 56440917Skarels int f, syserr; 5659242Ssam char *msg; 5669242Ssam { 56740917Skarels int len; 56840917Skarels char buf[BUFSIZ], *bp = buf; 5699242Ssam 57040917Skarels /* 57140917Skarels * Prepend binary one to message if we haven't sent 57240917Skarels * the magic null as confirmation. 57340917Skarels */ 57440917Skarels if (!confirmed) 57540917Skarels *bp++ = '\01'; /* error indicator */ 57640917Skarels if (syserr) 57740917Skarels len = sprintf(bp, "rlogind: %s: %s.\r\n", 57840917Skarels msg, strerror(errno)); 57940917Skarels else 58040917Skarels len = sprintf(bp, "rlogind: %s.\r\n", msg); 58140917Skarels (void) write(f, buf, bp + len - buf); 5829242Ssam exit(1); 5839242Ssam } 5849242Ssam 58536453Skfall do_rlogin(host) 58636518Skarels char *host; 58736453Skfall { 58836518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 58936518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 59036518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 59136518Skarels 59236518Skarels if (getuid()) 59336453Skfall return(-1); 59436453Skfall pwd = getpwnam(lusername); 59536518Skarels if (pwd == NULL) 59636453Skfall return(-1); 59736453Skfall return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 59836453Skfall } 59936453Skfall 60036453Skfall 60136518Skarels getstr(buf, cnt, errmsg) 60236518Skarels char *buf; 60336518Skarels int cnt; 60436518Skarels char *errmsg; 60536453Skfall { 60636518Skarels char c; 60736518Skarels 60836453Skfall do { 60936518Skarels if (read(0, &c, 1) != 1) 61036453Skfall exit(1); 61136518Skarels if (--cnt < 0) 61240917Skarels fatal(STDOUT_FILENO, errmsg, 0); 61336453Skfall *buf++ = c; 61436518Skarels } while (c != 0); 61536453Skfall } 61636453Skfall 61736518Skarels extern char **environ; 61836453Skfall 61936519Skarels setup_term(fd) 62036519Skarels int fd; 62136519Skarels { 62240917Skarels register char *cp = index(term+ENVSIZE, '/'); 62336519Skarels char *speed; 62439118Skarels struct termios tt; 62536519Skarels 62640917Skarels #ifndef notyet 62736711Skfall tcgetattr(fd, &tt); 62836519Skarels if (cp) { 62936519Skarels *cp++ = '\0'; 63036519Skarels speed = cp; 63136519Skarels cp = index(speed, '/'); 63236519Skarels if (cp) 63336519Skarels *cp++ = '\0'; 63436711Skfall cfsetspeed(&tt, atoi(speed)); 63536519Skarels } 63638710Skfall 63739118Skarels tt.c_iflag = TTYDEF_IFLAG; 63839118Skarels tt.c_oflag = TTYDEF_OFLAG; 63939118Skarels tt.c_lflag = TTYDEF_LFLAG; 64039118Skarels tcsetattr(fd, TCSADFLUSH, &tt); 64139118Skarels #else 64239118Skarels if (cp) { 64339118Skarels *cp++ = '\0'; 64439118Skarels speed = cp; 64539118Skarels cp = index(speed, '/'); 64639118Skarels if (cp) 64739118Skarels *cp++ = '\0'; 64840917Skarels tcgetattr(fd, &tt); 64940917Skarels cfsetspeed(&tt, atoi(speed)); 65040917Skarels tcsetattr(fd, TCSADFLUSH, &tt); 65138710Skfall } 65238710Skfall #endif 65336519Skarels 65436519Skarels env[0] = term; 65536519Skarels env[1] = 0; 65636519Skarels environ = env; 65736519Skarels } 65836609Skfall 65940917Skarels #ifdef KERBEROS 66040917Skarels #define VERSION_SIZE 9 66140917Skarels 66236609Skfall /* 66340917Skarels * Do the remote kerberos login to the named host with the 66440917Skarels * given inet address 66540917Skarels * 66640917Skarels * Return 0 on valid authorization 66740917Skarels * Return -1 on valid authentication, no authorization 66840917Skarels * Return >0 for error conditions 66940917Skarels */ 67040917Skarels do_krb_login(host, dest, encrypt) 67140917Skarels char *host; 67240917Skarels struct sockaddr_in *dest; 67340917Skarels int encrypt; 67440917Skarels { 67540917Skarels int rc; 67640917Skarels char instance[INST_SZ], version[VERSION_SIZE]; 67740917Skarels long authopts = 0L; /* !mutual */ 67840917Skarels struct sockaddr_in faddr; 67940917Skarels 68040917Skarels if (getuid()) 68140917Skarels return(KFAILURE); 68240917Skarels 68340917Skarels kdata = (AUTH_DAT *) auth_buf; 68440917Skarels ticket = (KTEXT) tick_buf; 68540917Skarels strcpy(instance, "*"); 68640917Skarels 68740917Skarels if (encrypt) { 68840917Skarels rc = sizeof(faddr); 68940917Skarels if (getsockname(0, &faddr, &rc)) 69040917Skarels return(-1); 69140917Skarels authopts = KOPT_DO_MUTUAL; 69240917Skarels rc = krb_recvauth( 69340917Skarels authopts, 0, 69440917Skarels ticket, "rcmd", 69540917Skarels instance, dest, &faddr, 69640917Skarels kdata, "", schedule, version); 69740917Skarels des_set_key(kdata->session, schedule); 69840917Skarels 69940917Skarels } else { 70040917Skarels rc = krb_recvauth( 70140917Skarels authopts, 0, 70240917Skarels ticket, "rcmd", 70340917Skarels instance, dest, (struct sockaddr_in *) 0, 70440917Skarels kdata, "", (bit_64 *) 0, version); 70540917Skarels } 70640917Skarels 70740917Skarels if (rc != KSUCCESS) 70840917Skarels return(rc); 70940917Skarels 71040917Skarels getstr(lusername, sizeof(lusername), "locuser"); 71140917Skarels /* get the "cmd" in the rcmd protocol */ 71240917Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 71340917Skarels 71440917Skarels pwd = getpwnam(lusername); 71540917Skarels if (pwd == NULL) 71640917Skarels return(-1); 71740917Skarels 71840917Skarels /* returns nonzero for no access */ 71940917Skarels /* return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); */ 72040917Skarels if (kuserok(kdata,lusername) != 0) 72140917Skarels return(-1); 72240917Skarels 72340917Skarels return(0); 72440917Skarels 72540917Skarels } 72640917Skarels #endif /* KERBEROS */ 72740917Skarels 72840917Skarels usage() 72940917Skarels { 73040917Skarels #ifdef KERBEROS 73140917Skarels syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]"); 73240917Skarels #else 73340917Skarels syslog(LOG_ERR, "usage: rlogind [-aln]"); 73440917Skarels #endif 73540917Skarels } 73640917Skarels 73740917Skarels /* 73836631Skarels * Check whether host h is in our local domain, 73939058Skarels * defined as sharing the last two components of the domain part, 74039058Skarels * or the entire domain part if the local domain has only one component. 74136631Skarels * If either name is unqualified (contains no '.'), 74236631Skarels * assume that the host is local, as it will be 74336631Skarels * interpreted as such. 74436631Skarels */ 74536631Skarels local_domain(h) 74636631Skarels char *h; 74736625Skfall { 74836631Skarels char localhost[MAXHOSTNAMELEN]; 74939058Skarels char *p1, *p2, *topdomain(); 75036631Skarels 75139058Skarels localhost[0] = 0; 75236631Skarels (void) gethostname(localhost, sizeof(localhost)); 75339058Skarels p1 = topdomain(localhost); 75439058Skarels p2 = topdomain(h); 75536631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 75636625Skfall return(1); 75736625Skfall return(0); 75836625Skfall } 75939058Skarels 76039058Skarels char * 76139058Skarels topdomain(h) 76239058Skarels char *h; 76339058Skarels { 76439058Skarels register char *p; 76539058Skarels char *maybe = NULL; 76639058Skarels int dots = 0; 76739058Skarels 76839058Skarels for (p = h + strlen(h); p >= h; p--) { 76939058Skarels if (*p == '.') { 77039058Skarels if (++dots == 2) 77139058Skarels return (p); 77239058Skarels maybe = p; 77339058Skarels } 77439058Skarels } 77539058Skarels return (maybe); 77639058Skarels } 777