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*43363Skfall static char sccsid[] = "@(#)rlogind.c 5.46 (Berkeley) 06/21/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); 299*43363Skfall #ifdef notdef 300*43363Skfall vhangup(); 301*43363Skfall #endif 30234424Sbostic (void)signal(SIGHUP, SIG_DFL); 30334424Sbostic t = open(line, O_RDWR); 30434424Sbostic if (t < 0) 30540917Skarels fatal(f, line, 1); 30636453Skfall setup_term(t); 30740917Skarels if (confirmed == 0) { 30840917Skarels write(f, "", 1); 30940917Skarels confirmed = 1; /* we sent the null! */ 31039249Smarc } 31140917Skarels #ifdef KERBEROS 31240917Skarels if (encrypt) 31340917Skarels (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 31440917Skarels 31540917Skarels if (use_kerberos == 0) 31639249Smarc #endif 31740917Skarels if (!authenticated && !hostok) 31840917Skarels write(f, "rlogind: Host address mismatch.\r\n", 31940917Skarels sizeof("rlogind: Host address mismatch.\r\n") - 1); 32040917Skarels 3219242Ssam pid = fork(); 3229242Ssam if (pid < 0) 32340917Skarels fatal(f, "", 1); 32418357Ssam if (pid == 0) { 32536711Skfall if (setsid() < 0) 32640917Skarels fatal(f, "setsid", 1); 32736711Skfall if (ioctl(t, TIOCSCTTY, 0) < 0) 32840917Skarels fatal(f, "ioctl(sctty)", 1); 32940917Skarels (void)close(f); 33040917Skarels (void)close(p); 33140917Skarels dup2(t, STDIN_FILENO); 33240917Skarels dup2(t, STDOUT_FILENO); 33340917Skarels dup2(t, STDERR_FILENO); 33440917Skarels (void)close(t); 33540917Skarels 336*43363Skfall if (authenticated) { 337*43363Skfall if (use_kerberos && (pwd->pw_uid == 0)) 338*43363Skfall syslog(LOG_INFO|LOG_AUTH, 339*43363Skfall "ROOT Kerberos login from %s.%s@%s on %s\n", 340*43363Skfall kdata->pname, kdata->pinst, kdata->prealm, 341*43363Skfall hp->h_name); 342*43363Skfall 34340917Skarels execl(_PATH_LOGIN, "login", "-p", 34440917Skarels "-h", hp->h_name, "-f", lusername, 0); 345*43363Skfall } else 34640917Skarels execl(_PATH_LOGIN, "login", "-p", 34740917Skarels "-h", hp->h_name, lusername, 0); 34840917Skarels fatal(STDERR_FILENO, _PATH_LOGIN, 1); 34918357Ssam /*NOTREACHED*/ 35018357Ssam } 35118357Ssam close(t); 35236453Skfall 35340917Skarels #ifdef KERBEROS 35440917Skarels /* 35540917Skarels * If encrypted, don't turn on NBIO or the des read/write 35640917Skarels * routines will croak. 35740917Skarels */ 35840917Skarels 35940917Skarels if (!encrypt) 36040917Skarels #endif 36140917Skarels ioctl(f, FIONBIO, &on); 36218357Ssam ioctl(p, FIONBIO, &on); 36318357Ssam ioctl(p, TIOCPKT, &on); 36418357Ssam signal(SIGCHLD, cleanup); 36518357Ssam protocol(f, p); 36630600Smckusick signal(SIGCHLD, SIG_IGN); 36718357Ssam cleanup(); 36818357Ssam } 3699242Ssam 37018357Ssam char magic[2] = { 0377, 0377 }; 37125423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 37218357Ssam 37318357Ssam /* 37418357Ssam * Handle a "control" request (signaled by magic being present) 37518357Ssam * in the data stream. For now, we are only willing to handle 37618357Ssam * window size changes. 37718357Ssam */ 37818357Ssam control(pty, cp, n) 37918357Ssam int pty; 38018357Ssam char *cp; 38118357Ssam int n; 38218357Ssam { 38328705Smckusick struct winsize w; 38418357Ssam 38528705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 38618357Ssam return (0); 38725423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 38828705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 38928705Smckusick w.ws_row = ntohs(w.ws_row); 39028705Smckusick w.ws_col = ntohs(w.ws_col); 39128705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 39228705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 39328705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 39428705Smckusick return (4+sizeof (w)); 39518357Ssam } 39618357Ssam 39718357Ssam /* 39818357Ssam * rlogin "protocol" machine. 39918357Ssam */ 40018357Ssam protocol(f, p) 40140917Skarels register int f, p; 40218357Ssam { 40340917Skarels char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 40418357Ssam register pcc = 0, fcc = 0; 40540917Skarels int cc, nfd, n; 40625740Skarels char cntl; 40718357Ssam 40818482Ssam /* 40918484Ssam * Must ignore SIGTTOU, otherwise we'll stop 41018484Ssam * when we try and set slave pty's window shape 41125423Skarels * (our controlling tty is the master pty). 41218482Ssam */ 41318484Ssam (void) signal(SIGTTOU, SIG_IGN); 41425423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 41536517Skarels if (f > p) 41636517Skarels nfd = f + 1; 41736517Skarels else 41836517Skarels nfd = p + 1; 41940917Skarels if (nfd > FD_SETSIZE) { 42040917Skarels syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 42140917Skarels fatal(f, "internal error (select mask too small)", 0); 42240917Skarels } 42318357Ssam for (;;) { 42440917Skarels fd_set ibits, obits, ebits, *omask; 42518357Ssam 42642956Sbostic FD_ZERO(&ebits); 42740917Skarels FD_ZERO(&ibits); 42840917Skarels FD_ZERO(&obits); 42940917Skarels omask = (fd_set *)NULL; 43040917Skarels if (fcc) { 43140917Skarels FD_SET(p, &obits); 43240917Skarels omask = &obits; 43340917Skarels } else 43440917Skarels FD_SET(f, &ibits); 43518357Ssam if (pcc >= 0) 43640917Skarels if (pcc) { 43740917Skarels FD_SET(f, &obits); 43840917Skarels omask = &obits; 43940917Skarels } else 44040917Skarels FD_SET(p, &ibits); 44140917Skarels FD_SET(p, &ebits); 44240917Skarels if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 44318357Ssam if (errno == EINTR) 4446446Swnj continue; 44540917Skarels fatal(f, "select", 1); 44618357Ssam } 44740917Skarels if (n == 0) { 44818357Ssam /* shouldn't happen... */ 44918357Ssam sleep(5); 45018357Ssam continue; 45118357Ssam } 45225740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 45340917Skarels if (FD_ISSET(p, &ebits)) { 45425740Skarels cc = read(p, &cntl, 1); 45525740Skarels if (cc == 1 && pkcontrol(cntl)) { 45625740Skarels cntl |= oobdata[0]; 45725740Skarels send(f, &cntl, 1, MSG_OOB); 45825740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 45925740Skarels pcc = 0; 46040917Skarels FD_CLR(p, &ibits); 46125740Skarels } 46225740Skarels } 46325740Skarels } 46440917Skarels if (FD_ISSET(f, &ibits)) { 46540917Skarels #ifdef KERBEROS 46640917Skarels if (encrypt) 46740917Skarels fcc = des_read(f, fibuf, sizeof(fibuf)); 46840917Skarels else 46940917Skarels #endif 47040917Skarels fcc = read(f, fibuf, sizeof(fibuf)); 47118357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 47218357Ssam fcc = 0; 47318357Ssam else { 47418357Ssam register char *cp; 47518357Ssam int left, n; 47618357Ssam 47718357Ssam if (fcc <= 0) 47816227Skarels break; 47918357Ssam fbp = fibuf; 48024723Smckusick 48118357Ssam top: 48225423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 48318357Ssam if (cp[0] == magic[0] && 48418357Ssam cp[1] == magic[1]) { 48518357Ssam left = fcc - (cp-fibuf); 48618357Ssam n = control(p, cp, left); 48718357Ssam if (n) { 48818357Ssam left -= n; 48918357Ssam if (left > 0) 49025423Skarels bcopy(cp+n, cp, left); 49118357Ssam fcc -= n; 49218357Ssam goto top; /* n^2 */ 49325423Skarels } 49425423Skarels } 49540917Skarels FD_SET(p, &obits); /* try write */ 49625423Skarels } 49725423Skarels } 49824723Smckusick 49940917Skarels if (FD_ISSET(p, &obits) && fcc > 0) { 50025423Skarels cc = write(p, fbp, fcc); 50124723Smckusick if (cc > 0) { 50224723Smckusick fcc -= cc; 50324723Smckusick fbp += cc; 5046446Swnj } 50518357Ssam } 50624723Smckusick 50740917Skarels if (FD_ISSET(p, &ibits)) { 50818357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 50918357Ssam pbp = pibuf; 51018357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 51118357Ssam pcc = 0; 51218357Ssam else if (pcc <= 0) 51318357Ssam break; 51436517Skarels else if (pibuf[0] == 0) { 51518357Ssam pbp++, pcc--; 51640917Skarels #ifdef KERBEROS 51740917Skarels if (!encrypt) 51840917Skarels #endif 51940917Skarels FD_SET(f, &obits); /* try write */ 52036517Skarels } else { 52118357Ssam if (pkcontrol(pibuf[0])) { 52225423Skarels pibuf[0] |= oobdata[0]; 52318357Ssam send(f, &pibuf[0], 1, MSG_OOB); 52416227Skarels } 52518357Ssam pcc = 0; 5266446Swnj } 52718357Ssam } 52840917Skarels if ((FD_ISSET(f, &obits)) && pcc > 0) { 52940917Skarels #ifdef KERBEROS 53040917Skarels if (encrypt) 53140917Skarels cc = des_write(f, pbp, pcc); 53240917Skarels else 53340917Skarels #endif 53440917Skarels cc = write(f, pbp, pcc); 53525423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 53640917Skarels /* 53740917Skarels * This happens when we try write after read 53840917Skarels * from p, but some old kernels balk at large 53940917Skarels * writes even when select returns true. 54040917Skarels */ 54140917Skarels if (!FD_ISSET(p, &ibits)) 54240917Skarels sleep(5); 54325423Skarels continue; 54425423Skarels } 54518357Ssam if (cc > 0) { 54618357Ssam pcc -= cc; 54718357Ssam pbp += cc; 54818357Ssam } 5496446Swnj } 5506446Swnj } 5516446Swnj } 5526446Swnj 5536446Swnj cleanup() 5546446Swnj { 55535440Sbostic char *p; 55635440Sbostic 55740917Skarels p = line + sizeof(_PATH_DEV) - 1; 55835440Sbostic if (logout(p)) 55935440Sbostic logwtmp(p, "", ""); 56035440Sbostic (void)chmod(line, 0666); 56135440Sbostic (void)chown(line, 0, 0); 56235440Sbostic *p = 'p'; 56335440Sbostic (void)chmod(line, 0666); 56435440Sbostic (void)chown(line, 0, 0); 56510192Ssam shutdown(netf, 2); 5666446Swnj exit(1); 5676446Swnj } 5686446Swnj 56940917Skarels fatal(f, msg, syserr) 57040917Skarels int f, syserr; 5719242Ssam char *msg; 5729242Ssam { 57340917Skarels int len; 57440917Skarels char buf[BUFSIZ], *bp = buf; 5759242Ssam 57640917Skarels /* 57740917Skarels * Prepend binary one to message if we haven't sent 57840917Skarels * the magic null as confirmation. 57940917Skarels */ 58040917Skarels if (!confirmed) 58140917Skarels *bp++ = '\01'; /* error indicator */ 58240917Skarels if (syserr) 58340917Skarels len = sprintf(bp, "rlogind: %s: %s.\r\n", 58440917Skarels msg, strerror(errno)); 58540917Skarels else 58640917Skarels len = sprintf(bp, "rlogind: %s.\r\n", msg); 58740917Skarels (void) write(f, buf, bp + len - buf); 5889242Ssam exit(1); 5899242Ssam } 5909242Ssam 59136453Skfall do_rlogin(host) 59236518Skarels char *host; 59336453Skfall { 59436518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 59536518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 59636518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 59736518Skarels 59836453Skfall pwd = getpwnam(lusername); 59936518Skarels if (pwd == NULL) 60036453Skfall return(-1); 60142264Sbostic if (pwd->pw_uid == 0) 60242264Sbostic return(-1); 60342264Sbostic return(ruserok(host, 0, rusername, lusername)); 60436453Skfall } 60536453Skfall 60636453Skfall 60736518Skarels getstr(buf, cnt, errmsg) 60836518Skarels char *buf; 60936518Skarels int cnt; 61036518Skarels char *errmsg; 61136453Skfall { 61236518Skarels char c; 61336518Skarels 61436453Skfall do { 61536518Skarels if (read(0, &c, 1) != 1) 61636453Skfall exit(1); 61736518Skarels if (--cnt < 0) 61840917Skarels fatal(STDOUT_FILENO, errmsg, 0); 61936453Skfall *buf++ = c; 62036518Skarels } while (c != 0); 62136453Skfall } 62236453Skfall 62336518Skarels extern char **environ; 62436453Skfall 62536519Skarels setup_term(fd) 62636519Skarels int fd; 62736519Skarels { 62840917Skarels register char *cp = index(term+ENVSIZE, '/'); 62936519Skarels char *speed; 63039118Skarels struct termios tt; 63136519Skarels 63240917Skarels #ifndef notyet 63336711Skfall tcgetattr(fd, &tt); 63436519Skarels if (cp) { 63536519Skarels *cp++ = '\0'; 63636519Skarels speed = cp; 63736519Skarels cp = index(speed, '/'); 63836519Skarels if (cp) 63936519Skarels *cp++ = '\0'; 64036711Skfall cfsetspeed(&tt, atoi(speed)); 64136519Skarels } 64238710Skfall 64339118Skarels tt.c_iflag = TTYDEF_IFLAG; 64439118Skarels tt.c_oflag = TTYDEF_OFLAG; 64539118Skarels tt.c_lflag = TTYDEF_LFLAG; 64643272Sbostic tcsetattr(fd, TCSAFLUSH, &tt); 64739118Skarels #else 64839118Skarels if (cp) { 64939118Skarels *cp++ = '\0'; 65039118Skarels speed = cp; 65139118Skarels cp = index(speed, '/'); 65239118Skarels if (cp) 65339118Skarels *cp++ = '\0'; 65440917Skarels tcgetattr(fd, &tt); 65540917Skarels cfsetspeed(&tt, atoi(speed)); 65643272Sbostic tcsetattr(fd, TCSAFLUSH, &tt); 65738710Skfall } 65838710Skfall #endif 65936519Skarels 66036519Skarels env[0] = term; 66136519Skarels env[1] = 0; 66236519Skarels environ = env; 66336519Skarels } 66436609Skfall 66540917Skarels #ifdef KERBEROS 66640917Skarels #define VERSION_SIZE 9 66740917Skarels 66836609Skfall /* 66940917Skarels * Do the remote kerberos login to the named host with the 67040917Skarels * given inet address 67140917Skarels * 67240917Skarels * Return 0 on valid authorization 67340917Skarels * Return -1 on valid authentication, no authorization 67440917Skarels * Return >0 for error conditions 67540917Skarels */ 67640917Skarels do_krb_login(host, dest, encrypt) 67740917Skarels char *host; 67840917Skarels struct sockaddr_in *dest; 67940917Skarels int encrypt; 68040917Skarels { 68140917Skarels int rc; 68240917Skarels char instance[INST_SZ], version[VERSION_SIZE]; 68340917Skarels long authopts = 0L; /* !mutual */ 68440917Skarels struct sockaddr_in faddr; 68540917Skarels 68640917Skarels kdata = (AUTH_DAT *) auth_buf; 68740917Skarels ticket = (KTEXT) tick_buf; 68840917Skarels 68942264Sbostic instance[0] = '*'; 69042264Sbostic instance[1] = '\0'; 69142264Sbostic 69240917Skarels if (encrypt) { 69340917Skarels rc = sizeof(faddr); 69440917Skarels if (getsockname(0, &faddr, &rc)) 69540917Skarels return(-1); 69640917Skarels authopts = KOPT_DO_MUTUAL; 69740917Skarels rc = krb_recvauth( 69840917Skarels authopts, 0, 69940917Skarels ticket, "rcmd", 70040917Skarels instance, dest, &faddr, 70140917Skarels kdata, "", schedule, version); 70240917Skarels des_set_key(kdata->session, schedule); 70340917Skarels 70440917Skarels } else { 70540917Skarels rc = krb_recvauth( 70640917Skarels authopts, 0, 70740917Skarels ticket, "rcmd", 70840917Skarels instance, dest, (struct sockaddr_in *) 0, 70940917Skarels kdata, "", (bit_64 *) 0, version); 71040917Skarels } 71140917Skarels 71240917Skarels if (rc != KSUCCESS) 71340917Skarels return(rc); 71440917Skarels 71540917Skarels getstr(lusername, sizeof(lusername), "locuser"); 71640917Skarels /* get the "cmd" in the rcmd protocol */ 71740917Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 71840917Skarels 71940917Skarels pwd = getpwnam(lusername); 72040917Skarels if (pwd == NULL) 72140917Skarels return(-1); 72240917Skarels 72340917Skarels /* returns nonzero for no access */ 72440917Skarels if (kuserok(kdata,lusername) != 0) 72540917Skarels return(-1); 72640917Skarels 72740917Skarels return(0); 72840917Skarels 72940917Skarels } 73040917Skarels #endif /* KERBEROS */ 73140917Skarels 73240917Skarels usage() 73340917Skarels { 73440917Skarels #ifdef KERBEROS 73540917Skarels syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]"); 73640917Skarels #else 73740917Skarels syslog(LOG_ERR, "usage: rlogind [-aln]"); 73840917Skarels #endif 73940917Skarels } 74040917Skarels 74140917Skarels /* 74236631Skarels * Check whether host h is in our local domain, 74339058Skarels * defined as sharing the last two components of the domain part, 74439058Skarels * or the entire domain part if the local domain has only one component. 74536631Skarels * If either name is unqualified (contains no '.'), 74636631Skarels * assume that the host is local, as it will be 74736631Skarels * interpreted as such. 74836631Skarels */ 74936631Skarels local_domain(h) 75036631Skarels char *h; 75136625Skfall { 75236631Skarels char localhost[MAXHOSTNAMELEN]; 75339058Skarels char *p1, *p2, *topdomain(); 75436631Skarels 75539058Skarels localhost[0] = 0; 75636631Skarels (void) gethostname(localhost, sizeof(localhost)); 75739058Skarels p1 = topdomain(localhost); 75839058Skarels p2 = topdomain(h); 75936631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 76036625Skfall return(1); 76136625Skfall return(0); 76236625Skfall } 76339058Skarels 76439058Skarels char * 76539058Skarels topdomain(h) 76639058Skarels char *h; 76739058Skarels { 76839058Skarels register char *p; 76939058Skarels char *maybe = NULL; 77039058Skarels int dots = 0; 77139058Skarels 77239058Skarels for (p = h + strlen(h); p >= h; p--) { 77339058Skarels if (*p == '.') { 77439058Skarels if (++dots == 2) 77539058Skarels return (p); 77639058Skarels maybe = p; 77739058Skarels } 77839058Skarels } 77939058Skarels return (maybe); 78039058Skarels } 781