121174Sdist /* 2*39119Skarels * Copyright (c) 1983, 1988, 1989 The Regents of the University of California. 335441Sbostic * All rights reserved. 435441Sbostic * 535441Sbostic * Redistribution and use in source and binary forms are permitted 635441Sbostic * provided that the above copyright notice and this paragraph are 735441Sbostic * duplicated in all such forms and that any documentation, 835441Sbostic * advertising materials, and other materials related to such 935441Sbostic * distribution and use acknowledge that the software was developed 1035441Sbostic * by the University of California, Berkeley. The name of the 1135441Sbostic * University may not be used to endorse or promote products derived 1235441Sbostic * from this software without specific prior written permission. 1335441Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435441Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535441Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621174Sdist */ 1721174Sdist 186446Swnj #ifndef lint 1921174Sdist char copyright[] = 20*39119Skarels "@(#) Copyright (c) 1983, 1988, 1989 The Regents of the University of California.\n\ 2121174Sdist All rights reserved.\n"; 2235441Sbostic #endif /* not lint */ 236446Swnj 2421174Sdist #ifndef lint 25*39119Skarels static char sccsid[] = "@(#)rlogind.c 5.38 (Berkeley) 09/11/89"; 2635441Sbostic #endif /* not lint */ 2721174Sdist 28*39119Skarels #ifdef KERBEROS 29*39119Skarels /* From: 30*39119Skarels * $Source: /mit/kerberos/ucb/mit/rlogind/RCS/rlogind.c,v $ 31*39119Skarels * $Header: rlogind.c,v 5.0 89/06/26 18:31:01 kfall Locked $ 32*39119Skarels */ 33*39119Skarels 34*39119Skarels #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> 49*39119Skarels #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> 60*39119Skarels #include <stdio.h> 61*39119Skarels #include "pathnames.h" 626446Swnj 6336518Skarels #ifndef TIOCPKT_WINDOW 6436518Skarels #define TIOCPKT_WINDOW 0x80 6536518Skarels #endif 6636518Skarels 67*39119Skarels #ifdef KERBEROS 68*39119Skarels #include <krb.h> 69*39119Skarels #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 70*39119Skarels 71*39119Skarels AUTH_DAT *kdata; 72*39119Skarels KTEXT ticket; 73*39119Skarels u_char auth_buf[sizeof(AUTH_DAT)]; 74*39119Skarels u_char tick_buf[sizeof(KTEXT_ST)]; 75*39119Skarels Key_schedule schedule; 76*39119Skarels int encrypt = 0, retval, use_kerberos = 0, vacuous = 0; 77*39119Skarels int do_krb_login(); 78*39119Skarels 79*39119Skarels #define ARGSTR "alnkvx" 80*39119Skarels #else 81*39119Skarels #define ARGSTR "aln" 82*39119Skarels #endif /* KERBEROS */ 83*39119Skarels 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; 9039058Skarels 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 { 103*39119Skarels extern int opterr, optind; 104*39119Skarels 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; 112*39119Skarels while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 11336517Skarels switch (ch) { 11439058Skarels case 'a': 11539058Skarels check_all = 1; 11639058Skarels break; 11736319Sbostic case 'l': 11836319Sbostic _check_rhosts_file = 0; 11936319Sbostic break; 12036517Skarels case 'n': 12136517Skarels keepalive = 0; 12236517Skarels break; 123*39119Skarels #ifdef KERBEROS 124*39119Skarels case 'k': 125*39119Skarels use_kerberos = 1; 126*39119Skarels break; 127*39119Skarels case 'v': 128*39119Skarels vacuous = 1; 129*39119Skarels break; 130*39119Skarels case 'x': 131*39119Skarels encrypt = 1; 132*39119Skarels break; 133*39119Skarels #endif 13436319Sbostic case '?': 13536319Sbostic default: 136*39119Skarels usage(); 13736319Sbostic break; 13836319Sbostic } 13936319Sbostic argc -= optind; 14036319Sbostic argv += optind; 14136319Sbostic 142*39119Skarels #ifdef KERBEROS 143*39119Skarels if (use_kerberos && vacuous) { 144*39119Skarels usage(); 145*39119Skarels fatal("only one of -k and -v allowed"); 146*39119Skarels } 147*39119Skarels #endif 14816369Skarels fromlen = sizeof (from); 14916369Skarels if (getpeername(0, &from, &fromlen) < 0) { 150*39119Skarels 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; 174*39119Skarels register struct hostent *hp; 17539118Skarels char remotehost[2 * MAXHOSTNAMELEN + 1]; 17624724Smckusick struct hostent hostent; 1778380Ssam char c; 1786446Swnj 1796446Swnj alarm(60); 1806446Swnj read(f, &c, 1); 181*39119Skarels 182*39119Skarels if(c != 0) 18336715Skfall exit(1); 184*39119Skarels #ifdef KERBEROS 185*39119Skarels if (vacuous) 186*39119Skarels fatal(f, "Remote host requires Kerberos authentication"); 187*39119Skarels #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*39119Skarels } 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 220*39119Skarels #ifdef KERBEROS 221*39119Skarels if (use_kerberos) { 222*39119Skarels retval = do_krb_login(hp->h_name, fromp, encrypt); 223*39119Skarels write(f, &c, 1); 224*39119Skarels if (retval == 0 && hostok) 225*39119Skarels authenticated++; 226*39119Skarels else if (retval > 0) 227*39119Skarels fatal(f, krb_err_txt[retval]); 228*39119Skarels else if(!hostok) 229*39119Skarels fatal(f, "krlogind: Host address mismatch."); 230*39119Skarels } else 231*39119Skarels #endif 232*39119Skarels { 233*39119Skarels if (fromp->sin_family != AF_INET || 234*39119Skarels fromp->sin_port >= IPPORT_RESERVED || 235*39119Skarels fromp->sin_port < IPPORT_RESERVED/2) { 236*39119Skarels syslog(LOG_NOTICE, "Connection from %s on illegal port", 237*39119Skarels inet_ntoa(fromp->sin_addr)); 238*39119Skarels fatal(f, "Permission denied"); 239*39119Skarels } 24036702Skarels #ifdef IP_OPTIONS 241*39119Skarels { 242*39119Skarels u_char optbuf[BUFSIZ/3], *cp; 243*39119Skarels char lbuf[BUFSIZ], *lp; 244*39119Skarels int optsize = sizeof(optbuf), ipproto; 245*39119Skarels struct protoent *ip; 24636702Skarels 247*39119Skarels if ((ip = getprotobyname("ip")) != NULL) 248*39119Skarels ipproto = ip->p_proto; 249*39119Skarels else 250*39119Skarels ipproto = IPPROTO_IP; 251*39119Skarels if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 252*39119Skarels &optsize) == 0 && optsize != 0) { 253*39119Skarels lp = lbuf; 254*39119Skarels for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 255*39119Skarels sprintf(lp, " %2.2x", *cp); 256*39119Skarels syslog(LOG_NOTICE, 257*39119Skarels "Connection received using IP options (ignored):%s", 258*39119Skarels lbuf); 259*39119Skarels if (setsockopt(0, ipproto, IP_OPTIONS, 260*39119Skarels (char *)NULL, &optsize) != 0) { 261*39119Skarels syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 262*39119Skarels exit(1); 263*39119Skarels } 264*39119Skarels } 265*39119Skarels } 26636702Skarels #endif 267*39119Skarels write(f, "", 1); 268*39119Skarels 269*39119Skarels if (do_rlogin(hp->h_name) == 0) { 270*39119Skarels if (hostok) 271*39119Skarels authenticated++; 272*39119Skarels else 273*39119Skarels write(f, "rlogind: Host address mismatch.\r\n", 274*39119Skarels sizeof("rlogind: Host address mismatch.\r\n") - 1); 275*39119Skarels } 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); 310*39119Skarels 3119242Ssam pid = fork(); 3129242Ssam if (pid < 0) 31334424Sbostic fatalperror(f, ""); 31418357Ssam if (pid == 0) { 31536711Skfall if (setsid() < 0) 31636711Skfall fatalperror(f, "setsid"); 31736711Skfall if (ioctl(t, TIOCSCTTY, 0) < 0) 31836711Skfall fatalperror(f, "ioctl(sctty)"); 31918357Ssam close(f), close(p); 32018357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 32116227Skarels close(t); 322*39119Skarels 32336631Skarels if (authenticated) 324*39119Skarels execl(_PATH_LOGIN, "login", "-p", 325*39119Skarels "-h", hp->h_name, "-f", lusername, 0); 32636525Skfall else 327*39119Skarels execl(_PATH_LOGIN, "login", "-p", 328*39119Skarels "-h", hp->h_name, lusername, 0); 329*39119Skarels fatalperror(2, _PATH_LOGIN); 33018357Ssam /*NOTREACHED*/ 33118357Ssam } 33218357Ssam close(t); 33336453Skfall 334*39119Skarels #ifdef KERBEROS 335*39119Skarels /* 336*39119Skarels * If encrypted, don't turn on NBIO or the des read/write 337*39119Skarels * routines will croak. 338*39119Skarels */ 339*39119Skarels 340*39119Skarels if (encrypt) 341*39119Skarels (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 342*39119Skarels else 343*39119Skarels #endif 344*39119Skarels ioctl(f, FIONBIO, &on); 34518357Ssam ioctl(p, FIONBIO, &on); 34618357Ssam ioctl(p, TIOCPKT, &on); 34718357Ssam signal(SIGTSTP, SIG_IGN); 34818357Ssam signal(SIGCHLD, cleanup); 34924724Smckusick setpgrp(0, 0); 35018357Ssam protocol(f, p); 35130600Smckusick signal(SIGCHLD, SIG_IGN); 35218357Ssam cleanup(); 35318357Ssam } 3549242Ssam 35518357Ssam char magic[2] = { 0377, 0377 }; 35625423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 35718357Ssam 35818357Ssam /* 35918357Ssam * Handle a "control" request (signaled by magic being present) 36018357Ssam * in the data stream. For now, we are only willing to handle 36118357Ssam * window size changes. 36218357Ssam */ 36318357Ssam control(pty, cp, n) 36418357Ssam int pty; 36518357Ssam char *cp; 36618357Ssam int n; 36718357Ssam { 36828705Smckusick struct winsize w; 36918357Ssam 37028705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 37118357Ssam return (0); 37225423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 37328705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 37428705Smckusick w.ws_row = ntohs(w.ws_row); 37528705Smckusick w.ws_col = ntohs(w.ws_col); 37628705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 37728705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 37828705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 37928705Smckusick return (4+sizeof (w)); 38018357Ssam } 38118357Ssam 38218357Ssam /* 38318357Ssam * rlogin "protocol" machine. 38418357Ssam */ 38518357Ssam protocol(f, p) 38618357Ssam int f, p; 38718357Ssam { 38818357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 38918357Ssam register pcc = 0, fcc = 0; 39036517Skarels int cc, nfd, pmask, fmask; 39125740Skarels char cntl; 39218357Ssam 39318482Ssam /* 39418484Ssam * Must ignore SIGTTOU, otherwise we'll stop 39518484Ssam * when we try and set slave pty's window shape 39625423Skarels * (our controlling tty is the master pty). 39718482Ssam */ 39818484Ssam (void) signal(SIGTTOU, SIG_IGN); 39925423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 40036517Skarels if (f > p) 40136517Skarels nfd = f + 1; 40236517Skarels else 40336517Skarels nfd = p + 1; 40436517Skarels fmask = 1 << f; 40536517Skarels pmask = 1 << p; 40618357Ssam for (;;) { 40725740Skarels int ibits, obits, ebits; 40818357Ssam 40925740Skarels ibits = 0; 41025740Skarels obits = 0; 41118357Ssam if (fcc) 41236517Skarels obits |= pmask; 41318357Ssam else 41436517Skarels ibits |= fmask; 41518357Ssam if (pcc >= 0) 41618357Ssam if (pcc) 41736517Skarels obits |= fmask; 4189242Ssam else 41936517Skarels ibits |= pmask; 42036517Skarels ebits = pmask; 42136517Skarels if (select(nfd, &ibits, obits ? &obits : (int *)NULL, 42236517Skarels &ebits, 0) < 0) { 42318357Ssam if (errno == EINTR) 4246446Swnj continue; 42534424Sbostic fatalperror(f, "select"); 42618357Ssam } 42725740Skarels if (ibits == 0 && obits == 0 && ebits == 0) { 42818357Ssam /* shouldn't happen... */ 42918357Ssam sleep(5); 43018357Ssam continue; 43118357Ssam } 43225740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 43336517Skarels if (ebits & pmask) { 43425740Skarels cc = read(p, &cntl, 1); 43525740Skarels if (cc == 1 && pkcontrol(cntl)) { 43625740Skarels cntl |= oobdata[0]; 43725740Skarels send(f, &cntl, 1, MSG_OOB); 43825740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 43925740Skarels pcc = 0; 44036517Skarels ibits &= ~pmask; 44125740Skarels } 44225740Skarels } 44325740Skarels } 44436517Skarels if (ibits & fmask) { 445*39119Skarels #ifdef KERBEROS 446*39119Skarels if (encrypt) 447*39119Skarels fcc = des_read(f, fibuf, sizeof(fibuf)); 448*39119Skarels else 449*39119Skarels #endif 450*39119Skarels fcc = read(f, fibuf, sizeof(fibuf)); 45118357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 45218357Ssam fcc = 0; 45318357Ssam else { 45418357Ssam register char *cp; 45518357Ssam int left, n; 45618357Ssam 45718357Ssam if (fcc <= 0) 45816227Skarels break; 45918357Ssam fbp = fibuf; 46024723Smckusick 46118357Ssam top: 46225423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 46318357Ssam if (cp[0] == magic[0] && 46418357Ssam cp[1] == magic[1]) { 46518357Ssam left = fcc - (cp-fibuf); 46618357Ssam n = control(p, cp, left); 46718357Ssam if (n) { 46818357Ssam left -= n; 46918357Ssam if (left > 0) 47025423Skarels bcopy(cp+n, cp, left); 47118357Ssam fcc -= n; 47218357Ssam goto top; /* n^2 */ 47325423Skarels } 47425423Skarels } 47536517Skarels obits |= pmask; /* try write */ 47625423Skarels } 47725423Skarels } 47824723Smckusick 47936517Skarels if ((obits & pmask) && fcc > 0) { 48025423Skarels cc = write(p, fbp, fcc); 48124723Smckusick if (cc > 0) { 48224723Smckusick fcc -= cc; 48324723Smckusick fbp += cc; 4846446Swnj } 48518357Ssam } 48624723Smckusick 48736517Skarels if (ibits & pmask) { 48818357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 48918357Ssam pbp = pibuf; 49018357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 49118357Ssam pcc = 0; 49218357Ssam else if (pcc <= 0) 49318357Ssam break; 49436517Skarels else if (pibuf[0] == 0) { 49518357Ssam pbp++, pcc--; 496*39119Skarels #ifdef KERBEROS 497*39119Skarels if (!encrypt) 498*39119Skarels #endif 499*39119Skarels obits |= fmask; /* try a write */ 50036517Skarels } else { 50118357Ssam if (pkcontrol(pibuf[0])) { 50225423Skarels pibuf[0] |= oobdata[0]; 50318357Ssam send(f, &pibuf[0], 1, MSG_OOB); 50416227Skarels } 50518357Ssam pcc = 0; 5066446Swnj } 50718357Ssam } 50836517Skarels if ((obits & fmask) && pcc > 0) { 509*39119Skarels #ifdef KERBEROS 510*39119Skarels if (encrypt) 511*39119Skarels cc = des_write(f, pbp, pcc); 512*39119Skarels else 513*39119Skarels #endif 514*39119Skarels cc = write(f, pbp, pcc); 51525423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 51625423Skarels /* also shouldn't happen */ 51725423Skarels sleep(5); 51825423Skarels continue; 51925423Skarels } 52018357Ssam if (cc > 0) { 52118357Ssam pcc -= cc; 52218357Ssam pbp += cc; 52318357Ssam } 5246446Swnj } 5256446Swnj } 5266446Swnj } 5276446Swnj 5286446Swnj cleanup() 5296446Swnj { 53035440Sbostic char *p; 53135440Sbostic 53235440Sbostic p = line + sizeof("/dev/") - 1; 53335440Sbostic if (logout(p)) 53435440Sbostic logwtmp(p, "", ""); 53535440Sbostic (void)chmod(line, 0666); 53635440Sbostic (void)chown(line, 0, 0); 53735440Sbostic *p = 'p'; 53835440Sbostic (void)chmod(line, 0666); 53935440Sbostic (void)chown(line, 0, 0); 54010192Ssam shutdown(netf, 2); 5416446Swnj exit(1); 5426446Swnj } 5436446Swnj 5449242Ssam fatal(f, msg) 5459242Ssam int f; 5469242Ssam char *msg; 5479242Ssam { 5489242Ssam char buf[BUFSIZ]; 5499242Ssam 5509242Ssam buf[0] = '\01'; /* error indicator */ 55113554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 5529242Ssam (void) write(f, buf, strlen(buf)); 5539242Ssam exit(1); 5549242Ssam } 5559242Ssam 55634424Sbostic fatalperror(f, msg) 5579242Ssam int f; 5589242Ssam char *msg; 5599242Ssam { 5609242Ssam char buf[BUFSIZ]; 56116227Skarels extern int sys_nerr; 5629242Ssam extern char *sys_errlist[]; 5639242Ssam 56418357Ssam if ((unsigned)errno < sys_nerr) 56516227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 56616227Skarels else 56716227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 5689242Ssam fatal(f, buf); 5699242Ssam } 57036453Skfall 57136453Skfall do_rlogin(host) 57236518Skarels char *host; 57336453Skfall { 57436453Skfall 57536518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 57636518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 57736518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 57836518Skarels 57936518Skarels if (getuid()) 58036453Skfall return(-1); 58136453Skfall pwd = getpwnam(lusername); 58236518Skarels if (pwd == NULL) 58336453Skfall return(-1); 58436453Skfall return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 58536453Skfall } 58636453Skfall 58736453Skfall 58836518Skarels getstr(buf, cnt, errmsg) 58936518Skarels char *buf; 59036518Skarels int cnt; 59136518Skarels char *errmsg; 59236453Skfall { 59336518Skarels char c; 59436518Skarels 59536453Skfall do { 59636518Skarels if (read(0, &c, 1) != 1) 59736453Skfall exit(1); 59836518Skarels if (--cnt < 0) 59936518Skarels fatal(1, errmsg); 60036453Skfall *buf++ = c; 60136518Skarels } while (c != 0); 60236453Skfall } 60336453Skfall 60436518Skarels extern char **environ; 60536453Skfall 60636519Skarels setup_term(fd) 60736519Skarels int fd; 60836519Skarels { 609*39119Skarels register char *cp = index(term+ENVSIZE, '/'); 61036519Skarels char *speed; 61139118Skarels struct termios tt; 61236519Skarels 613*39119Skarels #ifndef notyet 61436711Skfall tcgetattr(fd, &tt); 61536519Skarels if (cp) { 61636519Skarels *cp++ = '\0'; 61736519Skarels speed = cp; 61836519Skarels cp = index(speed, '/'); 61936519Skarels if (cp) 62036519Skarels *cp++ = '\0'; 62136711Skfall cfsetspeed(&tt, atoi(speed)); 62236519Skarels } 62338710Skfall 62439118Skarels tt.c_iflag = TTYDEF_IFLAG; 62539118Skarels tt.c_oflag = TTYDEF_OFLAG; 62639118Skarels tt.c_lflag = TTYDEF_LFLAG; 62739118Skarels tcsetattr(fd, TCSADFLUSH, &tt); 62839118Skarels #else 62939118Skarels if (cp) { 63039118Skarels *cp++ = '\0'; 63139118Skarels speed = cp; 63239118Skarels cp = index(speed, '/'); 63339118Skarels if (cp) 63439118Skarels *cp++ = '\0'; 635*39119Skarels tcgetattr(fd, &tt); 636*39119Skarels cfsetspeed(&tt, atoi(speed)); 637*39119Skarels tcsetattr(fd, TCSADFLUSH, &tt); 63838710Skfall } 63938710Skfall #endif 64036519Skarels 64136519Skarels env[0] = term; 64236519Skarels env[1] = 0; 64336519Skarels environ = env; 64436519Skarels } 64536609Skfall 646*39119Skarels #ifdef KERBEROS 647*39119Skarels #define VERSION_SIZE 9 648*39119Skarels 64936609Skfall /* 650*39119Skarels * Do the remote kerberos login to the named host with the 651*39119Skarels * given inet address 652*39119Skarels * 653*39119Skarels * Return 0 on valid authorization 654*39119Skarels * Return -1 on valid authentication, no authorization 655*39119Skarels * Return >0 for error conditions 656*39119Skarels */ 657*39119Skarels do_krb_login(host, dest, encrypt) 658*39119Skarels char *host; 659*39119Skarels struct sockaddr_in *dest; 660*39119Skarels int encrypt; 661*39119Skarels { 662*39119Skarels int rc; 663*39119Skarels char instance[INST_SZ], version[VERSION_SIZE]; 664*39119Skarels long authopts = 0L; /* !mutual */ 665*39119Skarels struct sockaddr_in faddr; 666*39119Skarels 667*39119Skarels if (getuid()) 668*39119Skarels return(KFAILURE); 669*39119Skarels 670*39119Skarels kdata = (AUTH_DAT *) auth_buf; 671*39119Skarels ticket = (KTEXT) tick_buf; 672*39119Skarels strcpy(instance, "*"); 673*39119Skarels 674*39119Skarels if (encrypt) { 675*39119Skarels rc = sizeof(faddr); 676*39119Skarels if (getsockname(0, &faddr, &rc)) 677*39119Skarels return(-1); 678*39119Skarels authopts = KOPT_DO_MUTUAL; 679*39119Skarels rc = krb_recvauth( 680*39119Skarels authopts, 0, 681*39119Skarels ticket, "rcmd", 682*39119Skarels instance, dest, &faddr, 683*39119Skarels kdata, "", schedule, version); 684*39119Skarels des_set_key(kdata->session, schedule); 685*39119Skarels 686*39119Skarels } else { 687*39119Skarels rc = krb_recvauth( 688*39119Skarels authopts, 0, 689*39119Skarels ticket, "rcmd", 690*39119Skarels instance, dest, (struct sockaddr_in *) 0, 691*39119Skarels kdata, "", (bit_64 *) 0, version); 692*39119Skarels } 693*39119Skarels 694*39119Skarels if (rc != KSUCCESS) 695*39119Skarels return(rc); 696*39119Skarels 697*39119Skarels getstr(lusername, sizeof(lusername), "locuser"); 698*39119Skarels /* get the "cmd" in the rcmd protocol */ 699*39119Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 700*39119Skarels 701*39119Skarels pwd = getpwnam(lusername); 702*39119Skarels if (pwd == NULL) 703*39119Skarels return(-1); 704*39119Skarels 705*39119Skarels /* returns nonzero for no access */ 706*39119Skarels /* return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); */ 707*39119Skarels if (kuserok(kdata,lusername) != 0) 708*39119Skarels return(-1); 709*39119Skarels 710*39119Skarels return(0); 711*39119Skarels 712*39119Skarels } 713*39119Skarels 714*39119Skarels #endif /* KERBEROS */ 715*39119Skarels 716*39119Skarels usage() 717*39119Skarels { 718*39119Skarels #ifdef KERBEROS 719*39119Skarels syslog(LOG_ERR, "usage: rlogind [-k | -v] [-a] [-l] [-n]"); 720*39119Skarels #else 721*39119Skarels syslog(LOG_ERR, "usage: rlogind [-a] [-l] [-n]"); 722*39119Skarels #endif 723*39119Skarels } 724*39119Skarels 725*39119Skarels /* 72636631Skarels * Check whether host h is in our local domain, 72739058Skarels * defined as sharing the last two components of the domain part, 72839058Skarels * or the entire domain part if the local domain has only one component. 72936631Skarels * If either name is unqualified (contains no '.'), 73036631Skarels * assume that the host is local, as it will be 73136631Skarels * interpreted as such. 73236631Skarels */ 73336631Skarels local_domain(h) 73436631Skarels char *h; 73536625Skfall { 73636631Skarels char localhost[MAXHOSTNAMELEN]; 73739058Skarels char *p1, *p2, *topdomain(); 73836631Skarels 73939058Skarels localhost[0] = 0; 74036631Skarels (void) gethostname(localhost, sizeof(localhost)); 74139058Skarels p1 = topdomain(localhost); 74239058Skarels p2 = topdomain(h); 74336631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 74436625Skfall return(1); 74536625Skfall return(0); 74636625Skfall } 74739058Skarels 74839058Skarels char * 74939058Skarels topdomain(h) 75039058Skarels char *h; 75139058Skarels { 75239058Skarels register char *p; 75339058Skarels char *maybe = NULL; 75439058Skarels int dots = 0; 75539058Skarels 75639058Skarels for (p = h + strlen(h); p >= h; p--) { 75739058Skarels if (*p == '.') { 75839058Skarels if (++dots == 2) 75939058Skarels return (p); 76039058Skarels maybe = p; 76139058Skarels } 76239058Skarels } 76339058Skarels return (maybe); 76439058Skarels } 765