121174Sdist /* 2*40917Skarels * 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[] = 20*40917Skarels "@(#) 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*40917Skarels static char sccsid[] = "@(#)rlogind.c 5.40 (Berkeley) 04/13/90"; 2635441Sbostic #endif /* not lint */ 2721174Sdist 28*40917Skarels #ifdef KERBEROS 29*40917Skarels /* From: 30*40917Skarels * $Source: /mit/kerberos/ucb/mit/rlogind/RCS/rlogind.c,v $ 31*40917Skarels * $Header: rlogind.c,v 5.0 89/06/26 18:31:01 kfall Locked $ 32*40917Skarels */ 33*40917Skarels #endif 34*40917Skarels 3516369Skarels /* 3616369Skarels * remote login server: 3736453Skfall * \0 3816369Skarels * remuser\0 3916369Skarels * locuser\0 4036453Skfall * terminal_type/speed\0 4136518Skarels * data 4216369Skarels */ 4316369Skarels 44*40917Skarels #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> 50*40917Skarels #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> 6018357Ssam #include <strings.h> 61*40917Skarels #include <stdio.h> 62*40917Skarels #include <unistd.h> 63*40917Skarels #include "pathnames.h" 646446Swnj 6536518Skarels #ifndef TIOCPKT_WINDOW 6636518Skarels #define TIOCPKT_WINDOW 0x80 6736518Skarels #endif 6836518Skarels 69*40917Skarels #ifdef KERBEROS 70*40917Skarels #include <kerberosIV/krb.h> 71*40917Skarels #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 72*40917Skarels 73*40917Skarels AUTH_DAT *kdata; 74*40917Skarels KTEXT ticket; 75*40917Skarels u_char auth_buf[sizeof(AUTH_DAT)]; 76*40917Skarels u_char tick_buf[sizeof(KTEXT_ST)]; 77*40917Skarels Key_schedule schedule; 78*40917Skarels int encrypt = 0, retval, use_kerberos = 0, vacuous = 0; 79*40917Skarels int do_krb_login(); 80*40917Skarels 81*40917Skarels #define ARGSTR "alnkvx" 82*40917Skarels #else 83*40917Skarels #define ARGSTR "aln" 84*40917Skarels #endif /* KERBEROS */ 85*40917Skarels 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 9436453Skfall #define SUPERUSER(pwd) ((pwd)->pw_uid == 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 { 105*40917Skarels extern int opterr, optind; 106*40917Skarels 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; 114*40917Skarels 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; 125*40917Skarels #ifdef KERBEROS 126*40917Skarels case 'k': 127*40917Skarels use_kerberos = 1; 128*40917Skarels break; 129*40917Skarels case 'v': 130*40917Skarels vacuous = 1; 131*40917Skarels break; 132*40917Skarels case 'x': 133*40917Skarels encrypt = 1; 134*40917Skarels break; 135*40917Skarels #endif 13636319Sbostic case '?': 13736319Sbostic default: 138*40917Skarels usage(); 13936319Sbostic break; 14036319Sbostic } 14136319Sbostic argc -= optind; 14236319Sbostic argv += optind; 14336319Sbostic 144*40917Skarels #ifdef KERBEROS 145*40917Skarels if (use_kerberos && vacuous) { 146*40917Skarels usage(); 147*40917Skarels fatal(STDERR_FILENO, "only one of -k and -v allowed", 0); 148*40917Skarels } 149*40917Skarels #endif 15016369Skarels fromlen = sizeof (from); 15116369Skarels if (getpeername(0, &from, &fromlen) < 0) { 152*40917Skarels syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 153*40917Skarels 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"); 15816369Skarels doit(0, &from); 1596446Swnj } 1606446Swnj 1616446Swnj int child; 1626446Swnj int cleanup(); 1636446Swnj int netf; 1646446Swnj char *line; 165*40917Skarels int confirmed; 16624724Smckusick extern char *inet_ntoa(); 1676446Swnj 16824889Smckusick struct winsize win = { 0, 0, 0, 0 }; 16924723Smckusick 17024889Smckusick 1716446Swnj doit(f, fromp) 1726446Swnj int f; 1736446Swnj struct sockaddr_in *fromp; 1746446Swnj { 17518357Ssam int i, p, t, pid, on = 1; 17636631Skarels int authenticated = 0, hostok = 0; 177*40917Skarels register struct hostent *hp; 17839249Smarc char remotehost[2 * MAXHOSTNAMELEN + 1]; 17924724Smckusick struct hostent hostent; 1808380Ssam char c; 1816446Swnj 1826446Swnj alarm(60); 1836446Swnj read(f, &c, 1); 184*40917Skarels 18539249Smarc if (c != 0) 18636715Skfall exit(1); 187*40917Skarels #ifdef KERBEROS 188*40917Skarels if (vacuous) 189*40917Skarels fatal(f, "Remote host requires Kerberos authentication", 0); 190*40917Skarels #endif 19136453Skfall 1926446Swnj alarm(0); 19316227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 1948380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 1958380Ssam fromp->sin_family); 19611345Ssam if (hp == 0) { 19724724Smckusick /* 19824724Smckusick * Only the name is used below. 19924724Smckusick */ 20024724Smckusick hp = &hostent; 20124724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 20236635Skarels hostok++; 203*40917Skarels } else if (check_all || local_domain(hp->h_name)) { 20436635Skarels /* 20536635Skarels * If name returned by gethostbyaddr is in our domain, 20636635Skarels * attempt to verify that we haven't been fooled by someone 20736635Skarels * in a remote net; look up the name and check that this 20836635Skarels * address corresponds to the name. 20936635Skarels */ 21036635Skarels strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 21136635Skarels remotehost[sizeof(remotehost) - 1] = 0; 21236635Skarels hp = gethostbyname(remotehost); 21336635Skarels if (hp) 21436635Skarels for (; hp->h_addr_list[0]; hp->h_addr_list++) 21536635Skarels if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 21636635Skarels sizeof(fromp->sin_addr))) { 21736635Skarels hostok++; 21836635Skarels break; 21936635Skarels } 22036633Skarels } else 22136635Skarels hostok++; 22236711Skfall 223*40917Skarels #ifdef KERBEROS 224*40917Skarels if (use_kerberos) { 225*40917Skarels retval = do_krb_login(hp->h_name, fromp, encrypt); 226*40917Skarels if (retval == 0 && hostok) 227*40917Skarels authenticated++; 228*40917Skarels else if (retval > 0) 229*40917Skarels fatal(f, krb_err_txt[retval], 0); 230*40917Skarels else if (!hostok) 231*40917Skarels fatal(f, "krlogind: Host address mismatch.", 0); 232*40917Skarels write(f, &c, 1); 233*40917Skarels confirmed = 1; /* we sent the null! */ 234*40917Skarels } else 235*40917Skarels #endif 236*40917Skarels { 237*40917Skarels if (fromp->sin_family != AF_INET || 238*40917Skarels fromp->sin_port >= IPPORT_RESERVED || 239*40917Skarels fromp->sin_port < IPPORT_RESERVED/2) { 240*40917Skarels syslog(LOG_NOTICE, "Connection from %s on illegal port", 241*40917Skarels inet_ntoa(fromp->sin_addr)); 242*40917Skarels fatal(f, "Permission denied", 0); 243*40917Skarels } 24436702Skarels #ifdef IP_OPTIONS 245*40917Skarels { 246*40917Skarels u_char optbuf[BUFSIZ/3], *cp; 247*40917Skarels char lbuf[BUFSIZ], *lp; 248*40917Skarels int optsize = sizeof(optbuf), ipproto; 249*40917Skarels struct protoent *ip; 25036702Skarels 251*40917Skarels if ((ip = getprotobyname("ip")) != NULL) 252*40917Skarels ipproto = ip->p_proto; 253*40917Skarels else 254*40917Skarels ipproto = IPPROTO_IP; 255*40917Skarels if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 256*40917Skarels &optsize) == 0 && optsize != 0) { 257*40917Skarels lp = lbuf; 258*40917Skarels for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 259*40917Skarels sprintf(lp, " %2.2x", *cp); 260*40917Skarels syslog(LOG_NOTICE, 261*40917Skarels "Connection received using IP options (ignored):%s", 262*40917Skarels lbuf); 263*40917Skarels if (setsockopt(0, ipproto, IP_OPTIONS, 264*40917Skarels (char *)NULL, &optsize) != 0) { 265*40917Skarels syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 266*40917Skarels exit(1); 267*40917Skarels } 268*40917Skarels } 269*40917Skarels } 27036702Skarels #endif 271*40917Skarels if (do_rlogin(hp->h_name) == 0 && hostok) 27239249Smarc authenticated++; 27336631Skarels } 27436636Skarels 2756446Swnj for (c = 'p'; c <= 's'; c++) { 2766446Swnj struct stat stb; 2776446Swnj line = "/dev/ptyXX"; 2786446Swnj line[strlen("/dev/pty")] = c; 2796446Swnj line[strlen("/dev/ptyp")] = '0'; 2806446Swnj if (stat(line, &stb) < 0) 2816446Swnj break; 2826446Swnj for (i = 0; i < 16; i++) { 28334424Sbostic line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 28434424Sbostic p = open(line, O_RDWR); 2856446Swnj if (p > 0) 2866446Swnj goto gotpty; 2876446Swnj } 2886446Swnj } 289*40917Skarels fatal(f, "Out of ptys", 0); 2909242Ssam /*NOTREACHED*/ 2916446Swnj gotpty: 29224889Smckusick (void) ioctl(p, TIOCSWINSZ, &win); 29316227Skarels netf = f; 294*40917Skarels line[sizeof(_PATH_DEV) - 1] = 't'; 29534424Sbostic t = open(line, O_RDWR); 29634424Sbostic if (t < 0) 297*40917Skarels fatal(f, line, 1); 29834424Sbostic if (fchmod(t, 0)) 299*40917Skarels fatal(f, line, 1); 30034424Sbostic (void)signal(SIGHUP, SIG_IGN); 30134424Sbostic vhangup(); 30234424Sbostic (void)signal(SIGHUP, SIG_DFL); 30334424Sbostic t = open(line, O_RDWR); 30434424Sbostic if (t < 0) 305*40917Skarels fatal(f, line, 1); 30636453Skfall setup_term(t); 307*40917Skarels if (confirmed == 0) { 308*40917Skarels write(f, "", 1); 309*40917Skarels confirmed = 1; /* we sent the null! */ 31039249Smarc } 311*40917Skarels #ifdef KERBEROS 312*40917Skarels if (encrypt) 313*40917Skarels (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 314*40917Skarels 315*40917Skarels if (use_kerberos == 0) 31639249Smarc #endif 317*40917Skarels if (!authenticated && !hostok) 318*40917Skarels write(f, "rlogind: Host address mismatch.\r\n", 319*40917Skarels sizeof("rlogind: Host address mismatch.\r\n") - 1); 320*40917Skarels 3219242Ssam pid = fork(); 3229242Ssam if (pid < 0) 323*40917Skarels fatal(f, "", 1); 32418357Ssam if (pid == 0) { 32536711Skfall if (setsid() < 0) 326*40917Skarels fatal(f, "setsid", 1); 32736711Skfall if (ioctl(t, TIOCSCTTY, 0) < 0) 328*40917Skarels fatal(f, "ioctl(sctty)", 1); 329*40917Skarels (void)close(f); 330*40917Skarels (void)close(p); 331*40917Skarels dup2(t, STDIN_FILENO); 332*40917Skarels dup2(t, STDOUT_FILENO); 333*40917Skarels dup2(t, STDERR_FILENO); 334*40917Skarels (void)close(t); 335*40917Skarels 33636631Skarels if (authenticated) 337*40917Skarels execl(_PATH_LOGIN, "login", "-p", 338*40917Skarels "-h", hp->h_name, "-f", lusername, 0); 33936525Skfall else 340*40917Skarels execl(_PATH_LOGIN, "login", "-p", 341*40917Skarels "-h", hp->h_name, lusername, 0); 342*40917Skarels fatal(STDERR_FILENO, _PATH_LOGIN, 1); 34318357Ssam /*NOTREACHED*/ 34418357Ssam } 34518357Ssam close(t); 34636453Skfall 347*40917Skarels #ifdef KERBEROS 348*40917Skarels /* 349*40917Skarels * If encrypted, don't turn on NBIO or the des read/write 350*40917Skarels * routines will croak. 351*40917Skarels */ 352*40917Skarels 353*40917Skarels if (!encrypt) 354*40917Skarels #endif 355*40917Skarels ioctl(f, FIONBIO, &on); 35618357Ssam ioctl(p, FIONBIO, &on); 35718357Ssam ioctl(p, TIOCPKT, &on); 35818357Ssam signal(SIGCHLD, cleanup); 35918357Ssam protocol(f, p); 36030600Smckusick signal(SIGCHLD, SIG_IGN); 36118357Ssam cleanup(); 36218357Ssam } 3639242Ssam 36418357Ssam char magic[2] = { 0377, 0377 }; 36525423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 36618357Ssam 36718357Ssam /* 36818357Ssam * Handle a "control" request (signaled by magic being present) 36918357Ssam * in the data stream. For now, we are only willing to handle 37018357Ssam * window size changes. 37118357Ssam */ 37218357Ssam control(pty, cp, n) 37318357Ssam int pty; 37418357Ssam char *cp; 37518357Ssam int n; 37618357Ssam { 37728705Smckusick struct winsize w; 37818357Ssam 37928705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 38018357Ssam return (0); 38125423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 38228705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 38328705Smckusick w.ws_row = ntohs(w.ws_row); 38428705Smckusick w.ws_col = ntohs(w.ws_col); 38528705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 38628705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 38728705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 38828705Smckusick return (4+sizeof (w)); 38918357Ssam } 39018357Ssam 39118357Ssam /* 39218357Ssam * rlogin "protocol" machine. 39318357Ssam */ 39418357Ssam protocol(f, p) 395*40917Skarels register int f, p; 39618357Ssam { 397*40917Skarels char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 39818357Ssam register pcc = 0, fcc = 0; 399*40917Skarels int cc, nfd, n; 40025740Skarels char cntl; 40118357Ssam 40218482Ssam /* 40318484Ssam * Must ignore SIGTTOU, otherwise we'll stop 40418484Ssam * when we try and set slave pty's window shape 40525423Skarels * (our controlling tty is the master pty). 40618482Ssam */ 40718484Ssam (void) signal(SIGTTOU, SIG_IGN); 40825423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 40936517Skarels if (f > p) 41036517Skarels nfd = f + 1; 41136517Skarels else 41236517Skarels nfd = p + 1; 413*40917Skarels if (nfd > FD_SETSIZE) { 414*40917Skarels syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 415*40917Skarels fatal(f, "internal error (select mask too small)", 0); 416*40917Skarels } 41718357Ssam for (;;) { 418*40917Skarels fd_set ibits, obits, ebits, *omask; 41918357Ssam 420*40917Skarels FD_ZERO(&ibits); 421*40917Skarels FD_ZERO(&obits); 422*40917Skarels omask = (fd_set *)NULL; 423*40917Skarels if (fcc) { 424*40917Skarels FD_SET(p, &obits); 425*40917Skarels omask = &obits; 426*40917Skarels } else 427*40917Skarels FD_SET(f, &ibits); 42818357Ssam if (pcc >= 0) 429*40917Skarels if (pcc) { 430*40917Skarels FD_SET(f, &obits); 431*40917Skarels omask = &obits; 432*40917Skarels } else 433*40917Skarels FD_SET(p, &ibits); 434*40917Skarels FD_SET(p, &ebits); 435*40917Skarels if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 43618357Ssam if (errno == EINTR) 4376446Swnj continue; 438*40917Skarels fatal(f, "select", 1); 43918357Ssam } 440*40917Skarels if (n == 0) { 44118357Ssam /* shouldn't happen... */ 44218357Ssam sleep(5); 44318357Ssam continue; 44418357Ssam } 44525740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 446*40917Skarels if (FD_ISSET(p, &ebits)) { 44725740Skarels cc = read(p, &cntl, 1); 44825740Skarels if (cc == 1 && pkcontrol(cntl)) { 44925740Skarels cntl |= oobdata[0]; 45025740Skarels send(f, &cntl, 1, MSG_OOB); 45125740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 45225740Skarels pcc = 0; 453*40917Skarels FD_CLR(p, &ibits); 45425740Skarels } 45525740Skarels } 45625740Skarels } 457*40917Skarels if (FD_ISSET(f, &ibits)) { 458*40917Skarels #ifdef KERBEROS 459*40917Skarels if (encrypt) 460*40917Skarels fcc = des_read(f, fibuf, sizeof(fibuf)); 461*40917Skarels else 462*40917Skarels #endif 463*40917Skarels fcc = read(f, fibuf, sizeof(fibuf)); 46418357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 46518357Ssam fcc = 0; 46618357Ssam else { 46718357Ssam register char *cp; 46818357Ssam int left, n; 46918357Ssam 47018357Ssam if (fcc <= 0) 47116227Skarels break; 47218357Ssam fbp = fibuf; 47324723Smckusick 47418357Ssam top: 47525423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 47618357Ssam if (cp[0] == magic[0] && 47718357Ssam cp[1] == magic[1]) { 47818357Ssam left = fcc - (cp-fibuf); 47918357Ssam n = control(p, cp, left); 48018357Ssam if (n) { 48118357Ssam left -= n; 48218357Ssam if (left > 0) 48325423Skarels bcopy(cp+n, cp, left); 48418357Ssam fcc -= n; 48518357Ssam goto top; /* n^2 */ 48625423Skarels } 48725423Skarels } 488*40917Skarels FD_SET(p, &obits); /* try write */ 48925423Skarels } 49025423Skarels } 49124723Smckusick 492*40917Skarels if (FD_ISSET(p, &obits) && fcc > 0) { 49325423Skarels cc = write(p, fbp, fcc); 49424723Smckusick if (cc > 0) { 49524723Smckusick fcc -= cc; 49624723Smckusick fbp += cc; 4976446Swnj } 49818357Ssam } 49924723Smckusick 500*40917Skarels if (FD_ISSET(p, &ibits)) { 50118357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 50218357Ssam pbp = pibuf; 50318357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 50418357Ssam pcc = 0; 50518357Ssam else if (pcc <= 0) 50618357Ssam break; 50736517Skarels else if (pibuf[0] == 0) { 50818357Ssam pbp++, pcc--; 509*40917Skarels #ifdef KERBEROS 510*40917Skarels if (!encrypt) 511*40917Skarels #endif 512*40917Skarels FD_SET(f, &obits); /* try write */ 51336517Skarels } else { 51418357Ssam if (pkcontrol(pibuf[0])) { 51525423Skarels pibuf[0] |= oobdata[0]; 51618357Ssam send(f, &pibuf[0], 1, MSG_OOB); 51716227Skarels } 51818357Ssam pcc = 0; 5196446Swnj } 52018357Ssam } 521*40917Skarels if ((FD_ISSET(f, &obits)) && pcc > 0) { 522*40917Skarels #ifdef KERBEROS 523*40917Skarels if (encrypt) 524*40917Skarels cc = des_write(f, pbp, pcc); 525*40917Skarels else 526*40917Skarels #endif 527*40917Skarels cc = write(f, pbp, pcc); 52825423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 529*40917Skarels /* 530*40917Skarels * This happens when we try write after read 531*40917Skarels * from p, but some old kernels balk at large 532*40917Skarels * writes even when select returns true. 533*40917Skarels */ 534*40917Skarels if (!FD_ISSET(p, &ibits)) 535*40917Skarels sleep(5); 53625423Skarels continue; 53725423Skarels } 53818357Ssam if (cc > 0) { 53918357Ssam pcc -= cc; 54018357Ssam pbp += cc; 54118357Ssam } 5426446Swnj } 5436446Swnj } 5446446Swnj } 5456446Swnj 5466446Swnj cleanup() 5476446Swnj { 54835440Sbostic char *p; 54935440Sbostic 550*40917Skarels p = line + sizeof(_PATH_DEV) - 1; 55135440Sbostic if (logout(p)) 55235440Sbostic logwtmp(p, "", ""); 55335440Sbostic (void)chmod(line, 0666); 55435440Sbostic (void)chown(line, 0, 0); 55535440Sbostic *p = 'p'; 55635440Sbostic (void)chmod(line, 0666); 55735440Sbostic (void)chown(line, 0, 0); 55810192Ssam shutdown(netf, 2); 5596446Swnj exit(1); 5606446Swnj } 5616446Swnj 562*40917Skarels fatal(f, msg, syserr) 563*40917Skarels int f, syserr; 5649242Ssam char *msg; 5659242Ssam { 566*40917Skarels int len; 567*40917Skarels char buf[BUFSIZ], *bp = buf; 5689242Ssam 569*40917Skarels /* 570*40917Skarels * Prepend binary one to message if we haven't sent 571*40917Skarels * the magic null as confirmation. 572*40917Skarels */ 573*40917Skarels if (!confirmed) 574*40917Skarels *bp++ = '\01'; /* error indicator */ 575*40917Skarels if (syserr) 576*40917Skarels len = sprintf(bp, "rlogind: %s: %s.\r\n", 577*40917Skarels msg, strerror(errno)); 578*40917Skarels else 579*40917Skarels len = sprintf(bp, "rlogind: %s.\r\n", msg); 580*40917Skarels (void) write(f, buf, bp + len - buf); 5819242Ssam exit(1); 5829242Ssam } 5839242Ssam 58436453Skfall do_rlogin(host) 58536518Skarels char *host; 58636453Skfall { 58736518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 58836518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 58936518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 59036518Skarels 59136518Skarels if (getuid()) 59236453Skfall return(-1); 59336453Skfall pwd = getpwnam(lusername); 59436518Skarels if (pwd == NULL) 59536453Skfall return(-1); 59636453Skfall return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 59736453Skfall } 59836453Skfall 59936453Skfall 60036518Skarels getstr(buf, cnt, errmsg) 60136518Skarels char *buf; 60236518Skarels int cnt; 60336518Skarels char *errmsg; 60436453Skfall { 60536518Skarels char c; 60636518Skarels 60736453Skfall do { 60836518Skarels if (read(0, &c, 1) != 1) 60936453Skfall exit(1); 61036518Skarels if (--cnt < 0) 611*40917Skarels fatal(STDOUT_FILENO, errmsg, 0); 61236453Skfall *buf++ = c; 61336518Skarels } while (c != 0); 61436453Skfall } 61536453Skfall 61636518Skarels extern char **environ; 61736453Skfall 61836519Skarels setup_term(fd) 61936519Skarels int fd; 62036519Skarels { 621*40917Skarels register char *cp = index(term+ENVSIZE, '/'); 62236519Skarels char *speed; 62339118Skarels struct termios tt; 62436519Skarels 625*40917Skarels #ifndef notyet 62636711Skfall tcgetattr(fd, &tt); 62736519Skarels if (cp) { 62836519Skarels *cp++ = '\0'; 62936519Skarels speed = cp; 63036519Skarels cp = index(speed, '/'); 63136519Skarels if (cp) 63236519Skarels *cp++ = '\0'; 63336711Skfall cfsetspeed(&tt, atoi(speed)); 63436519Skarels } 63538710Skfall 63639118Skarels tt.c_iflag = TTYDEF_IFLAG; 63739118Skarels tt.c_oflag = TTYDEF_OFLAG; 63839118Skarels tt.c_lflag = TTYDEF_LFLAG; 63939118Skarels tcsetattr(fd, TCSADFLUSH, &tt); 64039118Skarels #else 64139118Skarels if (cp) { 64239118Skarels *cp++ = '\0'; 64339118Skarels speed = cp; 64439118Skarels cp = index(speed, '/'); 64539118Skarels if (cp) 64639118Skarels *cp++ = '\0'; 647*40917Skarels tcgetattr(fd, &tt); 648*40917Skarels cfsetspeed(&tt, atoi(speed)); 649*40917Skarels tcsetattr(fd, TCSADFLUSH, &tt); 65038710Skfall } 65138710Skfall #endif 65236519Skarels 65336519Skarels env[0] = term; 65436519Skarels env[1] = 0; 65536519Skarels environ = env; 65636519Skarels } 65736609Skfall 658*40917Skarels #ifdef KERBEROS 659*40917Skarels #define VERSION_SIZE 9 660*40917Skarels 66136609Skfall /* 662*40917Skarels * Do the remote kerberos login to the named host with the 663*40917Skarels * given inet address 664*40917Skarels * 665*40917Skarels * Return 0 on valid authorization 666*40917Skarels * Return -1 on valid authentication, no authorization 667*40917Skarels * Return >0 for error conditions 668*40917Skarels */ 669*40917Skarels do_krb_login(host, dest, encrypt) 670*40917Skarels char *host; 671*40917Skarels struct sockaddr_in *dest; 672*40917Skarels int encrypt; 673*40917Skarels { 674*40917Skarels int rc; 675*40917Skarels char instance[INST_SZ], version[VERSION_SIZE]; 676*40917Skarels long authopts = 0L; /* !mutual */ 677*40917Skarels struct sockaddr_in faddr; 678*40917Skarels 679*40917Skarels if (getuid()) 680*40917Skarels return(KFAILURE); 681*40917Skarels 682*40917Skarels kdata = (AUTH_DAT *) auth_buf; 683*40917Skarels ticket = (KTEXT) tick_buf; 684*40917Skarels strcpy(instance, "*"); 685*40917Skarels 686*40917Skarels if (encrypt) { 687*40917Skarels rc = sizeof(faddr); 688*40917Skarels if (getsockname(0, &faddr, &rc)) 689*40917Skarels return(-1); 690*40917Skarels authopts = KOPT_DO_MUTUAL; 691*40917Skarels rc = krb_recvauth( 692*40917Skarels authopts, 0, 693*40917Skarels ticket, "rcmd", 694*40917Skarels instance, dest, &faddr, 695*40917Skarels kdata, "", schedule, version); 696*40917Skarels des_set_key(kdata->session, schedule); 697*40917Skarels 698*40917Skarels } else { 699*40917Skarels rc = krb_recvauth( 700*40917Skarels authopts, 0, 701*40917Skarels ticket, "rcmd", 702*40917Skarels instance, dest, (struct sockaddr_in *) 0, 703*40917Skarels kdata, "", (bit_64 *) 0, version); 704*40917Skarels } 705*40917Skarels 706*40917Skarels if (rc != KSUCCESS) 707*40917Skarels return(rc); 708*40917Skarels 709*40917Skarels getstr(lusername, sizeof(lusername), "locuser"); 710*40917Skarels /* get the "cmd" in the rcmd protocol */ 711*40917Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 712*40917Skarels 713*40917Skarels pwd = getpwnam(lusername); 714*40917Skarels if (pwd == NULL) 715*40917Skarels return(-1); 716*40917Skarels 717*40917Skarels /* returns nonzero for no access */ 718*40917Skarels /* return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); */ 719*40917Skarels if (kuserok(kdata,lusername) != 0) 720*40917Skarels return(-1); 721*40917Skarels 722*40917Skarels return(0); 723*40917Skarels 724*40917Skarels } 725*40917Skarels #endif /* KERBEROS */ 726*40917Skarels 727*40917Skarels usage() 728*40917Skarels { 729*40917Skarels #ifdef KERBEROS 730*40917Skarels syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]"); 731*40917Skarels #else 732*40917Skarels syslog(LOG_ERR, "usage: rlogind [-aln]"); 733*40917Skarels #endif 734*40917Skarels } 735*40917Skarels 736*40917Skarels /* 73736631Skarels * Check whether host h is in our local domain, 73839058Skarels * defined as sharing the last two components of the domain part, 73939058Skarels * or the entire domain part if the local domain has only one component. 74036631Skarels * If either name is unqualified (contains no '.'), 74136631Skarels * assume that the host is local, as it will be 74236631Skarels * interpreted as such. 74336631Skarels */ 74436631Skarels local_domain(h) 74536631Skarels char *h; 74636625Skfall { 74736631Skarels char localhost[MAXHOSTNAMELEN]; 74839058Skarels char *p1, *p2, *topdomain(); 74936631Skarels 75039058Skarels localhost[0] = 0; 75136631Skarels (void) gethostname(localhost, sizeof(localhost)); 75239058Skarels p1 = topdomain(localhost); 75339058Skarels p2 = topdomain(h); 75436631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 75536625Skfall return(1); 75636625Skfall return(0); 75736625Skfall } 75839058Skarels 75939058Skarels char * 76039058Skarels topdomain(h) 76139058Skarels char *h; 76239058Skarels { 76339058Skarels register char *p; 76439058Skarels char *maybe = NULL; 76539058Skarels int dots = 0; 76639058Skarels 76739058Skarels for (p = h + strlen(h); p >= h; p--) { 76839058Skarels if (*p == '.') { 76939058Skarels if (++dots == 2) 77039058Skarels return (p); 77139058Skarels maybe = p; 77239058Skarels } 77339058Skarels } 77439058Skarels return (maybe); 77539058Skarels } 776