121174Sdist /* 236517Skarels * Copyright (c) 1983, 1988 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[] = 2036517Skarels "@(#) Copyright (c) 1983, 1988 The Regents of the University of California.\n\ 2121174Sdist All rights reserved.\n"; 2235441Sbostic #endif /* not lint */ 236446Swnj 2421174Sdist #ifndef lint 25*39058Skarels static char sccsid[] = "@(#)rlogind.c 5.37 (Berkeley) 09/06/89"; 2635441Sbostic #endif /* not lint */ 2721174Sdist 28*39058Skarels #ifdef KERBEROS 29*39058Skarels /* From: 30*39058Skarels * $Source: /mit/kerberos/ucb/mit/rlogind/RCS/rlogind.c,v $ 31*39058Skarels * $Header: rlogind.c,v 5.0 89/06/26 18:31:01 kfall Locked $ 32*39058Skarels */ 33*39058Skarels 34*39058Skarels #endif 3516369Skarels /* 3616369Skarels * remote login server: 3736453Skfall * \0 3816369Skarels * remuser\0 3916369Skarels * locuser\0 4036453Skfall * terminal_type/speed\0 4136518Skarels * data 4216369Skarels */ 4316369Skarels 4437290Sbostic #include <sys/param.h> 456446Swnj #include <sys/stat.h> 466446Swnj #include <sys/socket.h> 4713554Ssam #include <sys/wait.h> 4818357Ssam #include <sys/file.h> 4937290Sbostic #include <sys/signal.h> 5037290Sbostic #include <sys/ioctl.h> 5137290Sbostic #include <sys/termios.h> 529208Ssam 539208Ssam #include <netinet/in.h> 549208Ssam 556446Swnj #include <errno.h> 566446Swnj #include <pwd.h> 578380Ssam #include <netdb.h> 5817187Sralph #include <syslog.h> 5918357Ssam #include <strings.h> 6037290Sbostic #include <stdio.h> 6137290Sbostic #include "pathnames.h" 626446Swnj 6336518Skarels #ifndef TIOCPKT_WINDOW 6436518Skarels #define TIOCPKT_WINDOW 0x80 6536518Skarels #endif 6636518Skarels 6736711Skfall #ifdef KERBEROS 6838710Skfall #include <krb.h> 6936711Skfall #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 7036711Skfall 7136711Skfall AUTH_DAT *kdata; 7236711Skfall KTEXT ticket; 7336711Skfall u_char auth_buf[sizeof(AUTH_DAT)]; 7436711Skfall u_char tick_buf[sizeof(KTEXT_ST)]; 7536711Skfall Key_schedule schedule; 7636711Skfall int encrypt = 0, retval, use_kerberos = 0, vacuous = 0; 7736711Skfall int do_krb_login(); 7836711Skfall 79*39058Skarels #define ARGSTR "alnkvx" 8036711Skfall #else 81*39058Skarels #define ARGSTR "aln" 8236711Skfall #endif /* KERBEROS */ 8336711Skfall 8436518Skarels char *env[2]; 8536518Skarels #define NMAX 30 8636517Skarels char lusername[NMAX+1], rusername[NMAX+1]; 8736517Skarels static char term[64] = "TERM="; 8836517Skarels #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 8936517Skarels int keepalive = 1; 90*39058Skarels int check_all = 0; 9136453Skfall 9236453Skfall #define SUPERUSER(pwd) ((pwd)->pw_uid == 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 { 10338710Skfall extern int opterr, optind; 10438710Skfall 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; 11236711Skfall while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 11336517Skarels switch (ch) { 114*39058Skarels case 'a': 115*39058Skarels check_all = 1; 116*39058Skarels break; 11736319Sbostic case 'l': 11836319Sbostic _check_rhosts_file = 0; 11936319Sbostic break; 12036517Skarels case 'n': 12136517Skarels keepalive = 0; 12236517Skarels break; 12336711Skfall #ifdef KERBEROS 12436711Skfall case 'k': 12536711Skfall use_kerberos = 1; 12636711Skfall break; 12736711Skfall case 'v': 12836711Skfall vacuous = 1; 12936711Skfall break; 13036715Skfall case 'x': 13136715Skfall encrypt = 1; 13236715Skfall break; 13336711Skfall #endif 13436319Sbostic case '?': 13536319Sbostic default: 13636711Skfall usage(); 13736319Sbostic break; 13836319Sbostic } 13936319Sbostic argc -= optind; 14036319Sbostic argv += optind; 14136319Sbostic 14236711Skfall #ifdef KERBEROS 14336711Skfall if (use_kerberos && vacuous) { 14436711Skfall usage(); 14536711Skfall fatal("only one of -k and -v allowed\n"); 14636711Skfall } 14736711Skfall #endif 14816369Skarels fromlen = sizeof (from); 14916369Skarels if (getpeername(0, &from, &fromlen) < 0) { 15036711Skfall syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 15136711Skfall fatalperror("Can't get peer name of remote host"); 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; 16324724Smckusick extern char *inet_ntoa(); 1646446Swnj 16524889Smckusick struct winsize win = { 0, 0, 0, 0 }; 16624723Smckusick 16724889Smckusick 1686446Swnj doit(f, fromp) 1696446Swnj int f; 1706446Swnj struct sockaddr_in *fromp; 1716446Swnj { 17218357Ssam int i, p, t, pid, on = 1; 17336631Skarels int authenticated = 0, hostok = 0; 17436711Skfall register struct hostent *hp; 17536703Skarels char remotehost[2 * MAXHOSTNAMELEN + 1]; 17624724Smckusick struct hostent hostent; 1778380Ssam char c; 1786446Swnj 1796446Swnj alarm(60); 1806446Swnj read(f, &c, 1); 18136711Skfall 18236715Skfall if(c != 0) 18336715Skfall exit(1); 18436711Skfall #ifdef KERBEROS 18536715Skfall if(vacuous) 18636715Skfall fatal(f, "Remote host requires Kerberos authentication"); 18736711Skfall #endif 18836453Skfall 1896446Swnj alarm(0); 19016227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 1918380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 1928380Ssam fromp->sin_family); 19311345Ssam if (hp == 0) { 19424724Smckusick /* 19524724Smckusick * Only the name is used below. 19624724Smckusick */ 19724724Smckusick hp = &hostent; 19824724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 19936635Skarels hostok++; 200*39058Skarels } else if (check_all || local_domain(hp->h_name)) { 20136635Skarels /* 20236635Skarels * If name returned by gethostbyaddr is in our domain, 20336635Skarels * attempt to verify that we haven't been fooled by someone 20436635Skarels * in a remote net; look up the name and check that this 20536635Skarels * address corresponds to the name. 20636635Skarels */ 20736635Skarels strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 20836635Skarels remotehost[sizeof(remotehost) - 1] = 0; 20936635Skarels hp = gethostbyname(remotehost); 21036635Skarels if (hp) 21136635Skarels for (; hp->h_addr_list[0]; hp->h_addr_list++) 21236635Skarels if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 21336635Skarels sizeof(fromp->sin_addr))) { 21436635Skarels hostok++; 21536635Skarels break; 21636635Skarels } 21736633Skarels } else 21836635Skarels hostok++; 21936711Skfall 22036711Skfall #ifdef KERBEROS 22136711Skfall if (use_kerberos) { 22236711Skfall retval = do_krb_login(hp->h_name, fromp, encrypt); 22336711Skfall write(f, &c, 1); 22436711Skfall if (retval == 0 && hostok) 22536711Skfall authenticated++; 22636711Skfall else if (retval > 0) 22736711Skfall fatal(f, krb_err_txt[retval]); 22836711Skfall else if(!hostok) 22936711Skfall fatal(f, "krlogind: Host address mismatch.\r\n"); 23036711Skfall } else 23136703Skarels #endif 23236711Skfall { 23336711Skfall if (fromp->sin_family != AF_INET || 23436711Skfall fromp->sin_port >= IPPORT_RESERVED || 23536711Skfall fromp->sin_port < IPPORT_RESERVED/2) { 23636711Skfall syslog(LOG_NOTICE, "Connection from %s on illegal port", 23736711Skfall inet_ntoa(fromp->sin_addr)); 23836711Skfall fatal(f, "Permission denied"); 23936711Skfall } 24036702Skarels #ifdef IP_OPTIONS 24136711Skfall { 24236711Skfall u_char optbuf[BUFSIZ/3], *cp; 24336711Skfall char lbuf[BUFSIZ], *lp; 24436711Skfall int optsize = sizeof(optbuf), ipproto; 24536711Skfall struct protoent *ip; 24636702Skarels 24736711Skfall if ((ip = getprotobyname("ip")) != NULL) 24836711Skfall ipproto = ip->p_proto; 24936711Skfall else 25036711Skfall ipproto = IPPROTO_IP; 25136711Skfall if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 25236711Skfall &optsize) == 0 && optsize != 0) { 25336711Skfall lp = lbuf; 25436711Skfall for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 25536711Skfall sprintf(lp, " %2.2x", *cp); 25636711Skfall syslog(LOG_NOTICE, 25736711Skfall "Connection received using IP options (ignored):%s", 25836711Skfall lbuf); 25936711Skfall if (setsockopt(0, ipproto, IP_OPTIONS, 26036711Skfall (char *)NULL, &optsize) != 0) { 26136711Skfall syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 26236711Skfall exit(1); 26336711Skfall } 26436711Skfall } 26536711Skfall } 26636702Skarels #endif 26736711Skfall write(f, "", 1); 26836711Skfall 26936711Skfall if (do_rlogin(hp->h_name) == 0) { 27036711Skfall if (hostok) 27136711Skfall authenticated++; 27236711Skfall else 27336711Skfall write(f, "rlogind: Host address mismatch.\r\n", 27436711Skfall sizeof("rlogind: Host address mismatch.\r\n") - 1); 27536711Skfall } 27636631Skarels } 27736636Skarels 2786446Swnj for (c = 'p'; c <= 's'; c++) { 2796446Swnj struct stat stb; 2806446Swnj line = "/dev/ptyXX"; 2816446Swnj line[strlen("/dev/pty")] = c; 2826446Swnj line[strlen("/dev/ptyp")] = '0'; 2836446Swnj if (stat(line, &stb) < 0) 2846446Swnj break; 2856446Swnj for (i = 0; i < 16; i++) { 28634424Sbostic line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 28734424Sbostic p = open(line, O_RDWR); 2886446Swnj if (p > 0) 2896446Swnj goto gotpty; 2906446Swnj } 2916446Swnj } 29224723Smckusick fatal(f, "Out of ptys"); 2939242Ssam /*NOTREACHED*/ 2946446Swnj gotpty: 29524889Smckusick (void) ioctl(p, TIOCSWINSZ, &win); 29616227Skarels netf = f; 2976446Swnj line[strlen("/dev/")] = 't'; 29834424Sbostic t = open(line, O_RDWR); 29934424Sbostic if (t < 0) 30034424Sbostic fatalperror(f, line); 30134424Sbostic if (fchmod(t, 0)) 30234424Sbostic fatalperror(f, line); 30334424Sbostic (void)signal(SIGHUP, SIG_IGN); 30434424Sbostic vhangup(); 30534424Sbostic (void)signal(SIGHUP, SIG_DFL); 30634424Sbostic t = open(line, O_RDWR); 30734424Sbostic if (t < 0) 30834424Sbostic fatalperror(f, line); 30936453Skfall setup_term(t); 3106446Swnj #ifdef DEBUG 31134424Sbostic { 31234424Sbostic int tt = open("/dev/tty", O_RDWR); 31334424Sbostic if (tt > 0) { 31434424Sbostic (void)ioctl(tt, TIOCNOTTY, 0); 31534424Sbostic (void)close(tt); 31634424Sbostic } 3176446Swnj } 3186446Swnj #endif 3199242Ssam pid = fork(); 3209242Ssam if (pid < 0) 32134424Sbostic fatalperror(f, ""); 32218357Ssam if (pid == 0) { 32336711Skfall if (setsid() < 0) 32436711Skfall fatalperror(f, "setsid"); 32536711Skfall if (ioctl(t, TIOCSCTTY, 0) < 0) 32636711Skfall fatalperror(f, "ioctl(sctty)"); 32718357Ssam close(f), close(p); 32818357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 32916227Skarels close(t); 33038710Skfall 33136631Skarels if (authenticated) 33237290Sbostic execl(_PATH_LOGIN, "login", "-p", 33336711Skfall "-h", hp->h_name, "-f", lusername, 0); 33436525Skfall else 33537290Sbostic execl(_PATH_LOGIN, "login", "-p", 33636711Skfall "-h", hp->h_name, lusername, 0); 33737290Sbostic fatalperror(2, _PATH_LOGIN); 33818357Ssam /*NOTREACHED*/ 33918357Ssam } 34018357Ssam close(t); 34136453Skfall 34236711Skfall #ifdef KERBEROS 34336711Skfall /* 34436711Skfall * If encrypted, don't turn on NBIO or the des read/write 34536711Skfall * routines will croak. 34636711Skfall */ 34736711Skfall 34836711Skfall if (encrypt) 34936711Skfall (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 35036711Skfall else 35136711Skfall #endif 35236711Skfall ioctl(f, FIONBIO, &on); 35318357Ssam ioctl(p, FIONBIO, &on); 35418357Ssam ioctl(p, TIOCPKT, &on); 35518357Ssam signal(SIGTSTP, SIG_IGN); 35618357Ssam signal(SIGCHLD, cleanup); 35724724Smckusick setpgrp(0, 0); 35818357Ssam protocol(f, p); 35930600Smckusick signal(SIGCHLD, SIG_IGN); 36018357Ssam cleanup(); 36118357Ssam } 3629242Ssam 36318357Ssam char magic[2] = { 0377, 0377 }; 36425423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 36518357Ssam 36618357Ssam /* 36718357Ssam * Handle a "control" request (signaled by magic being present) 36818357Ssam * in the data stream. For now, we are only willing to handle 36918357Ssam * window size changes. 37018357Ssam */ 37118357Ssam control(pty, cp, n) 37218357Ssam int pty; 37318357Ssam char *cp; 37418357Ssam int n; 37518357Ssam { 37628705Smckusick struct winsize w; 37718357Ssam 37828705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 37918357Ssam return (0); 38025423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 38128705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 38228705Smckusick w.ws_row = ntohs(w.ws_row); 38328705Smckusick w.ws_col = ntohs(w.ws_col); 38428705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 38528705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 38628705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 38728705Smckusick return (4+sizeof (w)); 38818357Ssam } 38918357Ssam 39018357Ssam /* 39118357Ssam * rlogin "protocol" machine. 39218357Ssam */ 39318357Ssam protocol(f, p) 39418357Ssam int f, p; 39518357Ssam { 39618357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 39718357Ssam register pcc = 0, fcc = 0; 39836517Skarels int cc, nfd, pmask, fmask; 39925740Skarels char cntl; 40018357Ssam 40118482Ssam /* 40218484Ssam * Must ignore SIGTTOU, otherwise we'll stop 40318484Ssam * when we try and set slave pty's window shape 40425423Skarels * (our controlling tty is the master pty). 40518482Ssam */ 40618484Ssam (void) signal(SIGTTOU, SIG_IGN); 40725423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 40836517Skarels if (f > p) 40936517Skarels nfd = f + 1; 41036517Skarels else 41136517Skarels nfd = p + 1; 41236517Skarels fmask = 1 << f; 41336517Skarels pmask = 1 << p; 41418357Ssam for (;;) { 41525740Skarels int ibits, obits, ebits; 41618357Ssam 41725740Skarels ibits = 0; 41825740Skarels obits = 0; 41918357Ssam if (fcc) 42036517Skarels obits |= pmask; 42118357Ssam else 42236517Skarels ibits |= fmask; 42318357Ssam if (pcc >= 0) 42418357Ssam if (pcc) 42536517Skarels obits |= fmask; 4269242Ssam else 42736517Skarels ibits |= pmask; 42836517Skarels ebits = pmask; 42936517Skarels if (select(nfd, &ibits, obits ? &obits : (int *)NULL, 43036517Skarels &ebits, 0) < 0) { 43118357Ssam if (errno == EINTR) 4326446Swnj continue; 43334424Sbostic fatalperror(f, "select"); 43418357Ssam } 43525740Skarels if (ibits == 0 && obits == 0 && ebits == 0) { 43618357Ssam /* shouldn't happen... */ 43718357Ssam sleep(5); 43818357Ssam continue; 43918357Ssam } 44025740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 44136517Skarels if (ebits & pmask) { 44225740Skarels cc = read(p, &cntl, 1); 44325740Skarels if (cc == 1 && pkcontrol(cntl)) { 44425740Skarels cntl |= oobdata[0]; 44525740Skarels send(f, &cntl, 1, MSG_OOB); 44625740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 44725740Skarels pcc = 0; 44836517Skarels ibits &= ~pmask; 44925740Skarels } 45025740Skarels } 45125740Skarels } 45236517Skarels if (ibits & fmask) { 45336711Skfall #ifdef KERBEROS 45436711Skfall if (encrypt) 45536711Skfall fcc = des_read(f, fibuf, sizeof(fibuf)); 45636711Skfall else 45736711Skfall #endif 45836711Skfall fcc = read(f, fibuf, sizeof(fibuf)); 45918357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 46018357Ssam fcc = 0; 46118357Ssam else { 46218357Ssam register char *cp; 46318357Ssam int left, n; 46418357Ssam 46518357Ssam if (fcc <= 0) 46616227Skarels break; 46718357Ssam fbp = fibuf; 46824723Smckusick 46918357Ssam top: 47025423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 47118357Ssam if (cp[0] == magic[0] && 47218357Ssam cp[1] == magic[1]) { 47318357Ssam left = fcc - (cp-fibuf); 47418357Ssam n = control(p, cp, left); 47518357Ssam if (n) { 47618357Ssam left -= n; 47718357Ssam if (left > 0) 47825423Skarels bcopy(cp+n, cp, left); 47918357Ssam fcc -= n; 48018357Ssam goto top; /* n^2 */ 48125423Skarels } 48225423Skarels } 48336517Skarels obits |= pmask; /* try write */ 48425423Skarels } 48525423Skarels } 48624723Smckusick 48736517Skarels if ((obits & pmask) && fcc > 0) { 48825423Skarels cc = write(p, fbp, fcc); 48924723Smckusick if (cc > 0) { 49024723Smckusick fcc -= cc; 49124723Smckusick fbp += cc; 4926446Swnj } 49318357Ssam } 49424723Smckusick 49536517Skarels if (ibits & pmask) { 49618357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 49718357Ssam pbp = pibuf; 49818357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 49918357Ssam pcc = 0; 50018357Ssam else if (pcc <= 0) 50118357Ssam break; 50236517Skarels else if (pibuf[0] == 0) { 50318357Ssam pbp++, pcc--; 50436711Skfall #ifdef KERBEROS 50536711Skfall if (!encrypt) 50636711Skfall #endif 50736711Skfall obits |= fmask; /* try a write */ 50836517Skarels } else { 50918357Ssam if (pkcontrol(pibuf[0])) { 51025423Skarels pibuf[0] |= oobdata[0]; 51118357Ssam send(f, &pibuf[0], 1, MSG_OOB); 51216227Skarels } 51318357Ssam pcc = 0; 5146446Swnj } 51518357Ssam } 51636517Skarels if ((obits & fmask) && pcc > 0) { 51736711Skfall #ifdef KERBEROS 51836711Skfall if (encrypt) 51936711Skfall cc = des_write(f, pbp, pcc); 52036711Skfall else 52136711Skfall #endif 52236711Skfall cc = write(f, pbp, pcc); 52325423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 52425423Skarels /* also shouldn't happen */ 52525423Skarels sleep(5); 52625423Skarels continue; 52725423Skarels } 52818357Ssam if (cc > 0) { 52918357Ssam pcc -= cc; 53018357Ssam pbp += cc; 53118357Ssam } 5326446Swnj } 5336446Swnj } 5346446Swnj } 5356446Swnj 5366446Swnj cleanup() 5376446Swnj { 53835440Sbostic char *p; 53935440Sbostic 54035440Sbostic p = line + sizeof("/dev/") - 1; 54135440Sbostic if (logout(p)) 54235440Sbostic logwtmp(p, "", ""); 54335440Sbostic (void)chmod(line, 0666); 54435440Sbostic (void)chown(line, 0, 0); 54535440Sbostic *p = 'p'; 54635440Sbostic (void)chmod(line, 0666); 54735440Sbostic (void)chown(line, 0, 0); 54810192Ssam shutdown(netf, 2); 5496446Swnj exit(1); 5506446Swnj } 5516446Swnj 5529242Ssam fatal(f, msg) 5539242Ssam int f; 5549242Ssam char *msg; 5559242Ssam { 5569242Ssam char buf[BUFSIZ]; 5579242Ssam 5589242Ssam buf[0] = '\01'; /* error indicator */ 55913554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 5609242Ssam (void) write(f, buf, strlen(buf)); 5619242Ssam exit(1); 5629242Ssam } 5639242Ssam 56434424Sbostic fatalperror(f, msg) 5659242Ssam int f; 5669242Ssam char *msg; 5679242Ssam { 5689242Ssam char buf[BUFSIZ]; 56916227Skarels extern int sys_nerr; 5709242Ssam extern char *sys_errlist[]; 5719242Ssam 57218357Ssam if ((unsigned)errno < sys_nerr) 57316227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 57416227Skarels else 57516227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 5769242Ssam fatal(f, buf); 5779242Ssam } 57836453Skfall 57936453Skfall do_rlogin(host) 58036518Skarels char *host; 58136453Skfall { 58236453Skfall 58336518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 58436518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 58536518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 58636518Skarels 58736518Skarels if (getuid()) 58836453Skfall return(-1); 58936453Skfall pwd = getpwnam(lusername); 59036518Skarels if (pwd == NULL) 59136453Skfall return(-1); 59236453Skfall return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 59336453Skfall } 59436453Skfall 59536453Skfall 59636518Skarels getstr(buf, cnt, errmsg) 59736518Skarels char *buf; 59836518Skarels int cnt; 59936518Skarels char *errmsg; 60036453Skfall { 60136518Skarels char c; 60236518Skarels 60336453Skfall do { 60436518Skarels if (read(0, &c, 1) != 1) 60536453Skfall exit(1); 60636518Skarels if (--cnt < 0) 60736518Skarels fatal(1, errmsg); 60836453Skfall *buf++ = c; 60936518Skarels } while (c != 0); 61036453Skfall } 61136453Skfall 61236518Skarels extern char **environ; 61336453Skfall 61436519Skarels setup_term(fd) 61536519Skarels int fd; 61636519Skarels { 61736711Skfall register char *cp = index(term+ENVSIZE, '/'); 61836519Skarels char *speed; 61936519Skarels 62038710Skfall struct termios tt; 62136711Skfall tcgetattr(fd, &tt); 62236519Skarels if (cp) { 62336519Skarels *cp++ = '\0'; 62436519Skarels speed = cp; 62536519Skarels cp = index(speed, '/'); 62636519Skarels if (cp) 62736519Skarels *cp++ = '\0'; 62836711Skfall cfsetspeed(&tt, atoi(speed)); 62936519Skarels } 63038710Skfall 63138710Skfall 63236711Skfall tt.c_iflag = BRKINT|ICRNL|IXON|ISTRIP|IEXTEN|IMAXBEL; 63336711Skfall tt.c_oflag = OPOST|ONLCR|OXTABS; 63436711Skfall tt.c_lflag = ISIG|ICANON|ECHO; 63536711Skfall tcsetattr(fd, TCSADFLUSH, &tt); 63638710Skfall #ifdef notdef 63738710Skfall { 63838710Skfall struct sgttyb b; 63938710Skfall (void) ioctl(fd, TIOCGETP, &b); 64038710Skfall b.sg_flags = ECHO|CRMOD|ANYP; 64138710Skfall b.sg_ispeed = b.sg_ospeed = atoi(speed); 64238710Skfall (void) ioctl(fd, TIOCSETP, &b); 64338710Skfall } 64438710Skfall #endif 64536519Skarels 64636519Skarels env[0] = term; 64736519Skarels env[1] = 0; 64836519Skarels environ = env; 64936519Skarels } 65036609Skfall 65136711Skfall #ifdef KERBEROS 65236711Skfall #define VERSION_SIZE 9 65336711Skfall 65436609Skfall /* 65536711Skfall * Do the remote kerberos login to the named host with the 65636711Skfall * given inet address 65736711Skfall * 65836711Skfall * Return 0 on valid authorization 65936711Skfall * Return -1 on valid authentication, no authorization 66036711Skfall * Return >0 for error conditions 66136711Skfall */ 66236711Skfall do_krb_login(host, dest, encrypt) 66336711Skfall char *host; 66436711Skfall struct sockaddr_in *dest; 66536711Skfall int encrypt; 66636711Skfall { 66736711Skfall int rc; 66836711Skfall char instance[INST_SZ], version[VERSION_SIZE]; 66936711Skfall long authopts = 0L; /* !mutual */ 67036711Skfall struct sockaddr_in faddr; 67136711Skfall 67236711Skfall if (getuid()) 67336711Skfall return(KFAILURE); 67436711Skfall 67536711Skfall kdata = (AUTH_DAT *) auth_buf; 67636711Skfall ticket = (KTEXT) tick_buf; 67736711Skfall strcpy(instance, "*"); 67836711Skfall 67936711Skfall if (encrypt) { 68036711Skfall rc = sizeof(faddr); 68136711Skfall if (getsockname(0, &faddr, &rc)) 68236711Skfall return(-1); 68336711Skfall authopts = KOPT_DO_MUTUAL; 68436711Skfall rc = krb_recvauth( 68536711Skfall authopts, 0, 68636711Skfall ticket, "rcmd", 68736711Skfall instance, dest, &faddr, 68836711Skfall kdata, "", schedule, version); 68936711Skfall des_set_key(kdata->session, schedule); 69036711Skfall 69136711Skfall } else { 69236711Skfall rc = krb_recvauth( 69336711Skfall authopts, 0, 69436711Skfall ticket, "rcmd", 69536711Skfall instance, dest, (struct sockaddr_in *) 0, 69636711Skfall kdata, "", (bit_64 *) 0, version); 69736711Skfall } 69836711Skfall 69936711Skfall if (rc != KSUCCESS) 70036711Skfall return(rc); 70136711Skfall 70236711Skfall getstr(lusername, sizeof(lusername), "locuser"); 70336711Skfall /* get the "cmd" in the rcmd protocol */ 70436711Skfall getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 70536711Skfall 70636711Skfall pwd = getpwnam(lusername); 70736711Skfall if (pwd == NULL) 70836711Skfall return(-1); 70936711Skfall 71036711Skfall /* returns nonzero for no access */ 71136711Skfall /* return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); */ 71236711Skfall if (kuserok(kdata,lusername) != 0) 71336711Skfall return(-1); 71436711Skfall 71536711Skfall return(0); 71636711Skfall 71736711Skfall } 71836711Skfall 71936711Skfall #endif /* KERBEROS */ 72036711Skfall 72136711Skfall usage() 72236711Skfall { 72336711Skfall #ifdef KERBEROS 724*39058Skarels syslog(LOG_ERR, "usage: rlogind [-k | -v] [-a] [-l] [-n]"); 72536711Skfall #else 726*39058Skarels syslog(LOG_ERR, "usage: rlogind [-a] [-l] [-n]"); 72736711Skfall #endif 72836711Skfall } 72936711Skfall 73036711Skfall /* 73136631Skarels * Check whether host h is in our local domain, 732*39058Skarels * defined as sharing the last two components of the domain part, 733*39058Skarels * or the entire domain part if the local domain has only one component. 73436631Skarels * If either name is unqualified (contains no '.'), 73536631Skarels * assume that the host is local, as it will be 73636631Skarels * interpreted as such. 73736631Skarels */ 73836631Skarels local_domain(h) 73936631Skarels char *h; 74036625Skfall { 74136631Skarels char localhost[MAXHOSTNAMELEN]; 742*39058Skarels char *p1, *p2, *topdomain(); 74336631Skarels 744*39058Skarels localhost[0] = 0; 74536631Skarels (void) gethostname(localhost, sizeof(localhost)); 746*39058Skarels p1 = topdomain(localhost); 747*39058Skarels p2 = topdomain(h); 74836631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 74936625Skfall return(1); 75036625Skfall return(0); 75136625Skfall } 752*39058Skarels 753*39058Skarels char * 754*39058Skarels topdomain(h) 755*39058Skarels char *h; 756*39058Skarels { 757*39058Skarels register char *p; 758*39058Skarels char *maybe = NULL; 759*39058Skarels int dots = 0; 760*39058Skarels 761*39058Skarels for (p = h + strlen(h); p >= h; p--) { 762*39058Skarels if (*p == '.') { 763*39058Skarels if (++dots == 2) 764*39058Skarels return (p); 765*39058Skarels maybe = p; 766*39058Skarels } 767*39058Skarels } 768*39058Skarels return (maybe); 769*39058Skarels } 770