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*36636Skarels static char sccsid[] = "@(#)rlogind.c 5.29 (Berkeley) 01/25/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 376446Swnj #include <stdio.h> 38*36636Skarels #include <sys/types.h> 396446Swnj #include <sys/stat.h> 406446Swnj #include <sys/socket.h> 4113554Ssam #include <sys/wait.h> 4218357Ssam #include <sys/file.h> 43*36636Skarels #include <sys/param.h> 449208Ssam 459208Ssam #include <netinet/in.h> 469208Ssam 476446Swnj #include <errno.h> 486446Swnj #include <pwd.h> 496446Swnj #include <signal.h> 50*36636Skarels #include <sys/ioctl.h> 51*36636Skarels #include <sys/termios.h> 526446Swnj #include <stdio.h> 538380Ssam #include <netdb.h> 5417187Sralph #include <syslog.h> 5518357Ssam #include <strings.h> 566446Swnj 5736518Skarels #ifndef TIOCPKT_WINDOW 5836518Skarels #define TIOCPKT_WINDOW 0x80 5936518Skarels #endif 6036518Skarels 61*36636Skarels #ifdef KERBEROS 62*36636Skarels #include <kerberos/krb.h> 63*36636Skarels #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 64*36636Skarels 65*36636Skarels AUTH_DAT *kdata; 66*36636Skarels KTEXT ticket; 67*36636Skarels u_char auth_buf[sizeof(AUTH_DAT)]; 68*36636Skarels u_char tick_buf[sizeof(KTEXT_ST)]; 69*36636Skarels Key_schedule schedule; 70*36636Skarels int encrypt, retval, use_kerberos = 0, vacuous = 0; 71*36636Skarels int do_krb_login(); 72*36636Skarels 73*36636Skarels #define OLD_RCMD 0x00 74*36636Skarels #define KERB_RCMD 0x00 75*36636Skarels #define KERB_RCMD_MUTUAL 0x03 76*36636Skarels 77*36636Skarels #define ARGSTR "lnkv" 78*36636Skarels #else 79*36636Skarels #define ARGSTR "ln" 80*36636Skarels #endif /* KERBEROS */ 81*36636Skarels 8236518Skarels char *env[2]; 8336518Skarels #define NMAX 30 8436517Skarels char lusername[NMAX+1], rusername[NMAX+1]; 8536517Skarels static char term[64] = "TERM="; 8636517Skarels #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 8736517Skarels int keepalive = 1; 8836453Skfall 8936453Skfall #define SUPERUSER(pwd) ((pwd)->pw_uid == 0) 9036453Skfall 9134424Sbostic extern int errno; 9210417Ssam int reapchild(); 9336453Skfall struct passwd *getpwnam(), *pwd; 9424723Smckusick char *malloc(); 9516369Skarels 966446Swnj main(argc, argv) 976446Swnj int argc; 986446Swnj char **argv; 996446Swnj { 10036319Sbostic extern int opterr, optind, _check_rhosts_file; 10136319Sbostic int ch; 10234424Sbostic int on = 1, fromlen; 1036446Swnj struct sockaddr_in from; 1046446Swnj 10536625Skfall openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 10636319Sbostic 10736319Sbostic opterr = 0; 108*36636Skarels while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 10936517Skarels switch (ch) { 11036319Sbostic case 'l': 11136319Sbostic _check_rhosts_file = 0; 11236319Sbostic break; 11336517Skarels case 'n': 11436517Skarels keepalive = 0; 11536517Skarels break; 116*36636Skarels #ifdef KERBEROS 117*36636Skarels case 'k': 118*36636Skarels use_kerberos = 1; 119*36636Skarels break; 120*36636Skarels case 'v': 121*36636Skarels vacuous = 1; 122*36636Skarels break; 123*36636Skarels #endif 12436319Sbostic case '?': 12536319Sbostic default: 126*36636Skarels usage(); 12736319Sbostic break; 12836319Sbostic } 12936319Sbostic argc -= optind; 13036319Sbostic argv += optind; 13136319Sbostic 132*36636Skarels #ifdef KERBEROS 133*36636Skarels if (use_kerberos && vacuous) { 134*36636Skarels usage(); 135*36636Skarels fatal("only one of -k and -v allowed\n"); 136*36636Skarels } 137*36636Skarels #endif 13816369Skarels fromlen = sizeof (from); 13916369Skarels if (getpeername(0, &from, &fromlen) < 0) { 140*36636Skarels syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 141*36636Skarels fatalperror("Can't get peer name of remote host"); 1428380Ssam } 14336517Skarels if (keepalive && 14436517Skarels setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 14517187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 14616369Skarels doit(0, &from); 1476446Swnj } 1486446Swnj 1496446Swnj int child; 1506446Swnj int cleanup(); 1516446Swnj int netf; 1526446Swnj char *line; 15324724Smckusick extern char *inet_ntoa(); 1546446Swnj 15524889Smckusick struct winsize win = { 0, 0, 0, 0 }; 15624723Smckusick 15724889Smckusick 1586446Swnj doit(f, fromp) 1596446Swnj int f; 1606446Swnj struct sockaddr_in *fromp; 1616446Swnj { 16218357Ssam int i, p, t, pid, on = 1; 16336631Skarels int authenticated = 0, hostok = 0; 164*36636Skarels register struct hostent *hp; 16536635Skarels char remotehost[2 * MAXHOSTNAMELEN + 1]; 16624724Smckusick struct hostent hostent; 1678380Ssam char c; 1686446Swnj 1696446Swnj alarm(60); 1706446Swnj read(f, &c, 1); 171*36636Skarels 172*36636Skarels #ifdef KERBEROS 173*36636Skarels /* 174*36636Skarels * XXX 1st char tells us which client we're talking to 175*36636Skarels */ 176*36636Skarels switch (c) { 177*36636Skarels 178*36636Skarels case OLD_RCMD: /* OLD_RCMD is same as KERB_RCMD */ 179*36636Skarels if (vacuous) 180*36636Skarels fatal(f, "Remote host requires Kerberos authentication"); 181*36636Skarels break; 182*36636Skarels 183*36636Skarels case KERB_RCMD_MUTUAL: 184*36636Skarels encrypt = 1; 185*36636Skarels break; 186*36636Skarels 187*36636Skarels default: 188*36636Skarels fatal(f, "Remote protocol error"); 189*36636Skarels } 190*36636Skarels #else 1916446Swnj if (c != 0) 1926446Swnj exit(1); 193*36636Skarels #endif 19436453Skfall 1956446Swnj alarm(0); 19616227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 1978380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 1988380Ssam fromp->sin_family); 19911345Ssam if (hp == 0) { 20024724Smckusick /* 20124724Smckusick * Only the name is used below. 20224724Smckusick */ 20324724Smckusick hp = &hostent; 20424724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 20536635Skarels hostok++; 206*36636Skarels } else if (local_domain(hp->h_name)) { 20736635Skarels /* 20836635Skarels * If name returned by gethostbyaddr is in our domain, 20936635Skarels * attempt to verify that we haven't been fooled by someone 21036635Skarels * in a remote net; look up the name and check that this 21136635Skarels * address corresponds to the name. 21236635Skarels */ 21336635Skarels strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 21436635Skarels remotehost[sizeof(remotehost) - 1] = 0; 21536635Skarels hp = gethostbyname(remotehost); 21636635Skarels if (hp) 21736635Skarels for (; hp->h_addr_list[0]; hp->h_addr_list++) 21836635Skarels if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 21936635Skarels sizeof(fromp->sin_addr))) { 22036635Skarels hostok++; 22136635Skarels break; 22236635Skarels } 22336633Skarels } else 22436635Skarels hostok++; 225*36636Skarels 226*36636Skarels #ifdef KERBEROS 227*36636Skarels if (use_kerberos) { 228*36636Skarels retval = do_krb_login(hp->h_name, fromp, encrypt); 229*36636Skarels write(f, &c, 1); 230*36636Skarels if (retval == 0) 231*36636Skarels authenticated++; 232*36636Skarels else if (retval > 0) 233*36636Skarels fatal(f, krb_err_txt[retval]); 234*36636Skarels } else 23536633Skarels #endif 23636631Skarels if (fromp->sin_family != AF_INET || 23736631Skarels fromp->sin_port >= IPPORT_RESERVED || 23836631Skarels fromp->sin_port < IPPORT_RESERVED/2) { 23936631Skarels syslog(LOG_NOTICE, "Connection from %s on illegal port", 24036631Skarels inet_ntoa(fromp->sin_addr)); 24136631Skarels fatal(f, "Permission denied"); 24236631Skarels } 24336632Skarels write(f, "", 1); 244*36636Skarels 24536632Skarels if (do_rlogin(hp->h_name) == 0) { 24636632Skarels if (hostok) 247*36636Skarels authenticated++; 24836632Skarels else 249*36636Skarels write(f, "rlogind: Host address mismatch.\r\n", 250*36636Skarels sizeof("rlogind: Host address mismatch.\r\n") - 1); 25136632Skarels } 25236609Skfall 2536446Swnj for (c = 'p'; c <= 's'; c++) { 2546446Swnj struct stat stb; 2556446Swnj line = "/dev/ptyXX"; 2566446Swnj line[strlen("/dev/pty")] = c; 2576446Swnj line[strlen("/dev/ptyp")] = '0'; 2586446Swnj if (stat(line, &stb) < 0) 2596446Swnj break; 2606446Swnj for (i = 0; i < 16; i++) { 26134424Sbostic line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 26234424Sbostic p = open(line, O_RDWR); 2636446Swnj if (p > 0) 2646446Swnj goto gotpty; 2656446Swnj } 2666446Swnj } 26724723Smckusick fatal(f, "Out of ptys"); 2689242Ssam /*NOTREACHED*/ 2696446Swnj gotpty: 27024889Smckusick (void) ioctl(p, TIOCSWINSZ, &win); 27116227Skarels netf = f; 2726446Swnj line[strlen("/dev/")] = 't'; 27334424Sbostic t = open(line, O_RDWR); 27434424Sbostic if (t < 0) 27534424Sbostic fatalperror(f, line); 27634424Sbostic if (fchmod(t, 0)) 27734424Sbostic fatalperror(f, line); 27834424Sbostic (void)signal(SIGHUP, SIG_IGN); 27934424Sbostic vhangup(); 28034424Sbostic (void)signal(SIGHUP, SIG_DFL); 28134424Sbostic t = open(line, O_RDWR); 28234424Sbostic if (t < 0) 28334424Sbostic fatalperror(f, line); 28436453Skfall setup_term(t); 2856446Swnj #ifdef DEBUG 28634424Sbostic { 28734424Sbostic int tt = open("/dev/tty", O_RDWR); 28834424Sbostic if (tt > 0) { 28934424Sbostic (void)ioctl(tt, TIOCNOTTY, 0); 29034424Sbostic (void)close(tt); 29134424Sbostic } 2926446Swnj } 2936446Swnj #endif 2949242Ssam pid = fork(); 2959242Ssam if (pid < 0) 29634424Sbostic fatalperror(f, ""); 29718357Ssam if (pid == 0) { 298*36636Skarels if (setsid() < 0) 299*36636Skarels fatalperror(f, "setsid"); 300*36636Skarels if (ioctl(t, TIOCSCTTY, 0) < 0) 301*36636Skarels fatalperror(f, "ioctl(sctty)"); 30218357Ssam close(f), close(p); 30318357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 30416227Skarels close(t); 30536631Skarels if (authenticated) 306*36636Skarels execl("/bin/login", "login", "-p", 307*36636Skarels "-h", hp->h_name, "-f", lusername, 0); 30836525Skfall else 309*36636Skarels execl("/bin/login", "login", "-p", 310*36636Skarels "-h", hp->h_name, lusername, 0); 31134424Sbostic fatalperror(2, "/bin/login"); 31218357Ssam /*NOTREACHED*/ 31318357Ssam } 31418357Ssam close(t); 31536453Skfall 316*36636Skarels #ifdef KERBEROS 317*36636Skarels /* 318*36636Skarels * If encrypted, don't turn on NBIO or the des read/write 319*36636Skarels * routines will croak. 320*36636Skarels */ 321*36636Skarels 322*36636Skarels if (encrypt) 323*36636Skarels (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 324*36636Skarels else 325*36636Skarels #endif 326*36636Skarels ioctl(f, FIONBIO, &on); 32718357Ssam ioctl(p, FIONBIO, &on); 32818357Ssam ioctl(p, TIOCPKT, &on); 32918357Ssam signal(SIGTSTP, SIG_IGN); 33018357Ssam signal(SIGCHLD, cleanup); 33124724Smckusick setpgrp(0, 0); 33218357Ssam protocol(f, p); 33330600Smckusick signal(SIGCHLD, SIG_IGN); 33418357Ssam cleanup(); 33518357Ssam } 3369242Ssam 33718357Ssam char magic[2] = { 0377, 0377 }; 33825423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 33918357Ssam 34018357Ssam /* 34118357Ssam * Handle a "control" request (signaled by magic being present) 34218357Ssam * in the data stream. For now, we are only willing to handle 34318357Ssam * window size changes. 34418357Ssam */ 34518357Ssam control(pty, cp, n) 34618357Ssam int pty; 34718357Ssam char *cp; 34818357Ssam int n; 34918357Ssam { 35028705Smckusick struct winsize w; 35118357Ssam 35228705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 35318357Ssam return (0); 35425423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 35528705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 35628705Smckusick w.ws_row = ntohs(w.ws_row); 35728705Smckusick w.ws_col = ntohs(w.ws_col); 35828705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 35928705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 36028705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 36128705Smckusick return (4+sizeof (w)); 36218357Ssam } 36318357Ssam 36418357Ssam /* 36518357Ssam * rlogin "protocol" machine. 36618357Ssam */ 36718357Ssam protocol(f, p) 36818357Ssam int f, p; 36918357Ssam { 37018357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 37118357Ssam register pcc = 0, fcc = 0; 37236517Skarels int cc, nfd, pmask, fmask; 37325740Skarels char cntl; 37418357Ssam 37518482Ssam /* 37618484Ssam * Must ignore SIGTTOU, otherwise we'll stop 37718484Ssam * when we try and set slave pty's window shape 37825423Skarels * (our controlling tty is the master pty). 37918482Ssam */ 38018484Ssam (void) signal(SIGTTOU, SIG_IGN); 38125423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 38236517Skarels if (f > p) 38336517Skarels nfd = f + 1; 38436517Skarels else 38536517Skarels nfd = p + 1; 38636517Skarels fmask = 1 << f; 38736517Skarels pmask = 1 << p; 38818357Ssam for (;;) { 38925740Skarels int ibits, obits, ebits; 39018357Ssam 39125740Skarels ibits = 0; 39225740Skarels obits = 0; 39318357Ssam if (fcc) 39436517Skarels obits |= pmask; 39518357Ssam else 39636517Skarels ibits |= fmask; 39718357Ssam if (pcc >= 0) 39818357Ssam if (pcc) 39936517Skarels obits |= fmask; 4009242Ssam else 40136517Skarels ibits |= pmask; 40236517Skarels ebits = pmask; 40336517Skarels if (select(nfd, &ibits, obits ? &obits : (int *)NULL, 40436517Skarels &ebits, 0) < 0) { 40518357Ssam if (errno == EINTR) 4066446Swnj continue; 40734424Sbostic fatalperror(f, "select"); 40818357Ssam } 40925740Skarels if (ibits == 0 && obits == 0 && ebits == 0) { 41018357Ssam /* shouldn't happen... */ 41118357Ssam sleep(5); 41218357Ssam continue; 41318357Ssam } 41425740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 41536517Skarels if (ebits & pmask) { 41625740Skarels cc = read(p, &cntl, 1); 41725740Skarels if (cc == 1 && pkcontrol(cntl)) { 41825740Skarels cntl |= oobdata[0]; 41925740Skarels send(f, &cntl, 1, MSG_OOB); 42025740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 42125740Skarels pcc = 0; 42236517Skarels ibits &= ~pmask; 42325740Skarels } 42425740Skarels } 42525740Skarels } 42636517Skarels if (ibits & fmask) { 427*36636Skarels #ifdef KERBEROS 428*36636Skarels if (encrypt) 429*36636Skarels fcc = des_read(f, fibuf, sizeof(fibuf)); 430*36636Skarels else 431*36636Skarels #endif 432*36636Skarels fcc = read(f, fibuf, sizeof(fibuf)); 43318357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 43418357Ssam fcc = 0; 43518357Ssam else { 43618357Ssam register char *cp; 43718357Ssam int left, n; 43818357Ssam 43918357Ssam if (fcc <= 0) 44016227Skarels break; 44118357Ssam fbp = fibuf; 44224723Smckusick 44318357Ssam top: 44425423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 44518357Ssam if (cp[0] == magic[0] && 44618357Ssam cp[1] == magic[1]) { 44718357Ssam left = fcc - (cp-fibuf); 44818357Ssam n = control(p, cp, left); 44918357Ssam if (n) { 45018357Ssam left -= n; 45118357Ssam if (left > 0) 45225423Skarels bcopy(cp+n, cp, left); 45318357Ssam fcc -= n; 45418357Ssam goto top; /* n^2 */ 45525423Skarels } 45625423Skarels } 45736517Skarels obits |= pmask; /* try write */ 45825423Skarels } 45925423Skarels } 46024723Smckusick 46136517Skarels if ((obits & pmask) && fcc > 0) { 46225423Skarels cc = write(p, fbp, fcc); 46324723Smckusick if (cc > 0) { 46424723Smckusick fcc -= cc; 46524723Smckusick fbp += cc; 4666446Swnj } 46718357Ssam } 46824723Smckusick 46936517Skarels if (ibits & pmask) { 47018357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 47118357Ssam pbp = pibuf; 47218357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 47318357Ssam pcc = 0; 47418357Ssam else if (pcc <= 0) 47518357Ssam break; 47636517Skarels else if (pibuf[0] == 0) { 47718357Ssam pbp++, pcc--; 478*36636Skarels #ifdef KERBEROS 479*36636Skarels if (!encrypt) 480*36636Skarels #endif 481*36636Skarels obits |= fmask; /* try a write */ 48236517Skarels } else { 48318357Ssam if (pkcontrol(pibuf[0])) { 48425423Skarels pibuf[0] |= oobdata[0]; 48518357Ssam send(f, &pibuf[0], 1, MSG_OOB); 48616227Skarels } 48718357Ssam pcc = 0; 4886446Swnj } 48918357Ssam } 49036517Skarels if ((obits & fmask) && pcc > 0) { 491*36636Skarels #ifdef KERBEROS 492*36636Skarels if (encrypt) 493*36636Skarels cc = des_write(f, pbp, pcc); 494*36636Skarels else 495*36636Skarels #endif 496*36636Skarels cc = write(f, pbp, pcc); 49725423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 49825423Skarels /* also shouldn't happen */ 49925423Skarels sleep(5); 50025423Skarels continue; 50125423Skarels } 50218357Ssam if (cc > 0) { 50318357Ssam pcc -= cc; 50418357Ssam pbp += cc; 50518357Ssam } 5066446Swnj } 5076446Swnj } 5086446Swnj } 5096446Swnj 5106446Swnj cleanup() 5116446Swnj { 51235440Sbostic char *p; 51335440Sbostic 51435440Sbostic p = line + sizeof("/dev/") - 1; 51535440Sbostic if (logout(p)) 51635440Sbostic logwtmp(p, "", ""); 51735440Sbostic (void)chmod(line, 0666); 51835440Sbostic (void)chown(line, 0, 0); 51935440Sbostic *p = 'p'; 52035440Sbostic (void)chmod(line, 0666); 52135440Sbostic (void)chown(line, 0, 0); 52210192Ssam shutdown(netf, 2); 5236446Swnj exit(1); 5246446Swnj } 5256446Swnj 5269242Ssam fatal(f, msg) 5279242Ssam int f; 5289242Ssam char *msg; 5299242Ssam { 5309242Ssam char buf[BUFSIZ]; 5319242Ssam 5329242Ssam buf[0] = '\01'; /* error indicator */ 53313554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 5349242Ssam (void) write(f, buf, strlen(buf)); 5359242Ssam exit(1); 5369242Ssam } 5379242Ssam 53834424Sbostic fatalperror(f, msg) 5399242Ssam int f; 5409242Ssam char *msg; 5419242Ssam { 5429242Ssam char buf[BUFSIZ]; 54316227Skarels extern int sys_nerr; 5449242Ssam extern char *sys_errlist[]; 5459242Ssam 54618357Ssam if ((unsigned)errno < sys_nerr) 54716227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 54816227Skarels else 54916227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 5509242Ssam fatal(f, buf); 5519242Ssam } 55236453Skfall 55336453Skfall do_rlogin(host) 55436518Skarels char *host; 55536453Skfall { 55636453Skfall 55736518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 55836518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 55936518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 56036518Skarels 56136518Skarels if (getuid()) 56236453Skfall return(-1); 56336453Skfall pwd = getpwnam(lusername); 56436518Skarels if (pwd == NULL) 56536453Skfall return(-1); 56636453Skfall return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 56736453Skfall } 56836453Skfall 56936453Skfall 57036518Skarels getstr(buf, cnt, errmsg) 57136518Skarels char *buf; 57236518Skarels int cnt; 57336518Skarels char *errmsg; 57436453Skfall { 57536518Skarels char c; 57636518Skarels 57736453Skfall do { 57836518Skarels if (read(0, &c, 1) != 1) 57936453Skfall exit(1); 58036518Skarels if (--cnt < 0) 58136518Skarels fatal(1, errmsg); 58236453Skfall *buf++ = c; 58336518Skarels } while (c != 0); 58436453Skfall } 58536453Skfall 58636518Skarels extern char **environ; 58736453Skfall 58836519Skarels setup_term(fd) 58936519Skarels int fd; 59036519Skarels { 591*36636Skarels struct termios tt; 592*36636Skarels register char *cp = index(term+ENVSIZE, '/'); 59336519Skarels char *speed; 59436519Skarels 595*36636Skarels tcgetattr(fd, &tt); 59636519Skarels if (cp) { 59736519Skarels *cp++ = '\0'; 59836519Skarels speed = cp; 59936519Skarels cp = index(speed, '/'); 60036519Skarels if (cp) 60136519Skarels *cp++ = '\0'; 602*36636Skarels cfsetspeed(&tt, atoi(speed)); 60336519Skarels } 604*36636Skarels tt.c_iflag = BRKINT|ICRNL|IXON|ISTRIP|IEXTEN|IMAXBEL; 605*36636Skarels tt.c_oflag = OPOST|ONLCR|OXTABS; 606*36636Skarels tt.c_lflag = ISIG|ICANON|ECHO; 607*36636Skarels tcsetattr(fd, TCSADFLUSH, &tt); 60836519Skarels 60936519Skarels env[0] = term; 61036519Skarels env[1] = 0; 61136519Skarels environ = env; 61236519Skarels } 61336609Skfall 614*36636Skarels #ifdef KERBEROS 615*36636Skarels #define VERSION_SIZE 9 616*36636Skarels 61736609Skfall /* 618*36636Skarels * Do the remote kerberos login to the named host with the 619*36636Skarels * given inet address 620*36636Skarels * 621*36636Skarels * Return 0 on valid authorization 622*36636Skarels * Return -1 on valid authentication, no authorization 623*36636Skarels * Return >0 for error conditions 624*36636Skarels */ 625*36636Skarels do_krb_login(host, dest, encrypt) 626*36636Skarels char *host; 627*36636Skarels struct sockaddr_in *dest; 628*36636Skarels int encrypt; 629*36636Skarels { 630*36636Skarels int rc; 631*36636Skarels char instance[INST_SZ], version[VERSION_SIZE]; 632*36636Skarels long authopts = 0L; /* !mutual */ 633*36636Skarels struct sockaddr_in faddr; 634*36636Skarels 635*36636Skarels if (getuid()) 636*36636Skarels return(KFAILURE); 637*36636Skarels 638*36636Skarels kdata = (AUTH_DAT *) auth_buf; 639*36636Skarels ticket = (KTEXT) tick_buf; 640*36636Skarels strcpy(instance, "*"); 641*36636Skarels 642*36636Skarels if (encrypt) { 643*36636Skarels rc = sizeof(faddr); 644*36636Skarels if (getsockname(0, &faddr, &rc)) 645*36636Skarels return(-1); 646*36636Skarels authopts = KOPT_DO_MUTUAL; 647*36636Skarels rc = krb_recvauth( 648*36636Skarels authopts, 0, 649*36636Skarels ticket, "rcmd", 650*36636Skarels instance, dest, &faddr, 651*36636Skarels kdata, "", schedule, version); 652*36636Skarels des_set_key(kdata->session, schedule); 653*36636Skarels 654*36636Skarels } else { 655*36636Skarels rc = krb_recvauth( 656*36636Skarels authopts, 0, 657*36636Skarels ticket, "rcmd", 658*36636Skarels instance, dest, (struct sockaddr_in *) 0, 659*36636Skarels kdata, "", (bit_64 *) 0, version); 660*36636Skarels } 661*36636Skarels 662*36636Skarels if (rc != KSUCCESS) 663*36636Skarels return(rc); 664*36636Skarels 665*36636Skarels if ((rc = krb_kntoln(kdata, rusername)) != KSUCCESS) 666*36636Skarels return(rc); 667*36636Skarels 668*36636Skarels getstr(lusername, sizeof(lusername), "locuser"); 669*36636Skarels /* get the "cmd" in the rcmd protocol */ 670*36636Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 671*36636Skarels 672*36636Skarels pwd = getpwnam(lusername); 673*36636Skarels if (pwd == NULL) 674*36636Skarels return(-1); 675*36636Skarels 676*36636Skarels /* returns nonzero for no access */ 677*36636Skarels /* return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); */ 678*36636Skarels if (kuserok(kdata,lusername) != 0) 679*36636Skarels return(-1); 680*36636Skarels 681*36636Skarels return(0); 682*36636Skarels 683*36636Skarels } 684*36636Skarels 685*36636Skarels #endif /* KERBEROS */ 686*36636Skarels 687*36636Skarels usage() 688*36636Skarels { 689*36636Skarels #ifdef KERBEROS 690*36636Skarels syslog(LOG_ERR, "usage: rlogind [-k | -v] [-l] [-n]"); 691*36636Skarels #else 692*36636Skarels syslog(LOG_ERR, "usage: rlogind [-l] [-n]"); 693*36636Skarels #endif 694*36636Skarels } 695*36636Skarels 696*36636Skarels /* 69736631Skarels * Check whether host h is in our local domain, 69836631Skarels * as determined by the part of the name following 69936631Skarels * the first '.' in its name and in ours. 70036631Skarels * If either name is unqualified (contains no '.'), 70136631Skarels * assume that the host is local, as it will be 70236631Skarels * interpreted as such. 70336631Skarels */ 70436631Skarels local_domain(h) 70536631Skarels char *h; 70636625Skfall { 70736631Skarels char localhost[MAXHOSTNAMELEN]; 70836631Skarels char *p1, *p2 = index(h, '.'); 70936631Skarels 71036631Skarels (void) gethostname(localhost, sizeof(localhost)); 71136631Skarels p1 = index(localhost, '.'); 71236631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 71336625Skfall return(1); 71436625Skfall return(0); 71536625Skfall } 716