1*38710Skfall 221174Sdist /* 3*38710Skfall * $Source: /mit/kerberos/ucb/mit/rlogind/RCS/rlogind.c,v $ 4*38710Skfall * $Header: rlogind.c,v 5.0 89/06/26 18:31:01 kfall Locked $ 5*38710Skfall */ 6*38710Skfall 7*38710Skfall /* 836517Skarels * Copyright (c) 1983, 1988 The Regents of the University of California. 935441Sbostic * All rights reserved. 1035441Sbostic * 1135441Sbostic * Redistribution and use in source and binary forms are permitted 1235441Sbostic * provided that the above copyright notice and this paragraph are 1335441Sbostic * duplicated in all such forms and that any documentation, 1435441Sbostic * advertising materials, and other materials related to such 1535441Sbostic * distribution and use acknowledge that the software was developed 1635441Sbostic * by the University of California, Berkeley. The name of the 1735441Sbostic * University may not be used to endorse or promote products derived 1835441Sbostic * from this software without specific prior written permission. 1935441Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 2035441Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 2135441Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2221174Sdist */ 2321174Sdist 246446Swnj #ifndef lint 2521174Sdist char copyright[] = 2636517Skarels "@(#) Copyright (c) 1983, 1988 The Regents of the University of California.\n\ 2721174Sdist All rights reserved.\n"; 2835441Sbostic #endif /* not lint */ 296446Swnj 3021174Sdist #ifndef lint 31*38710Skfall static char sccsid[] = "@(#)rlogind.c 5.35 (Berkeley) 4/2/89"; 3235441Sbostic #endif /* not lint */ 3321174Sdist 3416369Skarels /* 3516369Skarels * remote login server: 3636453Skfall * \0 3716369Skarels * remuser\0 3816369Skarels * locuser\0 3936453Skfall * terminal_type/speed\0 4036518Skarels * data 4116369Skarels */ 4216369Skarels 4337290Sbostic #include <sys/param.h> 446446Swnj #include <sys/stat.h> 456446Swnj #include <sys/socket.h> 4613554Ssam #include <sys/wait.h> 4718357Ssam #include <sys/file.h> 4837290Sbostic #include <sys/signal.h> 4937290Sbostic #include <sys/ioctl.h> 5037290Sbostic #include <sys/termios.h> 519208Ssam 529208Ssam #include <netinet/in.h> 539208Ssam 546446Swnj #include <errno.h> 556446Swnj #include <pwd.h> 568380Ssam #include <netdb.h> 5717187Sralph #include <syslog.h> 5818357Ssam #include <strings.h> 5937290Sbostic #include <stdio.h> 6037290Sbostic #include "pathnames.h" 616446Swnj 6236518Skarels #ifndef TIOCPKT_WINDOW 6336518Skarels #define TIOCPKT_WINDOW 0x80 6436518Skarels #endif 6536518Skarels 6636711Skfall #ifdef KERBEROS 67*38710Skfall #include <krb.h> 6836711Skfall #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 6936711Skfall 7036711Skfall AUTH_DAT *kdata; 7136711Skfall KTEXT ticket; 7236711Skfall u_char auth_buf[sizeof(AUTH_DAT)]; 7336711Skfall u_char tick_buf[sizeof(KTEXT_ST)]; 7436711Skfall Key_schedule schedule; 7536711Skfall int encrypt = 0, retval, use_kerberos = 0, vacuous = 0; 7636711Skfall int do_krb_login(); 7736711Skfall 78*38710Skfall #if BSD > 43 7936715Skfall #define ARGSTR "lnkvx" 8036711Skfall #else 81*38710Skfall #define ARGSTR "nkvx" 82*38710Skfall #endif 83*38710Skfall #else 84*38710Skfall #if BSD > 43 8536711Skfall #define ARGSTR "ln" 86*38710Skfall #else 87*38710Skfall #define ARGSTR "n" 88*38710Skfall #endif 8936711Skfall #endif /* KERBEROS */ 9036711Skfall 9136518Skarels char *env[2]; 9236518Skarels #define NMAX 30 9336517Skarels char lusername[NMAX+1], rusername[NMAX+1]; 9436517Skarels static char term[64] = "TERM="; 9536517Skarels #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 9636517Skarels int keepalive = 1; 9736453Skfall 9836453Skfall #define SUPERUSER(pwd) ((pwd)->pw_uid == 0) 9936453Skfall 10034424Sbostic extern int errno; 10110417Ssam int reapchild(); 10236453Skfall struct passwd *getpwnam(), *pwd; 10324723Smckusick char *malloc(); 10416369Skarels 1056446Swnj main(argc, argv) 1066446Swnj int argc; 1076446Swnj char **argv; 1086446Swnj { 109*38710Skfall extern int opterr, optind; 110*38710Skfall #if BSD > 43 111*38710Skfall extern int _check_rhosts_file; 112*38710Skfall #endif 11336319Sbostic int ch; 11434424Sbostic int on = 1, fromlen; 1156446Swnj struct sockaddr_in from; 1166446Swnj 11736625Skfall openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 11836319Sbostic 11936319Sbostic opterr = 0; 12036711Skfall while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 12136517Skarels switch (ch) { 122*38710Skfall #if BSD > 43 12336319Sbostic case 'l': 12436319Sbostic _check_rhosts_file = 0; 12536319Sbostic break; 126*38710Skfall #endif 12736517Skarels case 'n': 12836517Skarels keepalive = 0; 12936517Skarels break; 13036711Skfall #ifdef KERBEROS 13136711Skfall case 'k': 13236711Skfall use_kerberos = 1; 13336711Skfall break; 13436711Skfall case 'v': 13536711Skfall vacuous = 1; 13636711Skfall break; 13736715Skfall case 'x': 13836715Skfall encrypt = 1; 13936715Skfall break; 14036711Skfall #endif 14136319Sbostic case '?': 14236319Sbostic default: 14336711Skfall usage(); 14436319Sbostic break; 14536319Sbostic } 14636319Sbostic argc -= optind; 14736319Sbostic argv += optind; 14836319Sbostic 14936711Skfall #ifdef KERBEROS 15036711Skfall if (use_kerberos && vacuous) { 15136711Skfall usage(); 15236711Skfall fatal("only one of -k and -v allowed\n"); 15336711Skfall } 15436711Skfall #endif 15516369Skarels fromlen = sizeof (from); 15616369Skarels if (getpeername(0, &from, &fromlen) < 0) { 15736711Skfall syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 15836711Skfall fatalperror("Can't get peer name of remote host"); 1598380Ssam } 16036517Skarels if (keepalive && 16136517Skarels setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 16217187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 16316369Skarels doit(0, &from); 1646446Swnj } 1656446Swnj 1666446Swnj int child; 1676446Swnj int cleanup(); 1686446Swnj int netf; 1696446Swnj char *line; 17024724Smckusick extern char *inet_ntoa(); 1716446Swnj 17224889Smckusick struct winsize win = { 0, 0, 0, 0 }; 17324723Smckusick 17424889Smckusick 1756446Swnj doit(f, fromp) 1766446Swnj int f; 1776446Swnj struct sockaddr_in *fromp; 1786446Swnj { 17918357Ssam int i, p, t, pid, on = 1; 18036631Skarels int authenticated = 0, hostok = 0; 18136711Skfall register struct hostent *hp; 18236703Skarels char remotehost[2 * MAXHOSTNAMELEN + 1]; 18324724Smckusick struct hostent hostent; 1848380Ssam char c; 1856446Swnj 1866446Swnj alarm(60); 1876446Swnj read(f, &c, 1); 18836711Skfall 18936715Skfall if(c != 0) 19036715Skfall exit(1); 19136711Skfall #ifdef KERBEROS 19236715Skfall if(vacuous) 19336715Skfall fatal(f, "Remote host requires Kerberos authentication"); 19436711Skfall #endif 19536453Skfall 1966446Swnj alarm(0); 19716227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 1988380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 1998380Ssam fromp->sin_family); 20011345Ssam if (hp == 0) { 20124724Smckusick /* 20224724Smckusick * Only the name is used below. 20324724Smckusick */ 20424724Smckusick hp = &hostent; 20524724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 20636635Skarels hostok++; 20736711Skfall } else if (local_domain(hp->h_name)) { 20836635Skarels /* 20936635Skarels * If name returned by gethostbyaddr is in our domain, 21036635Skarels * attempt to verify that we haven't been fooled by someone 21136635Skarels * in a remote net; look up the name and check that this 21236635Skarels * address corresponds to the name. 21336635Skarels */ 21436635Skarels strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 21536635Skarels remotehost[sizeof(remotehost) - 1] = 0; 21636635Skarels hp = gethostbyname(remotehost); 21736635Skarels if (hp) 21836635Skarels for (; hp->h_addr_list[0]; hp->h_addr_list++) 21936635Skarels if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 22036635Skarels sizeof(fromp->sin_addr))) { 22136635Skarels hostok++; 22236635Skarels break; 22336635Skarels } 22436633Skarels } else 22536635Skarels hostok++; 22636711Skfall 22736711Skfall #ifdef KERBEROS 22836711Skfall if (use_kerberos) { 22936711Skfall retval = do_krb_login(hp->h_name, fromp, encrypt); 23036711Skfall write(f, &c, 1); 23136711Skfall if (retval == 0 && hostok) 23236711Skfall authenticated++; 23336711Skfall else if (retval > 0) 23436711Skfall fatal(f, krb_err_txt[retval]); 23536711Skfall else if(!hostok) 23636711Skfall fatal(f, "krlogind: Host address mismatch.\r\n"); 23736711Skfall } else 23836703Skarels #endif 23936711Skfall { 24036711Skfall if (fromp->sin_family != AF_INET || 24136711Skfall fromp->sin_port >= IPPORT_RESERVED || 24236711Skfall fromp->sin_port < IPPORT_RESERVED/2) { 24336711Skfall syslog(LOG_NOTICE, "Connection from %s on illegal port", 24436711Skfall inet_ntoa(fromp->sin_addr)); 24536711Skfall fatal(f, "Permission denied"); 24636711Skfall } 24736702Skarels #ifdef IP_OPTIONS 24836711Skfall { 24936711Skfall u_char optbuf[BUFSIZ/3], *cp; 25036711Skfall char lbuf[BUFSIZ], *lp; 25136711Skfall int optsize = sizeof(optbuf), ipproto; 25236711Skfall struct protoent *ip; 25336702Skarels 25436711Skfall if ((ip = getprotobyname("ip")) != NULL) 25536711Skfall ipproto = ip->p_proto; 25636711Skfall else 25736711Skfall ipproto = IPPROTO_IP; 25836711Skfall if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 25936711Skfall &optsize) == 0 && optsize != 0) { 26036711Skfall lp = lbuf; 26136711Skfall for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 26236711Skfall sprintf(lp, " %2.2x", *cp); 26336711Skfall syslog(LOG_NOTICE, 26436711Skfall "Connection received using IP options (ignored):%s", 26536711Skfall lbuf); 26636711Skfall if (setsockopt(0, ipproto, IP_OPTIONS, 26736711Skfall (char *)NULL, &optsize) != 0) { 26836711Skfall syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 26936711Skfall exit(1); 27036711Skfall } 27136711Skfall } 27236711Skfall } 27336702Skarels #endif 27436711Skfall write(f, "", 1); 27536711Skfall 27636711Skfall if (do_rlogin(hp->h_name) == 0) { 27736711Skfall if (hostok) 27836711Skfall authenticated++; 27936711Skfall else 28036711Skfall write(f, "rlogind: Host address mismatch.\r\n", 28136711Skfall sizeof("rlogind: Host address mismatch.\r\n") - 1); 28236711Skfall } 28336631Skarels } 28436636Skarels 2856446Swnj for (c = 'p'; c <= 's'; c++) { 2866446Swnj struct stat stb; 2876446Swnj line = "/dev/ptyXX"; 2886446Swnj line[strlen("/dev/pty")] = c; 2896446Swnj line[strlen("/dev/ptyp")] = '0'; 2906446Swnj if (stat(line, &stb) < 0) 2916446Swnj break; 2926446Swnj for (i = 0; i < 16; i++) { 29334424Sbostic line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 29434424Sbostic p = open(line, O_RDWR); 2956446Swnj if (p > 0) 2966446Swnj goto gotpty; 2976446Swnj } 2986446Swnj } 29924723Smckusick fatal(f, "Out of ptys"); 3009242Ssam /*NOTREACHED*/ 3016446Swnj gotpty: 30224889Smckusick (void) ioctl(p, TIOCSWINSZ, &win); 30316227Skarels netf = f; 3046446Swnj line[strlen("/dev/")] = 't'; 30534424Sbostic t = open(line, O_RDWR); 30634424Sbostic if (t < 0) 30734424Sbostic fatalperror(f, line); 30834424Sbostic if (fchmod(t, 0)) 30934424Sbostic fatalperror(f, line); 31034424Sbostic (void)signal(SIGHUP, SIG_IGN); 31134424Sbostic vhangup(); 31234424Sbostic (void)signal(SIGHUP, SIG_DFL); 31334424Sbostic t = open(line, O_RDWR); 31434424Sbostic if (t < 0) 31534424Sbostic fatalperror(f, line); 31636453Skfall setup_term(t); 3176446Swnj #ifdef DEBUG 31834424Sbostic { 31934424Sbostic int tt = open("/dev/tty", O_RDWR); 32034424Sbostic if (tt > 0) { 32134424Sbostic (void)ioctl(tt, TIOCNOTTY, 0); 32234424Sbostic (void)close(tt); 32334424Sbostic } 3246446Swnj } 3256446Swnj #endif 3269242Ssam pid = fork(); 3279242Ssam if (pid < 0) 32834424Sbostic fatalperror(f, ""); 32918357Ssam if (pid == 0) { 33036711Skfall if (setsid() < 0) 33136711Skfall fatalperror(f, "setsid"); 33236711Skfall if (ioctl(t, TIOCSCTTY, 0) < 0) 33336711Skfall fatalperror(f, "ioctl(sctty)"); 33418357Ssam close(f), close(p); 33518357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 33616227Skarels close(t); 337*38710Skfall 33836631Skarels if (authenticated) 33937290Sbostic execl(_PATH_LOGIN, "login", "-p", 34036711Skfall "-h", hp->h_name, "-f", lusername, 0); 34136525Skfall else 34237290Sbostic execl(_PATH_LOGIN, "login", "-p", 34336711Skfall "-h", hp->h_name, lusername, 0); 34437290Sbostic fatalperror(2, _PATH_LOGIN); 34518357Ssam /*NOTREACHED*/ 34618357Ssam } 34718357Ssam close(t); 34836453Skfall 34936711Skfall #ifdef KERBEROS 35036711Skfall /* 35136711Skfall * If encrypted, don't turn on NBIO or the des read/write 35236711Skfall * routines will croak. 35336711Skfall */ 35436711Skfall 35536711Skfall if (encrypt) 35636711Skfall (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 35736711Skfall else 35836711Skfall #endif 35936711Skfall ioctl(f, FIONBIO, &on); 36018357Ssam ioctl(p, FIONBIO, &on); 36118357Ssam ioctl(p, TIOCPKT, &on); 36218357Ssam signal(SIGTSTP, SIG_IGN); 36318357Ssam signal(SIGCHLD, cleanup); 36424724Smckusick setpgrp(0, 0); 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) 40118357Ssam int f, p; 40218357Ssam { 40318357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 40418357Ssam register pcc = 0, fcc = 0; 40536517Skarels int cc, nfd, pmask, fmask; 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; 41936517Skarels fmask = 1 << f; 42036517Skarels pmask = 1 << p; 42118357Ssam for (;;) { 42225740Skarels int ibits, obits, ebits; 42318357Ssam 42425740Skarels ibits = 0; 42525740Skarels obits = 0; 42618357Ssam if (fcc) 42736517Skarels obits |= pmask; 42818357Ssam else 42936517Skarels ibits |= fmask; 43018357Ssam if (pcc >= 0) 43118357Ssam if (pcc) 43236517Skarels obits |= fmask; 4339242Ssam else 43436517Skarels ibits |= pmask; 43536517Skarels ebits = pmask; 43636517Skarels if (select(nfd, &ibits, obits ? &obits : (int *)NULL, 43736517Skarels &ebits, 0) < 0) { 43818357Ssam if (errno == EINTR) 4396446Swnj continue; 44034424Sbostic fatalperror(f, "select"); 44118357Ssam } 44225740Skarels if (ibits == 0 && obits == 0 && ebits == 0) { 44318357Ssam /* shouldn't happen... */ 44418357Ssam sleep(5); 44518357Ssam continue; 44618357Ssam } 44725740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 44836517Skarels if (ebits & pmask) { 44925740Skarels cc = read(p, &cntl, 1); 45025740Skarels if (cc == 1 && pkcontrol(cntl)) { 45125740Skarels cntl |= oobdata[0]; 45225740Skarels send(f, &cntl, 1, MSG_OOB); 45325740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 45425740Skarels pcc = 0; 45536517Skarels ibits &= ~pmask; 45625740Skarels } 45725740Skarels } 45825740Skarels } 45936517Skarels if (ibits & fmask) { 46036711Skfall #ifdef KERBEROS 46136711Skfall if (encrypt) 46236711Skfall fcc = des_read(f, fibuf, sizeof(fibuf)); 46336711Skfall else 46436711Skfall #endif 46536711Skfall fcc = read(f, fibuf, sizeof(fibuf)); 46618357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 46718357Ssam fcc = 0; 46818357Ssam else { 46918357Ssam register char *cp; 47018357Ssam int left, n; 47118357Ssam 47218357Ssam if (fcc <= 0) 47316227Skarels break; 47418357Ssam fbp = fibuf; 47524723Smckusick 47618357Ssam top: 47725423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 47818357Ssam if (cp[0] == magic[0] && 47918357Ssam cp[1] == magic[1]) { 48018357Ssam left = fcc - (cp-fibuf); 48118357Ssam n = control(p, cp, left); 48218357Ssam if (n) { 48318357Ssam left -= n; 48418357Ssam if (left > 0) 48525423Skarels bcopy(cp+n, cp, left); 48618357Ssam fcc -= n; 48718357Ssam goto top; /* n^2 */ 48825423Skarels } 48925423Skarels } 49036517Skarels obits |= pmask; /* try write */ 49125423Skarels } 49225423Skarels } 49324723Smckusick 49436517Skarels if ((obits & pmask) && fcc > 0) { 49525423Skarels cc = write(p, fbp, fcc); 49624723Smckusick if (cc > 0) { 49724723Smckusick fcc -= cc; 49824723Smckusick fbp += cc; 4996446Swnj } 50018357Ssam } 50124723Smckusick 50236517Skarels if (ibits & pmask) { 50318357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 50418357Ssam pbp = pibuf; 50518357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 50618357Ssam pcc = 0; 50718357Ssam else if (pcc <= 0) 50818357Ssam break; 50936517Skarels else if (pibuf[0] == 0) { 51018357Ssam pbp++, pcc--; 51136711Skfall #ifdef KERBEROS 51236711Skfall if (!encrypt) 51336711Skfall #endif 51436711Skfall obits |= fmask; /* try a write */ 51536517Skarels } else { 51618357Ssam if (pkcontrol(pibuf[0])) { 51725423Skarels pibuf[0] |= oobdata[0]; 51818357Ssam send(f, &pibuf[0], 1, MSG_OOB); 51916227Skarels } 52018357Ssam pcc = 0; 5216446Swnj } 52218357Ssam } 52336517Skarels if ((obits & fmask) && pcc > 0) { 52436711Skfall #ifdef KERBEROS 52536711Skfall if (encrypt) 52636711Skfall cc = des_write(f, pbp, pcc); 52736711Skfall else 52836711Skfall #endif 52936711Skfall cc = write(f, pbp, pcc); 53025423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 53125423Skarels /* also shouldn't happen */ 53225423Skarels sleep(5); 53325423Skarels continue; 53425423Skarels } 53518357Ssam if (cc > 0) { 53618357Ssam pcc -= cc; 53718357Ssam pbp += cc; 53818357Ssam } 5396446Swnj } 5406446Swnj } 5416446Swnj } 5426446Swnj 5436446Swnj cleanup() 5446446Swnj { 54535440Sbostic char *p; 54635440Sbostic 54735440Sbostic p = line + sizeof("/dev/") - 1; 54835440Sbostic if (logout(p)) 54935440Sbostic logwtmp(p, "", ""); 55035440Sbostic (void)chmod(line, 0666); 55135440Sbostic (void)chown(line, 0, 0); 55235440Sbostic *p = 'p'; 55335440Sbostic (void)chmod(line, 0666); 55435440Sbostic (void)chown(line, 0, 0); 55510192Ssam shutdown(netf, 2); 5566446Swnj exit(1); 5576446Swnj } 5586446Swnj 5599242Ssam fatal(f, msg) 5609242Ssam int f; 5619242Ssam char *msg; 5629242Ssam { 5639242Ssam char buf[BUFSIZ]; 5649242Ssam 5659242Ssam buf[0] = '\01'; /* error indicator */ 56613554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 5679242Ssam (void) write(f, buf, strlen(buf)); 5689242Ssam exit(1); 5699242Ssam } 5709242Ssam 57134424Sbostic fatalperror(f, msg) 5729242Ssam int f; 5739242Ssam char *msg; 5749242Ssam { 5759242Ssam char buf[BUFSIZ]; 57616227Skarels extern int sys_nerr; 5779242Ssam extern char *sys_errlist[]; 5789242Ssam 57918357Ssam if ((unsigned)errno < sys_nerr) 58016227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 58116227Skarels else 58216227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 5839242Ssam fatal(f, buf); 5849242Ssam } 58536453Skfall 58636453Skfall do_rlogin(host) 58736518Skarels char *host; 58836453Skfall { 58936453Skfall 59036518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 59136518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 59236518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 59336518Skarels 59436518Skarels if (getuid()) 59536453Skfall return(-1); 59636453Skfall pwd = getpwnam(lusername); 59736518Skarels if (pwd == NULL) 59836453Skfall return(-1); 59936453Skfall return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 60036453Skfall } 60136453Skfall 60236453Skfall 60336518Skarels getstr(buf, cnt, errmsg) 60436518Skarels char *buf; 60536518Skarels int cnt; 60636518Skarels char *errmsg; 60736453Skfall { 60836518Skarels char c; 60936518Skarels 61036453Skfall do { 61136518Skarels if (read(0, &c, 1) != 1) 61236453Skfall exit(1); 61336518Skarels if (--cnt < 0) 61436518Skarels fatal(1, errmsg); 61536453Skfall *buf++ = c; 61636518Skarels } while (c != 0); 61736453Skfall } 61836453Skfall 61936518Skarels extern char **environ; 62036453Skfall 62136519Skarels setup_term(fd) 62236519Skarels int fd; 62336519Skarels { 62436711Skfall register char *cp = index(term+ENVSIZE, '/'); 62536519Skarels char *speed; 62636519Skarels 627*38710Skfall struct termios tt; 62836711Skfall tcgetattr(fd, &tt); 62936519Skarels if (cp) { 63036519Skarels *cp++ = '\0'; 63136519Skarels speed = cp; 63236519Skarels cp = index(speed, '/'); 63336519Skarels if (cp) 63436519Skarels *cp++ = '\0'; 63536711Skfall cfsetspeed(&tt, atoi(speed)); 63636519Skarels } 637*38710Skfall 638*38710Skfall 63936711Skfall tt.c_iflag = BRKINT|ICRNL|IXON|ISTRIP|IEXTEN|IMAXBEL; 64036711Skfall tt.c_oflag = OPOST|ONLCR|OXTABS; 64136711Skfall tt.c_lflag = ISIG|ICANON|ECHO; 64236711Skfall tcsetattr(fd, TCSADFLUSH, &tt); 643*38710Skfall #ifdef notdef 644*38710Skfall { 645*38710Skfall struct sgttyb b; 646*38710Skfall (void) ioctl(fd, TIOCGETP, &b); 647*38710Skfall b.sg_flags = ECHO|CRMOD|ANYP; 648*38710Skfall b.sg_ispeed = b.sg_ospeed = atoi(speed); 649*38710Skfall (void) ioctl(fd, TIOCSETP, &b); 650*38710Skfall } 651*38710Skfall #endif 65236519Skarels 65336519Skarels env[0] = term; 65436519Skarels env[1] = 0; 65536519Skarels environ = env; 65636519Skarels } 65736609Skfall 65836711Skfall #ifdef KERBEROS 65936711Skfall #define VERSION_SIZE 9 66036711Skfall 66136609Skfall /* 66236711Skfall * Do the remote kerberos login to the named host with the 66336711Skfall * given inet address 66436711Skfall * 66536711Skfall * Return 0 on valid authorization 66636711Skfall * Return -1 on valid authentication, no authorization 66736711Skfall * Return >0 for error conditions 66836711Skfall */ 66936711Skfall do_krb_login(host, dest, encrypt) 67036711Skfall char *host; 67136711Skfall struct sockaddr_in *dest; 67236711Skfall int encrypt; 67336711Skfall { 67436711Skfall int rc; 67536711Skfall char instance[INST_SZ], version[VERSION_SIZE]; 67636711Skfall long authopts = 0L; /* !mutual */ 67736711Skfall struct sockaddr_in faddr; 67836711Skfall 67936711Skfall if (getuid()) 68036711Skfall return(KFAILURE); 68136711Skfall 68236711Skfall kdata = (AUTH_DAT *) auth_buf; 68336711Skfall ticket = (KTEXT) tick_buf; 68436711Skfall strcpy(instance, "*"); 68536711Skfall 68636711Skfall if (encrypt) { 68736711Skfall rc = sizeof(faddr); 68836711Skfall if (getsockname(0, &faddr, &rc)) 68936711Skfall return(-1); 69036711Skfall authopts = KOPT_DO_MUTUAL; 69136711Skfall rc = krb_recvauth( 69236711Skfall authopts, 0, 69336711Skfall ticket, "rcmd", 69436711Skfall instance, dest, &faddr, 69536711Skfall kdata, "", schedule, version); 69636711Skfall des_set_key(kdata->session, schedule); 69736711Skfall 69836711Skfall } else { 69936711Skfall rc = krb_recvauth( 70036711Skfall authopts, 0, 70136711Skfall ticket, "rcmd", 70236711Skfall instance, dest, (struct sockaddr_in *) 0, 70336711Skfall kdata, "", (bit_64 *) 0, version); 70436711Skfall } 70536711Skfall 70636711Skfall if (rc != KSUCCESS) 70736711Skfall return(rc); 70836711Skfall 70936711Skfall getstr(lusername, sizeof(lusername), "locuser"); 71036711Skfall /* get the "cmd" in the rcmd protocol */ 71136711Skfall getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 71236711Skfall 71336711Skfall pwd = getpwnam(lusername); 71436711Skfall if (pwd == NULL) 71536711Skfall return(-1); 71636711Skfall 71736711Skfall /* returns nonzero for no access */ 71836711Skfall /* return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); */ 71936711Skfall if (kuserok(kdata,lusername) != 0) 72036711Skfall return(-1); 72136711Skfall 72236711Skfall return(0); 72336711Skfall 72436711Skfall } 72536711Skfall 72636711Skfall #endif /* KERBEROS */ 72736711Skfall 72836711Skfall usage() 72936711Skfall { 73036711Skfall #ifdef KERBEROS 73136711Skfall syslog(LOG_ERR, "usage: rlogind [-k | -v] [-l] [-n]"); 73236711Skfall #else 73336711Skfall syslog(LOG_ERR, "usage: rlogind [-l] [-n]"); 73436711Skfall #endif 73536711Skfall } 73636711Skfall 73736711Skfall /* 73836631Skarels * Check whether host h is in our local domain, 73936631Skarels * as determined by the part of the name following 74036631Skarels * the first '.' in its name and in ours. 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]; 74936631Skarels char *p1, *p2 = index(h, '.'); 75036631Skarels 75136631Skarels (void) gethostname(localhost, sizeof(localhost)); 75236631Skarels p1 = index(localhost, '.'); 75336631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 75436625Skfall return(1); 75536625Skfall return(0); 75636625Skfall } 757