rlogind.c revision 29916
11592Srgrimes/*- 21592Srgrimes * Copyright (c) 1983, 1988, 1989, 1993 31592Srgrimes * The Regents of the University of California. All rights reserved. 41592Srgrimes * 51592Srgrimes * Redistribution and use in source and binary forms, with or without 61592Srgrimes * modification, are permitted provided that the following conditions 71592Srgrimes * are met: 81592Srgrimes * 1. Redistributions of source code must retain the above copyright 91592Srgrimes * notice, this list of conditions and the following disclaimer. 101592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111592Srgrimes * notice, this list of conditions and the following disclaimer in the 121592Srgrimes * documentation and/or other materials provided with the distribution. 131592Srgrimes * 3. All advertising materials mentioning features or use of this software 141592Srgrimes * must display the following acknowledgement: 151592Srgrimes * This product includes software developed by the University of 161592Srgrimes * California, Berkeley and its contributors. 171592Srgrimes * 4. Neither the name of the University nor the names of its contributors 181592Srgrimes * may be used to endorse or promote products derived from this software 191592Srgrimes * without specific prior written permission. 201592Srgrimes * 211592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311592Srgrimes * SUCH DAMAGE. 3218471Swosch * 3329916Smarkm * $Id: rlogind.c,v 1.17 1997/03/28 15:48:16 imp Exp $ 341592Srgrimes */ 351592Srgrimes 361592Srgrimes#ifndef lint 3729916Smarkmstatic const char copyright[] = 381592Srgrimes"@(#) Copyright (c) 1983, 1988, 1989, 1993\n\ 391592Srgrimes The Regents of the University of California. All rights reserved.\n"; 401592Srgrimes#endif /* not lint */ 411592Srgrimes 421592Srgrimes#ifndef lint 4329916Smarkmstatic const char sccsid[] = "@(#)rlogind.c 8.1 (Berkeley) 6/4/93"; 441592Srgrimes#endif /* not lint */ 451592Srgrimes 461592Srgrimes/* 471592Srgrimes * remote login server: 481592Srgrimes * \0 491592Srgrimes * remuser\0 501592Srgrimes * locuser\0 511592Srgrimes * terminal_type/speed\0 521592Srgrimes * data 531592Srgrimes */ 541592Srgrimes 551592Srgrimes#define FD_SETSIZE 16 /* don't need many bits for select */ 5629916Smarkm#include <sys/types.h> 571592Srgrimes#include <sys/param.h> 581592Srgrimes#include <sys/stat.h> 591592Srgrimes#include <sys/ioctl.h> 601592Srgrimes#include <signal.h> 611592Srgrimes#include <termios.h> 621592Srgrimes 631592Srgrimes#include <sys/socket.h> 641592Srgrimes#include <netinet/in.h> 651592Srgrimes#include <netinet/in_systm.h> 661592Srgrimes#include <netinet/ip.h> 6711486Sdg#include <netinet/tcp.h> 681592Srgrimes#include <arpa/inet.h> 691592Srgrimes#include <netdb.h> 701592Srgrimes 711592Srgrimes#include <pwd.h> 721592Srgrimes#include <syslog.h> 731592Srgrimes#include <errno.h> 741592Srgrimes#include <stdio.h> 751592Srgrimes#include <unistd.h> 761592Srgrimes#include <stdlib.h> 771592Srgrimes#include <string.h> 7829916Smarkm#include <libutil.h> 791592Srgrimes#include "pathnames.h" 801592Srgrimes 811592Srgrimes#ifndef TIOCPKT_WINDOW 821592Srgrimes#define TIOCPKT_WINDOW 0x80 831592Srgrimes#endif 841592Srgrimes 851592Srgrimes#ifdef KERBEROS 8614024Smarkm#include <des.h> 8729916Smarkm#include <krb.h> 881592Srgrimes#define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 891592Srgrimes 901592SrgrimesAUTH_DAT *kdata; 911592SrgrimesKTEXT ticket; 921592Srgrimesu_char auth_buf[sizeof(AUTH_DAT)]; 931592Srgrimesu_char tick_buf[sizeof(KTEXT_ST)]; 941592SrgrimesKey_schedule schedule; 951592Srgrimesint doencrypt, retval, use_kerberos, vacuous; 961592Srgrimes 9711486Sdg#define ARGSTR "Dalnkvx" 981592Srgrimes#else 9911486Sdg#define ARGSTR "Daln" 1001592Srgrimes#endif /* KERBEROS */ 1011592Srgrimes 1021592Srgrimeschar *env[2]; 1031592Srgrimes#define NMAX 30 1041592Srgrimeschar lusername[NMAX+1], rusername[NMAX+1]; 1051592Srgrimesstatic char term[64] = "TERM="; 1061592Srgrimes#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 1071592Srgrimesint keepalive = 1; 1081592Srgrimesint check_all = 0; 10911486Sdgint no_delay; 1101592Srgrimes 1111592Srgrimesstruct passwd *pwd; 1121592Srgrimes 1131592Srgrimesvoid doit __P((int, struct sockaddr_in *)); 1141592Srgrimesint control __P((int, char *, int)); 1151592Srgrimesvoid protocol __P((int, int)); 1161592Srgrimesvoid cleanup __P((int)); 1171592Srgrimesvoid fatal __P((int, char *, int)); 1181592Srgrimesint do_rlogin __P((struct sockaddr_in *)); 1191592Srgrimesvoid getstr __P((char *, int, char *)); 1201592Srgrimesvoid setup_term __P((int)); 1211592Srgrimesint do_krb_login __P((struct sockaddr_in *)); 1221592Srgrimesvoid usage __P((void)); 1231592Srgrimesint local_domain __P((char *)); 1241592Srgrimeschar *topdomain __P((char *)); 1251592Srgrimes 1261592Srgrimesint 1271592Srgrimesmain(argc, argv) 1281592Srgrimes int argc; 1291592Srgrimes char *argv[]; 1301592Srgrimes{ 1311592Srgrimes extern int __check_rhosts_file; 1321592Srgrimes struct sockaddr_in from; 1331592Srgrimes int ch, fromlen, on; 1341592Srgrimes 1351592Srgrimes openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 1361592Srgrimes 1371592Srgrimes opterr = 0; 13824349Simp while ((ch = getopt(argc, argv, ARGSTR)) != -1) 1391592Srgrimes switch (ch) { 14011486Sdg case 'D': 14111486Sdg no_delay = 1; 14211486Sdg break; 1431592Srgrimes case 'a': 1441592Srgrimes check_all = 1; 1451592Srgrimes break; 1461592Srgrimes case 'l': 1471592Srgrimes __check_rhosts_file = 0; 1481592Srgrimes break; 1491592Srgrimes case 'n': 1501592Srgrimes keepalive = 0; 1511592Srgrimes break; 1521592Srgrimes#ifdef KERBEROS 1531592Srgrimes case 'k': 1541592Srgrimes use_kerberos = 1; 1551592Srgrimes break; 1561592Srgrimes case 'v': 1571592Srgrimes vacuous = 1; 1581592Srgrimes break; 1591592Srgrimes#ifdef CRYPT 1601592Srgrimes case 'x': 1611592Srgrimes doencrypt = 1; 1621592Srgrimes break; 1631592Srgrimes#endif 1641592Srgrimes#endif 1651592Srgrimes case '?': 1661592Srgrimes default: 1671592Srgrimes usage(); 1681592Srgrimes break; 1691592Srgrimes } 1701592Srgrimes argc -= optind; 1711592Srgrimes argv += optind; 1721592Srgrimes 1731592Srgrimes#ifdef KERBEROS 1741592Srgrimes if (use_kerberos && vacuous) { 1751592Srgrimes usage(); 1761592Srgrimes fatal(STDERR_FILENO, "only one of -k and -v allowed", 0); 1771592Srgrimes } 1781592Srgrimes#endif 1791592Srgrimes fromlen = sizeof (from); 1801592Srgrimes if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 1811592Srgrimes syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 1821592Srgrimes fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 1831592Srgrimes } 1841592Srgrimes on = 1; 1851592Srgrimes if (keepalive && 1861592Srgrimes setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 1871592Srgrimes syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 18811486Sdg if (no_delay && 18911486Sdg setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) 19011486Sdg syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m"); 1911592Srgrimes on = IPTOS_LOWDELAY; 1921592Srgrimes if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 1931592Srgrimes syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 19411486Sdg 1951592Srgrimes doit(0, &from); 19629916Smarkm return 0; 1971592Srgrimes} 1981592Srgrimes 1991592Srgrimesint child; 2001592Srgrimesint netf; 2011592Srgrimeschar line[MAXPATHLEN]; 2021592Srgrimesint confirmed; 2031592Srgrimes 2041592Srgrimesstruct winsize win = { 0, 0, 0, 0 }; 2051592Srgrimes 2061592Srgrimes 2071592Srgrimesvoid 2081592Srgrimesdoit(f, fromp) 2091592Srgrimes int f; 2101592Srgrimes struct sockaddr_in *fromp; 2111592Srgrimes{ 2121592Srgrimes int master, pid, on = 1; 2131592Srgrimes int authenticated = 0; 2141592Srgrimes register struct hostent *hp; 2151592Srgrimes char hostname[2 * MAXHOSTNAMELEN + 1]; 2161592Srgrimes char c; 2171592Srgrimes 2181592Srgrimes alarm(60); 2191592Srgrimes read(f, &c, 1); 2201592Srgrimes 2211592Srgrimes if (c != 0) 2221592Srgrimes exit(1); 2231592Srgrimes#ifdef KERBEROS 2241592Srgrimes if (vacuous) 2251592Srgrimes fatal(f, "Remote host requires Kerberos authentication", 0); 2261592Srgrimes#endif 2271592Srgrimes 2281592Srgrimes alarm(0); 2291592Srgrimes fromp->sin_port = ntohs((u_short)fromp->sin_port); 2301592Srgrimes hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr), 2311592Srgrimes fromp->sin_family); 23224191Simp if (hp) { 23324191Simp (void)strncpy(hostname, hp->h_name, sizeof(hostname)); 23424191Simp } else { 23524191Simp (void)strncpy(hostname, inet_ntoa(fromp->sin_addr), sizeof(hostname)); 23624191Simp } 23724191Simp hostname[sizeof(hostname) - 1] = '\0'; 2381592Srgrimes 2391592Srgrimes#ifdef KERBEROS 2401592Srgrimes if (use_kerberos) { 2411592Srgrimes retval = do_krb_login(fromp); 2421592Srgrimes if (retval == 0) 2431592Srgrimes authenticated++; 2441592Srgrimes else if (retval > 0) 2451592Srgrimes fatal(f, krb_err_txt[retval], 0); 2461592Srgrimes write(f, &c, 1); 2471592Srgrimes confirmed = 1; /* we sent the null! */ 2481592Srgrimes } else 2491592Srgrimes#endif 2501592Srgrimes { 2511592Srgrimes if (fromp->sin_family != AF_INET || 2521592Srgrimes fromp->sin_port >= IPPORT_RESERVED || 2531592Srgrimes fromp->sin_port < IPPORT_RESERVED/2) { 2541592Srgrimes syslog(LOG_NOTICE, "Connection from %s on illegal port", 2551592Srgrimes inet_ntoa(fromp->sin_addr)); 2561592Srgrimes fatal(f, "Permission denied", 0); 2571592Srgrimes } 2581592Srgrimes#ifdef IP_OPTIONS 2591592Srgrimes { 26022455Simp u_char optbuf[BUFSIZ/3]; 26122455Simp int optsize = sizeof(optbuf), ipproto, i; 2621592Srgrimes struct protoent *ip; 2631592Srgrimes 2641592Srgrimes if ((ip = getprotobyname("ip")) != NULL) 2651592Srgrimes ipproto = ip->p_proto; 2661592Srgrimes else 2671592Srgrimes ipproto = IPPROTO_IP; 2681592Srgrimes if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 2691592Srgrimes &optsize) == 0 && optsize != 0) { 27022455Simp for (i = 0; i < optsize; ) { 27122455Simp u_char c = optbuf[i]; 27222455Simp if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 27322455Simp syslog(LOG_NOTICE, 27422455Simp "Connection refused from %s with IP option %s", 27522455Simp inet_ntoa(fromp->sin_addr), 27622455Simp c == IPOPT_LSRR ? "LSRR" : "SSRR"); 27722455Simp exit(1); 27822455Simp } 27922455Simp if (c == IPOPT_EOL) 28022455Simp break; 28122455Simp i += (c == IPOPT_NOP) ? 1 : optbuf[i+1]; 2821592Srgrimes } 2831592Srgrimes } 2841592Srgrimes } 2851592Srgrimes#endif 2861592Srgrimes if (do_rlogin(fromp) == 0) 2871592Srgrimes authenticated++; 2881592Srgrimes } 2891592Srgrimes if (confirmed == 0) { 2901592Srgrimes write(f, "", 1); 2911592Srgrimes confirmed = 1; /* we sent the null! */ 2921592Srgrimes } 2931592Srgrimes#ifdef KERBEROS 2941592Srgrimes#ifdef CRYPT 2951592Srgrimes if (doencrypt) 29629916Smarkm (void) des_enc_write(f, 29729916Smarkm SECURE_MESSAGE, 29829916Smarkm strlen(SECURE_MESSAGE), 29929916Smarkm schedule, &kdata->session); 3001592Srgrimes#endif 3011592Srgrimes#endif 3021592Srgrimes netf = f; 3031592Srgrimes 3041592Srgrimes pid = forkpty(&master, line, NULL, &win); 3051592Srgrimes if (pid < 0) { 3061592Srgrimes if (errno == ENOENT) 3071592Srgrimes fatal(f, "Out of ptys", 0); 3081592Srgrimes else 3091592Srgrimes fatal(f, "Forkpty", 1); 3101592Srgrimes } 3111592Srgrimes if (pid == 0) { 3121592Srgrimes if (f > 2) /* f should always be 0, but... */ 3131592Srgrimes (void) close(f); 3141592Srgrimes setup_term(0); 31512575Snate if (*lusername=='-') { 3162076Sguido syslog(LOG_ERR, "tried to pass user \"%s\" to login", 3172076Sguido lusername); 3182076Sguido fatal(STDERR_FILENO, "invalid user", 0); 3192076Sguido } 3201592Srgrimes if (authenticated) { 3211592Srgrimes#ifdef KERBEROS 3221592Srgrimes if (use_kerberos && (pwd->pw_uid == 0)) 3231592Srgrimes syslog(LOG_INFO|LOG_AUTH, 3241592Srgrimes "ROOT Kerberos login from %s.%s@%s on %s\n", 3251592Srgrimes kdata->pname, kdata->pinst, kdata->prealm, 3261592Srgrimes hostname); 3271592Srgrimes#endif 3281592Srgrimes 3291592Srgrimes execl(_PATH_LOGIN, "login", "-p", 3301592Srgrimes "-h", hostname, "-f", lusername, (char *)NULL); 3311592Srgrimes } else 3321592Srgrimes execl(_PATH_LOGIN, "login", "-p", 3331592Srgrimes "-h", hostname, lusername, (char *)NULL); 3341592Srgrimes fatal(STDERR_FILENO, _PATH_LOGIN, 1); 3351592Srgrimes /*NOTREACHED*/ 3361592Srgrimes } 3371592Srgrimes#ifdef CRYPT 3381592Srgrimes#ifdef KERBEROS 3391592Srgrimes /* 3401592Srgrimes * If encrypted, don't turn on NBIO or the des read/write 3411592Srgrimes * routines will croak. 3421592Srgrimes */ 3431592Srgrimes 3441592Srgrimes if (!doencrypt) 3451592Srgrimes#endif 3461592Srgrimes#endif 3471592Srgrimes ioctl(f, FIONBIO, &on); 3481592Srgrimes ioctl(master, FIONBIO, &on); 3491592Srgrimes ioctl(master, TIOCPKT, &on); 3501592Srgrimes signal(SIGCHLD, cleanup); 3511592Srgrimes protocol(f, master); 3521592Srgrimes signal(SIGCHLD, SIG_IGN); 3531592Srgrimes cleanup(0); 3541592Srgrimes} 3551592Srgrimes 3561592Srgrimeschar magic[2] = { 0377, 0377 }; 3571592Srgrimeschar oobdata[] = {TIOCPKT_WINDOW}; 3581592Srgrimes 3591592Srgrimes/* 3601592Srgrimes * Handle a "control" request (signaled by magic being present) 3611592Srgrimes * in the data stream. For now, we are only willing to handle 3621592Srgrimes * window size changes. 3631592Srgrimes */ 3641592Srgrimesint 3651592Srgrimescontrol(pty, cp, n) 3661592Srgrimes int pty; 3671592Srgrimes char *cp; 3681592Srgrimes int n; 3691592Srgrimes{ 3701592Srgrimes struct winsize w; 3711592Srgrimes 3721592Srgrimes if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 3731592Srgrimes return (0); 3741592Srgrimes oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 3751592Srgrimes bcopy(cp+4, (char *)&w, sizeof(w)); 3761592Srgrimes w.ws_row = ntohs(w.ws_row); 3771592Srgrimes w.ws_col = ntohs(w.ws_col); 3781592Srgrimes w.ws_xpixel = ntohs(w.ws_xpixel); 3791592Srgrimes w.ws_ypixel = ntohs(w.ws_ypixel); 3801592Srgrimes (void)ioctl(pty, TIOCSWINSZ, &w); 3811592Srgrimes return (4+sizeof (w)); 3821592Srgrimes} 3831592Srgrimes 3841592Srgrimes/* 3851592Srgrimes * rlogin "protocol" machine. 3861592Srgrimes */ 3871592Srgrimesvoid 3881592Srgrimesprotocol(f, p) 3891592Srgrimes register int f, p; 3901592Srgrimes{ 3911592Srgrimes char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 3921592Srgrimes register pcc = 0, fcc = 0; 3931592Srgrimes int cc, nfd, n; 3941592Srgrimes char cntl; 3951592Srgrimes 3961592Srgrimes /* 3971592Srgrimes * Must ignore SIGTTOU, otherwise we'll stop 3981592Srgrimes * when we try and set slave pty's window shape 3991592Srgrimes * (our controlling tty is the master pty). 4001592Srgrimes */ 4011592Srgrimes (void) signal(SIGTTOU, SIG_IGN); 4021592Srgrimes send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 4031592Srgrimes if (f > p) 4041592Srgrimes nfd = f + 1; 4051592Srgrimes else 4061592Srgrimes nfd = p + 1; 4071592Srgrimes if (nfd > FD_SETSIZE) { 4081592Srgrimes syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 4091592Srgrimes fatal(f, "internal error (select mask too small)", 0); 4101592Srgrimes } 4111592Srgrimes for (;;) { 4121592Srgrimes fd_set ibits, obits, ebits, *omask; 4131592Srgrimes 4141592Srgrimes FD_ZERO(&ebits); 4151592Srgrimes FD_ZERO(&ibits); 4161592Srgrimes FD_ZERO(&obits); 4171592Srgrimes omask = (fd_set *)NULL; 4181592Srgrimes if (fcc) { 4191592Srgrimes FD_SET(p, &obits); 4201592Srgrimes omask = &obits; 4211592Srgrimes } else 4221592Srgrimes FD_SET(f, &ibits); 4231592Srgrimes if (pcc >= 0) 4241592Srgrimes if (pcc) { 4251592Srgrimes FD_SET(f, &obits); 4261592Srgrimes omask = &obits; 4271592Srgrimes } else 4281592Srgrimes FD_SET(p, &ibits); 4291592Srgrimes FD_SET(p, &ebits); 4301592Srgrimes if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 4311592Srgrimes if (errno == EINTR) 4321592Srgrimes continue; 4331592Srgrimes fatal(f, "select", 1); 4341592Srgrimes } 4351592Srgrimes if (n == 0) { 4361592Srgrimes /* shouldn't happen... */ 4371592Srgrimes sleep(5); 4381592Srgrimes continue; 4391592Srgrimes } 4401592Srgrimes#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 4411592Srgrimes if (FD_ISSET(p, &ebits)) { 4421592Srgrimes cc = read(p, &cntl, 1); 4431592Srgrimes if (cc == 1 && pkcontrol(cntl)) { 4441592Srgrimes cntl |= oobdata[0]; 4451592Srgrimes send(f, &cntl, 1, MSG_OOB); 4461592Srgrimes if (cntl & TIOCPKT_FLUSHWRITE) { 4471592Srgrimes pcc = 0; 4481592Srgrimes FD_CLR(p, &ibits); 4491592Srgrimes } 4501592Srgrimes } 4511592Srgrimes } 4521592Srgrimes if (FD_ISSET(f, &ibits)) { 4531592Srgrimes#ifdef CRYPT 4541592Srgrimes#ifdef KERBEROS 4551592Srgrimes if (doencrypt) 45629916Smarkm fcc = des_enc_read(f, fibuf, sizeof(fibuf), 45729916Smarkm schedule, &kdata->session); 4581592Srgrimes else 4591592Srgrimes#endif 4601592Srgrimes#endif 4611592Srgrimes fcc = read(f, fibuf, sizeof(fibuf)); 4621592Srgrimes if (fcc < 0 && errno == EWOULDBLOCK) 4631592Srgrimes fcc = 0; 4641592Srgrimes else { 4651592Srgrimes register char *cp; 4661592Srgrimes int left, n; 4671592Srgrimes 4681592Srgrimes if (fcc <= 0) 4691592Srgrimes break; 4701592Srgrimes fbp = fibuf; 4711592Srgrimes 4721592Srgrimes top: 4731592Srgrimes for (cp = fibuf; cp < fibuf+fcc-1; cp++) 4741592Srgrimes if (cp[0] == magic[0] && 4751592Srgrimes cp[1] == magic[1]) { 4761592Srgrimes left = fcc - (cp-fibuf); 4771592Srgrimes n = control(p, cp, left); 4781592Srgrimes if (n) { 4791592Srgrimes left -= n; 4801592Srgrimes if (left > 0) 4811592Srgrimes bcopy(cp+n, cp, left); 4821592Srgrimes fcc -= n; 4831592Srgrimes goto top; /* n^2 */ 4841592Srgrimes } 4851592Srgrimes } 4861592Srgrimes FD_SET(p, &obits); /* try write */ 4871592Srgrimes } 4881592Srgrimes } 4891592Srgrimes 4901592Srgrimes if (FD_ISSET(p, &obits) && fcc > 0) { 4911592Srgrimes cc = write(p, fbp, fcc); 4921592Srgrimes if (cc > 0) { 4931592Srgrimes fcc -= cc; 4941592Srgrimes fbp += cc; 4951592Srgrimes } 4961592Srgrimes } 4971592Srgrimes 4981592Srgrimes if (FD_ISSET(p, &ibits)) { 4991592Srgrimes pcc = read(p, pibuf, sizeof (pibuf)); 5001592Srgrimes pbp = pibuf; 5011592Srgrimes if (pcc < 0 && errno == EWOULDBLOCK) 5021592Srgrimes pcc = 0; 5031592Srgrimes else if (pcc <= 0) 5041592Srgrimes break; 5051592Srgrimes else if (pibuf[0] == 0) { 5061592Srgrimes pbp++, pcc--; 5071592Srgrimes#ifdef CRYPT 5081592Srgrimes#ifdef KERBEROS 5091592Srgrimes if (!doencrypt) 5101592Srgrimes#endif 5111592Srgrimes#endif 5121592Srgrimes FD_SET(f, &obits); /* try write */ 5131592Srgrimes } else { 5141592Srgrimes if (pkcontrol(pibuf[0])) { 5151592Srgrimes pibuf[0] |= oobdata[0]; 5161592Srgrimes send(f, &pibuf[0], 1, MSG_OOB); 5171592Srgrimes } 5181592Srgrimes pcc = 0; 5191592Srgrimes } 5201592Srgrimes } 5211592Srgrimes if ((FD_ISSET(f, &obits)) && pcc > 0) { 5221592Srgrimes#ifdef CRYPT 5231592Srgrimes#ifdef KERBEROS 5241592Srgrimes if (doencrypt) 52529916Smarkm cc = des_enc_write(f, pbp, pcc, 52629916Smarkm schedule, &kdata->session); 5271592Srgrimes else 5281592Srgrimes#endif 5291592Srgrimes#endif 5301592Srgrimes cc = write(f, pbp, pcc); 5311592Srgrimes if (cc < 0 && errno == EWOULDBLOCK) { 5321592Srgrimes /* 5331592Srgrimes * This happens when we try write after read 5341592Srgrimes * from p, but some old kernels balk at large 5351592Srgrimes * writes even when select returns true. 5361592Srgrimes */ 5371592Srgrimes if (!FD_ISSET(p, &ibits)) 5381592Srgrimes sleep(5); 5391592Srgrimes continue; 5401592Srgrimes } 5411592Srgrimes if (cc > 0) { 5421592Srgrimes pcc -= cc; 5431592Srgrimes pbp += cc; 5441592Srgrimes } 5451592Srgrimes } 5461592Srgrimes } 5471592Srgrimes} 5481592Srgrimes 5491592Srgrimesvoid 5501592Srgrimescleanup(signo) 5511592Srgrimes int signo; 5521592Srgrimes{ 5531592Srgrimes char *p; 5541592Srgrimes 5551592Srgrimes p = line + sizeof(_PATH_DEV) - 1; 5561592Srgrimes if (logout(p)) 5571592Srgrimes logwtmp(p, "", ""); 5581592Srgrimes (void)chmod(line, 0666); 5591592Srgrimes (void)chown(line, 0, 0); 5601592Srgrimes *p = 'p'; 5611592Srgrimes (void)chmod(line, 0666); 5621592Srgrimes (void)chown(line, 0, 0); 5631592Srgrimes shutdown(netf, 2); 5641592Srgrimes exit(1); 5651592Srgrimes} 5661592Srgrimes 5671592Srgrimesvoid 5681592Srgrimesfatal(f, msg, syserr) 5691592Srgrimes int f; 5701592Srgrimes char *msg; 5711592Srgrimes int syserr; 5721592Srgrimes{ 5731592Srgrimes int len; 5741592Srgrimes char buf[BUFSIZ], *bp = buf; 5751592Srgrimes 5761592Srgrimes /* 5771592Srgrimes * Prepend binary one to message if we haven't sent 5781592Srgrimes * the magic null as confirmation. 5791592Srgrimes */ 5801592Srgrimes if (!confirmed) 5811592Srgrimes *bp++ = '\01'; /* error indicator */ 5821592Srgrimes if (syserr) 5831592Srgrimes len = sprintf(bp, "rlogind: %s: %s.\r\n", 5841592Srgrimes msg, strerror(errno)); 5851592Srgrimes else 5861592Srgrimes len = sprintf(bp, "rlogind: %s.\r\n", msg); 5871592Srgrimes (void) write(f, buf, bp + len - buf); 5881592Srgrimes exit(1); 5891592Srgrimes} 5901592Srgrimes 5911592Srgrimesint 5921592Srgrimesdo_rlogin(dest) 5931592Srgrimes struct sockaddr_in *dest; 5941592Srgrimes{ 5951592Srgrimes getstr(rusername, sizeof(rusername), "remuser too long"); 5961592Srgrimes getstr(lusername, sizeof(lusername), "locuser too long"); 5971592Srgrimes getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 5981592Srgrimes 5991592Srgrimes pwd = getpwnam(lusername); 6001592Srgrimes if (pwd == NULL) 6011592Srgrimes return (-1); 6021592Srgrimes /* XXX why don't we syslog() failure? */ 60312434Speter return (iruserok(dest->sin_addr.s_addr, pwd->pw_uid == 0, 60412434Speter rusername, lusername)); 6051592Srgrimes} 6061592Srgrimes 6071592Srgrimesvoid 6081592Srgrimesgetstr(buf, cnt, errmsg) 6091592Srgrimes char *buf; 6101592Srgrimes int cnt; 6111592Srgrimes char *errmsg; 6121592Srgrimes{ 6131592Srgrimes char c; 6141592Srgrimes 6151592Srgrimes do { 6161592Srgrimes if (read(0, &c, 1) != 1) 6171592Srgrimes exit(1); 6181592Srgrimes if (--cnt < 0) 6191592Srgrimes fatal(STDOUT_FILENO, errmsg, 0); 6201592Srgrimes *buf++ = c; 6211592Srgrimes } while (c != 0); 6221592Srgrimes} 6231592Srgrimes 6241592Srgrimesextern char **environ; 6251592Srgrimes 6261592Srgrimesvoid 6271592Srgrimessetup_term(fd) 6281592Srgrimes int fd; 6291592Srgrimes{ 6301592Srgrimes register char *cp = index(term+ENVSIZE, '/'); 6311592Srgrimes char *speed; 6321592Srgrimes struct termios tt; 6331592Srgrimes 6341592Srgrimes#ifndef notyet 6351592Srgrimes tcgetattr(fd, &tt); 6361592Srgrimes if (cp) { 6371592Srgrimes *cp++ = '\0'; 6381592Srgrimes speed = cp; 6391592Srgrimes cp = index(speed, '/'); 6401592Srgrimes if (cp) 6411592Srgrimes *cp++ = '\0'; 6421592Srgrimes cfsetspeed(&tt, atoi(speed)); 6431592Srgrimes } 6441592Srgrimes 6451592Srgrimes tt.c_iflag = TTYDEF_IFLAG; 6461592Srgrimes tt.c_oflag = TTYDEF_OFLAG; 6471592Srgrimes tt.c_lflag = TTYDEF_LFLAG; 6481592Srgrimes tcsetattr(fd, TCSAFLUSH, &tt); 6491592Srgrimes#else 6501592Srgrimes if (cp) { 6511592Srgrimes *cp++ = '\0'; 6521592Srgrimes speed = cp; 6531592Srgrimes cp = index(speed, '/'); 6541592Srgrimes if (cp) 6551592Srgrimes *cp++ = '\0'; 6561592Srgrimes tcgetattr(fd, &tt); 6571592Srgrimes cfsetspeed(&tt, atoi(speed)); 6581592Srgrimes tcsetattr(fd, TCSAFLUSH, &tt); 6591592Srgrimes } 6601592Srgrimes#endif 6611592Srgrimes 6621592Srgrimes env[0] = term; 6631592Srgrimes env[1] = 0; 6641592Srgrimes environ = env; 6651592Srgrimes} 6661592Srgrimes 6671592Srgrimes#ifdef KERBEROS 6681592Srgrimes#define VERSION_SIZE 9 6691592Srgrimes 6701592Srgrimes/* 6711592Srgrimes * Do the remote kerberos login to the named host with the 6721592Srgrimes * given inet address 6731592Srgrimes * 6741592Srgrimes * Return 0 on valid authorization 6751592Srgrimes * Return -1 on valid authentication, no authorization 6761592Srgrimes * Return >0 for error conditions 6771592Srgrimes */ 6781592Srgrimesint 6791592Srgrimesdo_krb_login(dest) 6801592Srgrimes struct sockaddr_in *dest; 6811592Srgrimes{ 6821592Srgrimes int rc; 6831592Srgrimes char instance[INST_SZ], version[VERSION_SIZE]; 6841592Srgrimes long authopts = 0L; /* !mutual */ 6851592Srgrimes struct sockaddr_in faddr; 6861592Srgrimes 6871592Srgrimes kdata = (AUTH_DAT *) auth_buf; 6881592Srgrimes ticket = (KTEXT) tick_buf; 6891592Srgrimes 6901592Srgrimes instance[0] = '*'; 6911592Srgrimes instance[1] = '\0'; 6921592Srgrimes 6931592Srgrimes#ifdef CRYPT 6941592Srgrimes if (doencrypt) { 6951592Srgrimes rc = sizeof(faddr); 6961592Srgrimes if (getsockname(0, (struct sockaddr *)&faddr, &rc)) 6971592Srgrimes return (-1); 6981592Srgrimes authopts = KOPT_DO_MUTUAL; 6991592Srgrimes rc = krb_recvauth( 7001592Srgrimes authopts, 0, 7011592Srgrimes ticket, "rcmd", 7021592Srgrimes instance, dest, &faddr, 7031592Srgrimes kdata, "", schedule, version); 70429916Smarkm des_set_key(&kdata->session, schedule); 7051592Srgrimes 7061592Srgrimes } else 7071592Srgrimes#endif 7081592Srgrimes rc = krb_recvauth( 7091592Srgrimes authopts, 0, 7101592Srgrimes ticket, "rcmd", 7111592Srgrimes instance, dest, (struct sockaddr_in *) 0, 71218449Spst kdata, "", NULL, version); 7131592Srgrimes 7141592Srgrimes if (rc != KSUCCESS) 7151592Srgrimes return (rc); 7161592Srgrimes 7171592Srgrimes getstr(lusername, sizeof(lusername), "locuser"); 7181592Srgrimes /* get the "cmd" in the rcmd protocol */ 7191592Srgrimes getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 7201592Srgrimes 7211592Srgrimes pwd = getpwnam(lusername); 7221592Srgrimes if (pwd == NULL) 7231592Srgrimes return (-1); 7241592Srgrimes 7251592Srgrimes /* returns nonzero for no access */ 7261592Srgrimes if (kuserok(kdata, lusername) != 0) 7271592Srgrimes return (-1); 7288870Srgrimes 7291592Srgrimes return (0); 7301592Srgrimes 7311592Srgrimes} 7321592Srgrimes#endif /* KERBEROS */ 7331592Srgrimes 7341592Srgrimesvoid 7351592Srgrimesusage() 7361592Srgrimes{ 7371592Srgrimes#ifdef KERBEROS 73811486Sdg syslog(LOG_ERR, "usage: rlogind [-Daln] [-k | -v]"); 7391592Srgrimes#else 74011486Sdg syslog(LOG_ERR, "usage: rlogind [-Daln]"); 7411592Srgrimes#endif 7421592Srgrimes} 7431592Srgrimes 7441592Srgrimes/* 7451592Srgrimes * Check whether host h is in our local domain, 7461592Srgrimes * defined as sharing the last two components of the domain part, 7471592Srgrimes * or the entire domain part if the local domain has only one component. 7481592Srgrimes * If either name is unqualified (contains no '.'), 7491592Srgrimes * assume that the host is local, as it will be 7501592Srgrimes * interpreted as such. 7511592Srgrimes */ 7521592Srgrimesint 7531592Srgrimeslocal_domain(h) 7541592Srgrimes char *h; 7551592Srgrimes{ 7561592Srgrimes char localhost[MAXHOSTNAMELEN]; 7571592Srgrimes char *p1, *p2; 7581592Srgrimes 7591592Srgrimes localhost[0] = 0; 7601592Srgrimes (void) gethostname(localhost, sizeof(localhost)); 7611592Srgrimes p1 = topdomain(localhost); 7621592Srgrimes p2 = topdomain(h); 7631592Srgrimes if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 7641592Srgrimes return (1); 7651592Srgrimes return (0); 7661592Srgrimes} 7671592Srgrimes 7681592Srgrimeschar * 7691592Srgrimestopdomain(h) 7701592Srgrimes char *h; 7711592Srgrimes{ 7721592Srgrimes register char *p; 7731592Srgrimes char *maybe = NULL; 7741592Srgrimes int dots = 0; 7751592Srgrimes 7761592Srgrimes for (p = h + strlen(h); p >= h; p--) { 7771592Srgrimes if (*p == '.') { 7781592Srgrimes if (++dots == 2) 7791592Srgrimes return (p); 7801592Srgrimes maybe = p; 7811592Srgrimes } 7821592Srgrimes } 7831592Srgrimes return (maybe); 7841592Srgrimes} 785