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*37290Sbostic static char sccsid[] = "@(#)rlogind.c 5.35 (Berkeley) 04/02/89"; 2635441Sbostic #endif /* not lint */ 2721174Sdist 2816369Skarels /* 2916369Skarels * remote login server: 3036453Skfall * \0 3116369Skarels * remuser\0 3216369Skarels * locuser\0 3336453Skfall * terminal_type/speed\0 3436518Skarels * data 3516369Skarels */ 3616369Skarels 37*37290Sbostic #include <sys/param.h> 386446Swnj #include <sys/stat.h> 396446Swnj #include <sys/socket.h> 4013554Ssam #include <sys/wait.h> 4118357Ssam #include <sys/file.h> 42*37290Sbostic #include <sys/signal.h> 43*37290Sbostic #include <sys/ioctl.h> 44*37290Sbostic #include <sys/termios.h> 459208Ssam 469208Ssam #include <netinet/in.h> 479208Ssam 486446Swnj #include <errno.h> 496446Swnj #include <pwd.h> 508380Ssam #include <netdb.h> 5117187Sralph #include <syslog.h> 5218357Ssam #include <strings.h> 53*37290Sbostic #include <stdio.h> 54*37290Sbostic #include "pathnames.h" 556446Swnj 5636518Skarels #ifndef TIOCPKT_WINDOW 5736518Skarels #define TIOCPKT_WINDOW 0x80 5836518Skarels #endif 5936518Skarels 6036711Skfall #ifdef KERBEROS 6136711Skfall #include <kerberos/krb.h> 6236711Skfall #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 6336711Skfall 6436711Skfall AUTH_DAT *kdata; 6536711Skfall KTEXT ticket; 6636711Skfall u_char auth_buf[sizeof(AUTH_DAT)]; 6736711Skfall u_char tick_buf[sizeof(KTEXT_ST)]; 6836711Skfall Key_schedule schedule; 6936711Skfall int encrypt = 0, retval, use_kerberos = 0, vacuous = 0; 7036711Skfall int do_krb_login(); 7136711Skfall 7236715Skfall #define ARGSTR "lnkvx" 7336711Skfall #else 7436711Skfall #define ARGSTR "ln" 7536711Skfall #endif /* KERBEROS */ 7636711Skfall 7736518Skarels char *env[2]; 7836518Skarels #define NMAX 30 7936517Skarels char lusername[NMAX+1], rusername[NMAX+1]; 8036517Skarels static char term[64] = "TERM="; 8136517Skarels #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 8236517Skarels int keepalive = 1; 8336453Skfall 8436453Skfall #define SUPERUSER(pwd) ((pwd)->pw_uid == 0) 8536453Skfall 8634424Sbostic extern int errno; 8710417Ssam int reapchild(); 8836453Skfall struct passwd *getpwnam(), *pwd; 8924723Smckusick char *malloc(); 9016369Skarels 916446Swnj main(argc, argv) 926446Swnj int argc; 936446Swnj char **argv; 946446Swnj { 9536319Sbostic extern int opterr, optind, _check_rhosts_file; 9636319Sbostic int ch; 9734424Sbostic int on = 1, fromlen; 986446Swnj struct sockaddr_in from; 996446Swnj 10036625Skfall openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 10136319Sbostic 10236319Sbostic opterr = 0; 10336711Skfall while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 10436517Skarels switch (ch) { 10536319Sbostic case 'l': 10636319Sbostic _check_rhosts_file = 0; 10736319Sbostic break; 10836517Skarels case 'n': 10936517Skarels keepalive = 0; 11036517Skarels break; 11136711Skfall #ifdef KERBEROS 11236711Skfall case 'k': 11336711Skfall use_kerberos = 1; 11436711Skfall break; 11536711Skfall case 'v': 11636711Skfall vacuous = 1; 11736711Skfall break; 11836715Skfall case 'x': 11936715Skfall encrypt = 1; 12036715Skfall break; 12136711Skfall #endif 12236319Sbostic case '?': 12336319Sbostic default: 12436711Skfall usage(); 12536319Sbostic break; 12636319Sbostic } 12736319Sbostic argc -= optind; 12836319Sbostic argv += optind; 12936319Sbostic 13036711Skfall #ifdef KERBEROS 13136711Skfall if (use_kerberos && vacuous) { 13236711Skfall usage(); 13336711Skfall fatal("only one of -k and -v allowed\n"); 13436711Skfall } 13536711Skfall #endif 13616369Skarels fromlen = sizeof (from); 13716369Skarels if (getpeername(0, &from, &fromlen) < 0) { 13836711Skfall syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 13936711Skfall fatalperror("Can't get peer name of remote host"); 1408380Ssam } 14136517Skarels if (keepalive && 14236517Skarels setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 14317187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 14416369Skarels doit(0, &from); 1456446Swnj } 1466446Swnj 1476446Swnj int child; 1486446Swnj int cleanup(); 1496446Swnj int netf; 1506446Swnj char *line; 15124724Smckusick extern char *inet_ntoa(); 1526446Swnj 15324889Smckusick struct winsize win = { 0, 0, 0, 0 }; 15424723Smckusick 15524889Smckusick 1566446Swnj doit(f, fromp) 1576446Swnj int f; 1586446Swnj struct sockaddr_in *fromp; 1596446Swnj { 16018357Ssam int i, p, t, pid, on = 1; 16136631Skarels int authenticated = 0, hostok = 0; 16236711Skfall register struct hostent *hp; 16336703Skarels char remotehost[2 * MAXHOSTNAMELEN + 1]; 16424724Smckusick struct hostent hostent; 1658380Ssam char c; 1666446Swnj 1676446Swnj alarm(60); 1686446Swnj read(f, &c, 1); 16936711Skfall 17036715Skfall if(c != 0) 17136715Skfall exit(1); 17236711Skfall #ifdef KERBEROS 17336715Skfall if(vacuous) 17436715Skfall fatal(f, "Remote host requires Kerberos authentication"); 17536711Skfall #endif 17636453Skfall 1776446Swnj alarm(0); 17816227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 1798380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 1808380Ssam fromp->sin_family); 18111345Ssam if (hp == 0) { 18224724Smckusick /* 18324724Smckusick * Only the name is used below. 18424724Smckusick */ 18524724Smckusick hp = &hostent; 18624724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 18736635Skarels hostok++; 18836711Skfall } else if (local_domain(hp->h_name)) { 18936635Skarels /* 19036635Skarels * If name returned by gethostbyaddr is in our domain, 19136635Skarels * attempt to verify that we haven't been fooled by someone 19236635Skarels * in a remote net; look up the name and check that this 19336635Skarels * address corresponds to the name. 19436635Skarels */ 19536635Skarels strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 19636635Skarels remotehost[sizeof(remotehost) - 1] = 0; 19736635Skarels hp = gethostbyname(remotehost); 19836635Skarels if (hp) 19936635Skarels for (; hp->h_addr_list[0]; hp->h_addr_list++) 20036635Skarels if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 20136635Skarels sizeof(fromp->sin_addr))) { 20236635Skarels hostok++; 20336635Skarels break; 20436635Skarels } 20536633Skarels } else 20636635Skarels hostok++; 20736711Skfall 20836711Skfall #ifdef KERBEROS 20936711Skfall if (use_kerberos) { 21036711Skfall retval = do_krb_login(hp->h_name, fromp, encrypt); 21136711Skfall write(f, &c, 1); 21236711Skfall if (retval == 0 && hostok) 21336711Skfall authenticated++; 21436711Skfall else if (retval > 0) 21536711Skfall fatal(f, krb_err_txt[retval]); 21636711Skfall else if(!hostok) 21736711Skfall fatal(f, "krlogind: Host address mismatch.\r\n"); 21836711Skfall } else 21936703Skarels #endif 22036711Skfall { 22136711Skfall if (fromp->sin_family != AF_INET || 22236711Skfall fromp->sin_port >= IPPORT_RESERVED || 22336711Skfall fromp->sin_port < IPPORT_RESERVED/2) { 22436711Skfall syslog(LOG_NOTICE, "Connection from %s on illegal port", 22536711Skfall inet_ntoa(fromp->sin_addr)); 22636711Skfall fatal(f, "Permission denied"); 22736711Skfall } 22836702Skarels #ifdef IP_OPTIONS 22936711Skfall { 23036711Skfall u_char optbuf[BUFSIZ/3], *cp; 23136711Skfall char lbuf[BUFSIZ], *lp; 23236711Skfall int optsize = sizeof(optbuf), ipproto; 23336711Skfall struct protoent *ip; 23436702Skarels 23536711Skfall if ((ip = getprotobyname("ip")) != NULL) 23636711Skfall ipproto = ip->p_proto; 23736711Skfall else 23836711Skfall ipproto = IPPROTO_IP; 23936711Skfall if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 24036711Skfall &optsize) == 0 && optsize != 0) { 24136711Skfall lp = lbuf; 24236711Skfall for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 24336711Skfall sprintf(lp, " %2.2x", *cp); 24436711Skfall syslog(LOG_NOTICE, 24536711Skfall "Connection received using IP options (ignored):%s", 24636711Skfall lbuf); 24736711Skfall if (setsockopt(0, ipproto, IP_OPTIONS, 24836711Skfall (char *)NULL, &optsize) != 0) { 24936711Skfall syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 25036711Skfall exit(1); 25136711Skfall } 25236711Skfall } 25336711Skfall } 25436702Skarels #endif 25536711Skfall write(f, "", 1); 25636711Skfall 25736711Skfall if (do_rlogin(hp->h_name) == 0) { 25836711Skfall if (hostok) 25936711Skfall authenticated++; 26036711Skfall else 26136711Skfall write(f, "rlogind: Host address mismatch.\r\n", 26236711Skfall sizeof("rlogind: Host address mismatch.\r\n") - 1); 26336711Skfall } 26436631Skarels } 26536636Skarels 2666446Swnj for (c = 'p'; c <= 's'; c++) { 2676446Swnj struct stat stb; 2686446Swnj line = "/dev/ptyXX"; 2696446Swnj line[strlen("/dev/pty")] = c; 2706446Swnj line[strlen("/dev/ptyp")] = '0'; 2716446Swnj if (stat(line, &stb) < 0) 2726446Swnj break; 2736446Swnj for (i = 0; i < 16; i++) { 27434424Sbostic line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 27534424Sbostic p = open(line, O_RDWR); 2766446Swnj if (p > 0) 2776446Swnj goto gotpty; 2786446Swnj } 2796446Swnj } 28024723Smckusick fatal(f, "Out of ptys"); 2819242Ssam /*NOTREACHED*/ 2826446Swnj gotpty: 28324889Smckusick (void) ioctl(p, TIOCSWINSZ, &win); 28416227Skarels netf = f; 2856446Swnj line[strlen("/dev/")] = 't'; 28634424Sbostic t = open(line, O_RDWR); 28734424Sbostic if (t < 0) 28834424Sbostic fatalperror(f, line); 28934424Sbostic if (fchmod(t, 0)) 29034424Sbostic fatalperror(f, line); 29134424Sbostic (void)signal(SIGHUP, SIG_IGN); 29234424Sbostic vhangup(); 29334424Sbostic (void)signal(SIGHUP, SIG_DFL); 29434424Sbostic t = open(line, O_RDWR); 29534424Sbostic if (t < 0) 29634424Sbostic fatalperror(f, line); 29736453Skfall setup_term(t); 2986446Swnj #ifdef DEBUG 29934424Sbostic { 30034424Sbostic int tt = open("/dev/tty", O_RDWR); 30134424Sbostic if (tt > 0) { 30234424Sbostic (void)ioctl(tt, TIOCNOTTY, 0); 30334424Sbostic (void)close(tt); 30434424Sbostic } 3056446Swnj } 3066446Swnj #endif 3079242Ssam pid = fork(); 3089242Ssam if (pid < 0) 30934424Sbostic fatalperror(f, ""); 31018357Ssam if (pid == 0) { 31136711Skfall if (setsid() < 0) 31236711Skfall fatalperror(f, "setsid"); 31336711Skfall if (ioctl(t, TIOCSCTTY, 0) < 0) 31436711Skfall fatalperror(f, "ioctl(sctty)"); 31518357Ssam close(f), close(p); 31618357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 31716227Skarels close(t); 31836631Skarels if (authenticated) 319*37290Sbostic execl(_PATH_LOGIN, "login", "-p", 32036711Skfall "-h", hp->h_name, "-f", lusername, 0); 32136525Skfall else 322*37290Sbostic execl(_PATH_LOGIN, "login", "-p", 32336711Skfall "-h", hp->h_name, lusername, 0); 324*37290Sbostic fatalperror(2, _PATH_LOGIN); 32518357Ssam /*NOTREACHED*/ 32618357Ssam } 32718357Ssam close(t); 32836453Skfall 32936711Skfall #ifdef KERBEROS 33036711Skfall /* 33136711Skfall * If encrypted, don't turn on NBIO or the des read/write 33236711Skfall * routines will croak. 33336711Skfall */ 33436711Skfall 33536711Skfall if (encrypt) 33636711Skfall (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 33736711Skfall else 33836711Skfall #endif 33936711Skfall ioctl(f, FIONBIO, &on); 34018357Ssam ioctl(p, FIONBIO, &on); 34118357Ssam ioctl(p, TIOCPKT, &on); 34218357Ssam signal(SIGTSTP, SIG_IGN); 34318357Ssam signal(SIGCHLD, cleanup); 34424724Smckusick setpgrp(0, 0); 34518357Ssam protocol(f, p); 34630600Smckusick signal(SIGCHLD, SIG_IGN); 34718357Ssam cleanup(); 34818357Ssam } 3499242Ssam 35018357Ssam char magic[2] = { 0377, 0377 }; 35125423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 35218357Ssam 35318357Ssam /* 35418357Ssam * Handle a "control" request (signaled by magic being present) 35518357Ssam * in the data stream. For now, we are only willing to handle 35618357Ssam * window size changes. 35718357Ssam */ 35818357Ssam control(pty, cp, n) 35918357Ssam int pty; 36018357Ssam char *cp; 36118357Ssam int n; 36218357Ssam { 36328705Smckusick struct winsize w; 36418357Ssam 36528705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 36618357Ssam return (0); 36725423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 36828705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 36928705Smckusick w.ws_row = ntohs(w.ws_row); 37028705Smckusick w.ws_col = ntohs(w.ws_col); 37128705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 37228705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 37328705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 37428705Smckusick return (4+sizeof (w)); 37518357Ssam } 37618357Ssam 37718357Ssam /* 37818357Ssam * rlogin "protocol" machine. 37918357Ssam */ 38018357Ssam protocol(f, p) 38118357Ssam int f, p; 38218357Ssam { 38318357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 38418357Ssam register pcc = 0, fcc = 0; 38536517Skarels int cc, nfd, pmask, fmask; 38625740Skarels char cntl; 38718357Ssam 38818482Ssam /* 38918484Ssam * Must ignore SIGTTOU, otherwise we'll stop 39018484Ssam * when we try and set slave pty's window shape 39125423Skarels * (our controlling tty is the master pty). 39218482Ssam */ 39318484Ssam (void) signal(SIGTTOU, SIG_IGN); 39425423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 39536517Skarels if (f > p) 39636517Skarels nfd = f + 1; 39736517Skarels else 39836517Skarels nfd = p + 1; 39936517Skarels fmask = 1 << f; 40036517Skarels pmask = 1 << p; 40118357Ssam for (;;) { 40225740Skarels int ibits, obits, ebits; 40318357Ssam 40425740Skarels ibits = 0; 40525740Skarels obits = 0; 40618357Ssam if (fcc) 40736517Skarels obits |= pmask; 40818357Ssam else 40936517Skarels ibits |= fmask; 41018357Ssam if (pcc >= 0) 41118357Ssam if (pcc) 41236517Skarels obits |= fmask; 4139242Ssam else 41436517Skarels ibits |= pmask; 41536517Skarels ebits = pmask; 41636517Skarels if (select(nfd, &ibits, obits ? &obits : (int *)NULL, 41736517Skarels &ebits, 0) < 0) { 41818357Ssam if (errno == EINTR) 4196446Swnj continue; 42034424Sbostic fatalperror(f, "select"); 42118357Ssam } 42225740Skarels if (ibits == 0 && obits == 0 && ebits == 0) { 42318357Ssam /* shouldn't happen... */ 42418357Ssam sleep(5); 42518357Ssam continue; 42618357Ssam } 42725740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 42836517Skarels if (ebits & pmask) { 42925740Skarels cc = read(p, &cntl, 1); 43025740Skarels if (cc == 1 && pkcontrol(cntl)) { 43125740Skarels cntl |= oobdata[0]; 43225740Skarels send(f, &cntl, 1, MSG_OOB); 43325740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 43425740Skarels pcc = 0; 43536517Skarels ibits &= ~pmask; 43625740Skarels } 43725740Skarels } 43825740Skarels } 43936517Skarels if (ibits & fmask) { 44036711Skfall #ifdef KERBEROS 44136711Skfall if (encrypt) 44236711Skfall fcc = des_read(f, fibuf, sizeof(fibuf)); 44336711Skfall else 44436711Skfall #endif 44536711Skfall fcc = read(f, fibuf, sizeof(fibuf)); 44618357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 44718357Ssam fcc = 0; 44818357Ssam else { 44918357Ssam register char *cp; 45018357Ssam int left, n; 45118357Ssam 45218357Ssam if (fcc <= 0) 45316227Skarels break; 45418357Ssam fbp = fibuf; 45524723Smckusick 45618357Ssam top: 45725423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 45818357Ssam if (cp[0] == magic[0] && 45918357Ssam cp[1] == magic[1]) { 46018357Ssam left = fcc - (cp-fibuf); 46118357Ssam n = control(p, cp, left); 46218357Ssam if (n) { 46318357Ssam left -= n; 46418357Ssam if (left > 0) 46525423Skarels bcopy(cp+n, cp, left); 46618357Ssam fcc -= n; 46718357Ssam goto top; /* n^2 */ 46825423Skarels } 46925423Skarels } 47036517Skarels obits |= pmask; /* try write */ 47125423Skarels } 47225423Skarels } 47324723Smckusick 47436517Skarels if ((obits & pmask) && fcc > 0) { 47525423Skarels cc = write(p, fbp, fcc); 47624723Smckusick if (cc > 0) { 47724723Smckusick fcc -= cc; 47824723Smckusick fbp += cc; 4796446Swnj } 48018357Ssam } 48124723Smckusick 48236517Skarels if (ibits & pmask) { 48318357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 48418357Ssam pbp = pibuf; 48518357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 48618357Ssam pcc = 0; 48718357Ssam else if (pcc <= 0) 48818357Ssam break; 48936517Skarels else if (pibuf[0] == 0) { 49018357Ssam pbp++, pcc--; 49136711Skfall #ifdef KERBEROS 49236711Skfall if (!encrypt) 49336711Skfall #endif 49436711Skfall obits |= fmask; /* try a write */ 49536517Skarels } else { 49618357Ssam if (pkcontrol(pibuf[0])) { 49725423Skarels pibuf[0] |= oobdata[0]; 49818357Ssam send(f, &pibuf[0], 1, MSG_OOB); 49916227Skarels } 50018357Ssam pcc = 0; 5016446Swnj } 50218357Ssam } 50336517Skarels if ((obits & fmask) && pcc > 0) { 50436711Skfall #ifdef KERBEROS 50536711Skfall if (encrypt) 50636711Skfall cc = des_write(f, pbp, pcc); 50736711Skfall else 50836711Skfall #endif 50936711Skfall cc = write(f, pbp, pcc); 51025423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 51125423Skarels /* also shouldn't happen */ 51225423Skarels sleep(5); 51325423Skarels continue; 51425423Skarels } 51518357Ssam if (cc > 0) { 51618357Ssam pcc -= cc; 51718357Ssam pbp += cc; 51818357Ssam } 5196446Swnj } 5206446Swnj } 5216446Swnj } 5226446Swnj 5236446Swnj cleanup() 5246446Swnj { 52535440Sbostic char *p; 52635440Sbostic 52735440Sbostic p = line + sizeof("/dev/") - 1; 52835440Sbostic if (logout(p)) 52935440Sbostic logwtmp(p, "", ""); 53035440Sbostic (void)chmod(line, 0666); 53135440Sbostic (void)chown(line, 0, 0); 53235440Sbostic *p = 'p'; 53335440Sbostic (void)chmod(line, 0666); 53435440Sbostic (void)chown(line, 0, 0); 53510192Ssam shutdown(netf, 2); 5366446Swnj exit(1); 5376446Swnj } 5386446Swnj 5399242Ssam fatal(f, msg) 5409242Ssam int f; 5419242Ssam char *msg; 5429242Ssam { 5439242Ssam char buf[BUFSIZ]; 5449242Ssam 5459242Ssam buf[0] = '\01'; /* error indicator */ 54613554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 5479242Ssam (void) write(f, buf, strlen(buf)); 5489242Ssam exit(1); 5499242Ssam } 5509242Ssam 55134424Sbostic fatalperror(f, msg) 5529242Ssam int f; 5539242Ssam char *msg; 5549242Ssam { 5559242Ssam char buf[BUFSIZ]; 55616227Skarels extern int sys_nerr; 5579242Ssam extern char *sys_errlist[]; 5589242Ssam 55918357Ssam if ((unsigned)errno < sys_nerr) 56016227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 56116227Skarels else 56216227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 5639242Ssam fatal(f, buf); 5649242Ssam } 56536453Skfall 56636453Skfall do_rlogin(host) 56736518Skarels char *host; 56836453Skfall { 56936453Skfall 57036518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 57136518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 57236518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 57336518Skarels 57436518Skarels if (getuid()) 57536453Skfall return(-1); 57636453Skfall pwd = getpwnam(lusername); 57736518Skarels if (pwd == NULL) 57836453Skfall return(-1); 57936453Skfall return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 58036453Skfall } 58136453Skfall 58236453Skfall 58336518Skarels getstr(buf, cnt, errmsg) 58436518Skarels char *buf; 58536518Skarels int cnt; 58636518Skarels char *errmsg; 58736453Skfall { 58836518Skarels char c; 58936518Skarels 59036453Skfall do { 59136518Skarels if (read(0, &c, 1) != 1) 59236453Skfall exit(1); 59336518Skarels if (--cnt < 0) 59436518Skarels fatal(1, errmsg); 59536453Skfall *buf++ = c; 59636518Skarels } while (c != 0); 59736453Skfall } 59836453Skfall 59936518Skarels extern char **environ; 60036453Skfall 60136519Skarels setup_term(fd) 60236519Skarels int fd; 60336519Skarels { 60436711Skfall struct termios tt; 60536711Skfall register char *cp = index(term+ENVSIZE, '/'); 60636519Skarels char *speed; 60736519Skarels 60836711Skfall tcgetattr(fd, &tt); 60936519Skarels if (cp) { 61036519Skarels *cp++ = '\0'; 61136519Skarels speed = cp; 61236519Skarels cp = index(speed, '/'); 61336519Skarels if (cp) 61436519Skarels *cp++ = '\0'; 61536711Skfall cfsetspeed(&tt, atoi(speed)); 61636519Skarels } 61736711Skfall tt.c_iflag = BRKINT|ICRNL|IXON|ISTRIP|IEXTEN|IMAXBEL; 61836711Skfall tt.c_oflag = OPOST|ONLCR|OXTABS; 61936711Skfall tt.c_lflag = ISIG|ICANON|ECHO; 62036711Skfall tcsetattr(fd, TCSADFLUSH, &tt); 62136519Skarels 62236519Skarels env[0] = term; 62336519Skarels env[1] = 0; 62436519Skarels environ = env; 62536519Skarels } 62636609Skfall 62736711Skfall #ifdef KERBEROS 62836711Skfall #define VERSION_SIZE 9 62936711Skfall 63036609Skfall /* 63136711Skfall * Do the remote kerberos login to the named host with the 63236711Skfall * given inet address 63336711Skfall * 63436711Skfall * Return 0 on valid authorization 63536711Skfall * Return -1 on valid authentication, no authorization 63636711Skfall * Return >0 for error conditions 63736711Skfall */ 63836711Skfall do_krb_login(host, dest, encrypt) 63936711Skfall char *host; 64036711Skfall struct sockaddr_in *dest; 64136711Skfall int encrypt; 64236711Skfall { 64336711Skfall int rc; 64436711Skfall char instance[INST_SZ], version[VERSION_SIZE]; 64536711Skfall long authopts = 0L; /* !mutual */ 64636711Skfall struct sockaddr_in faddr; 64736711Skfall 64836711Skfall if (getuid()) 64936711Skfall return(KFAILURE); 65036711Skfall 65136711Skfall kdata = (AUTH_DAT *) auth_buf; 65236711Skfall ticket = (KTEXT) tick_buf; 65336711Skfall strcpy(instance, "*"); 65436711Skfall 65536711Skfall if (encrypt) { 65636711Skfall rc = sizeof(faddr); 65736711Skfall if (getsockname(0, &faddr, &rc)) 65836711Skfall return(-1); 65936711Skfall authopts = KOPT_DO_MUTUAL; 66036711Skfall rc = krb_recvauth( 66136711Skfall authopts, 0, 66236711Skfall ticket, "rcmd", 66336711Skfall instance, dest, &faddr, 66436711Skfall kdata, "", schedule, version); 66536711Skfall des_set_key(kdata->session, schedule); 66636711Skfall 66736711Skfall } else { 66836711Skfall rc = krb_recvauth( 66936711Skfall authopts, 0, 67036711Skfall ticket, "rcmd", 67136711Skfall instance, dest, (struct sockaddr_in *) 0, 67236711Skfall kdata, "", (bit_64 *) 0, version); 67336711Skfall } 67436711Skfall 67536711Skfall if (rc != KSUCCESS) 67636711Skfall return(rc); 67736711Skfall 67836711Skfall getstr(lusername, sizeof(lusername), "locuser"); 67936711Skfall /* get the "cmd" in the rcmd protocol */ 68036711Skfall getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 68136711Skfall 68236711Skfall pwd = getpwnam(lusername); 68336711Skfall if (pwd == NULL) 68436711Skfall return(-1); 68536711Skfall 68636711Skfall /* returns nonzero for no access */ 68736711Skfall /* return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); */ 68836711Skfall if (kuserok(kdata,lusername) != 0) 68936711Skfall return(-1); 69036711Skfall 69136711Skfall return(0); 69236711Skfall 69336711Skfall } 69436711Skfall 69536711Skfall #endif /* KERBEROS */ 69636711Skfall 69736711Skfall usage() 69836711Skfall { 69936711Skfall #ifdef KERBEROS 70036711Skfall syslog(LOG_ERR, "usage: rlogind [-k | -v] [-l] [-n]"); 70136711Skfall #else 70236711Skfall syslog(LOG_ERR, "usage: rlogind [-l] [-n]"); 70336711Skfall #endif 70436711Skfall } 70536711Skfall 70636711Skfall /* 70736631Skarels * Check whether host h is in our local domain, 70836631Skarels * as determined by the part of the name following 70936631Skarels * the first '.' in its name and in ours. 71036631Skarels * If either name is unqualified (contains no '.'), 71136631Skarels * assume that the host is local, as it will be 71236631Skarels * interpreted as such. 71336631Skarels */ 71436631Skarels local_domain(h) 71536631Skarels char *h; 71636625Skfall { 71736631Skarels char localhost[MAXHOSTNAMELEN]; 71836631Skarels char *p1, *p2 = index(h, '.'); 71936631Skarels 72036631Skarels (void) gethostname(localhost, sizeof(localhost)); 72136631Skarels p1 = index(localhost, '.'); 72236631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 72336625Skfall return(1); 72436625Skfall return(0); 72536625Skfall } 726