rlogind.c revision 96196
11592Srgrimes/*- 21592Srgrimes * Copyright (c) 1983, 1988, 1989, 1993 31592Srgrimes * The Regents of the University of California. All rights reserved. 496196Sdes * Copyright (c) 2002 Networks Associates Technology, Inc. 596196Sdes * All rights reserved. 61592Srgrimes * 796196Sdes * Portions of this software were developed for the FreeBSD Project by 896196Sdes * ThinkSec AS and NAI Labs, the Security Research Division of Network 996196Sdes * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 1096196Sdes * ("CBOSS"), as part of the DARPA CHATS research program. 1196196Sdes * 121592Srgrimes * Redistribution and use in source and binary forms, with or without 131592Srgrimes * modification, are permitted provided that the following conditions 141592Srgrimes * are met: 151592Srgrimes * 1. Redistributions of source code must retain the above copyright 161592Srgrimes * notice, this list of conditions and the following disclaimer. 171592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 181592Srgrimes * notice, this list of conditions and the following disclaimer in the 191592Srgrimes * documentation and/or other materials provided with the distribution. 201592Srgrimes * 3. All advertising materials mentioning features or use of this software 211592Srgrimes * must display the following acknowledgement: 221592Srgrimes * This product includes software developed by the University of 231592Srgrimes * California, Berkeley and its contributors. 241592Srgrimes * 4. Neither the name of the University nor the names of its contributors 251592Srgrimes * may be used to endorse or promote products derived from this software 261592Srgrimes * without specific prior written permission. 271592Srgrimes * 281592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 291592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 301592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 311592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 321592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 331592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 341592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 351592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 361592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 371592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 381592Srgrimes * SUCH DAMAGE. 391592Srgrimes */ 401592Srgrimes 411592Srgrimes#ifndef lint 4229916Smarkmstatic const char copyright[] = 431592Srgrimes"@(#) Copyright (c) 1983, 1988, 1989, 1993\n\ 441592Srgrimes The Regents of the University of California. All rights reserved.\n"; 451592Srgrimes#endif /* not lint */ 461592Srgrimes 471592Srgrimes#ifndef lint 4831405Scharnier#if 0 4929916Smarkmstatic const char sccsid[] = "@(#)rlogind.c 8.1 (Berkeley) 6/4/93"; 5031405Scharnier#endif 5131405Scharnierstatic const char rcsid[] = 5250476Speter "$FreeBSD: head/libexec/rlogind/rlogind.c 96196 2002-05-08 00:47:01Z des $"; 531592Srgrimes#endif /* not lint */ 541592Srgrimes 551592Srgrimes/* 561592Srgrimes * remote login server: 571592Srgrimes * \0 581592Srgrimes * remuser\0 591592Srgrimes * locuser\0 601592Srgrimes * terminal_type/speed\0 611592Srgrimes * data 621592Srgrimes */ 631592Srgrimes 641592Srgrimes#define FD_SETSIZE 16 /* don't need many bits for select */ 6529916Smarkm#include <sys/types.h> 661592Srgrimes#include <sys/param.h> 671592Srgrimes#include <sys/stat.h> 681592Srgrimes#include <sys/ioctl.h> 691592Srgrimes#include <signal.h> 701592Srgrimes#include <termios.h> 711592Srgrimes 721592Srgrimes#include <sys/socket.h> 731592Srgrimes#include <netinet/in.h> 741592Srgrimes#include <netinet/in_systm.h> 751592Srgrimes#include <netinet/ip.h> 7611486Sdg#include <netinet/tcp.h> 771592Srgrimes#include <arpa/inet.h> 781592Srgrimes#include <netdb.h> 791592Srgrimes 8031405Scharnier#include <errno.h> 8131405Scharnier#include <libutil.h> 8296196Sdes#include <paths.h> 831592Srgrimes#include <pwd.h> 841592Srgrimes#include <syslog.h> 851592Srgrimes#include <stdio.h> 861592Srgrimes#include <stdlib.h> 871592Srgrimes#include <string.h> 8831405Scharnier#include <unistd.h> 891592Srgrimes 9051433Smarkm 911592Srgrimes#ifndef TIOCPKT_WINDOW 921592Srgrimes#define TIOCPKT_WINDOW 0x80 931592Srgrimes#endif 941592Srgrimes 9551433Smarkm#define ARGSTR "Dalnx" 961592Srgrimes 9756590Sshin/* wrapper for KAME-special getnameinfo() */ 9856590Sshin#ifndef NI_WITHSCOPEID 9956590Sshin#define NI_WITHSCOPEID 0 10056590Sshin#endif 10156590Sshin 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 11356590Sshinunion sockunion { 11456590Sshin struct sockinet { 11556590Sshin u_char si_len; 11656590Sshin u_char si_family; 11756590Sshin u_short si_port; 11856590Sshin } su_si; 11956590Sshin struct sockaddr_in su_sin; 12056590Sshin struct sockaddr_in6 su_sin6; 12156590Sshin}; 12256590Sshin#define su_len su_si.si_len 12356590Sshin#define su_family su_si.si_family 12456590Sshin#define su_port su_si.si_port 12556590Sshin 12690377Simpvoid doit(int, union sockunion *); 12790377Simpint control(int, char *, int); 12890377Simpvoid protocol(int, int); 12990377Simpvoid cleanup(int); 13090377Simpvoid fatal(int, char *, int); 13190377Simpint do_rlogin(union sockunion *); 13290377Simpvoid getstr(char *, int, char *); 13390377Simpvoid setup_term(int); 13490377Simpint do_krb_login(struct sockaddr_in *); 13590377Simpvoid usage(void); 1361592Srgrimes 13751433Smarkm 1381592Srgrimesint 13990377Simpmain(int argc, char *argv[]) 1401592Srgrimes{ 1411592Srgrimes extern int __check_rhosts_file; 14256590Sshin union sockunion from; 1431592Srgrimes int ch, fromlen, on; 1441592Srgrimes 1451592Srgrimes openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 1461592Srgrimes 1471592Srgrimes opterr = 0; 14824349Simp while ((ch = getopt(argc, argv, ARGSTR)) != -1) 1491592Srgrimes switch (ch) { 15011486Sdg case 'D': 15111486Sdg no_delay = 1; 15211486Sdg break; 1531592Srgrimes case 'a': 1541592Srgrimes check_all = 1; 1551592Srgrimes break; 1561592Srgrimes case 'l': 1571592Srgrimes __check_rhosts_file = 0; 1581592Srgrimes break; 1591592Srgrimes case 'n': 1601592Srgrimes keepalive = 0; 1611592Srgrimes break; 1621592Srgrimes#ifdef CRYPT 1631592Srgrimes case 'x': 1641592Srgrimes doencrypt = 1; 1651592Srgrimes break; 1661592Srgrimes#endif 1671592Srgrimes case '?': 1681592Srgrimes default: 1691592Srgrimes usage(); 1701592Srgrimes break; 1711592Srgrimes } 1721592Srgrimes argc -= optind; 1731592Srgrimes argv += optind; 1741592Srgrimes 1751592Srgrimes fromlen = sizeof (from); 1761592Srgrimes if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 1771592Srgrimes syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 1781592Srgrimes fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 1791592Srgrimes } 1801592Srgrimes on = 1; 1811592Srgrimes if (keepalive && 1821592Srgrimes setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 1831592Srgrimes syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 18411486Sdg if (no_delay && 18511486Sdg setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) 18611486Sdg syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m"); 18796196Sdes if (from.su_family == AF_INET) 18856590Sshin { 1891592Srgrimes on = IPTOS_LOWDELAY; 1901592Srgrimes if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 1911592Srgrimes syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 19256590Sshin } 19311486Sdg 1941592Srgrimes doit(0, &from); 19529916Smarkm return 0; 1961592Srgrimes} 1971592Srgrimes 1981592Srgrimesint child; 1991592Srgrimesint netf; 2001592Srgrimeschar line[MAXPATHLEN]; 2011592Srgrimesint confirmed; 2021592Srgrimes 2031592Srgrimesstruct winsize win = { 0, 0, 0, 0 }; 2041592Srgrimes 2051592Srgrimes 2061592Srgrimesvoid 20790377Simpdoit(int f, union sockunion *fromp) 2081592Srgrimes{ 2091592Srgrimes int master, pid, on = 1; 2101592Srgrimes int authenticated = 0; 21156590Sshin char hostname[2 * MAXHOSTNAMELEN + 1]; 21256590Sshin char nameinfo[2 * INET6_ADDRSTRLEN + 1]; 2131592Srgrimes char c; 2141592Srgrimes 2151592Srgrimes alarm(60); 2161592Srgrimes read(f, &c, 1); 2171592Srgrimes 2181592Srgrimes if (c != 0) 2191592Srgrimes exit(1); 2201592Srgrimes 2211592Srgrimes alarm(0); 22256590Sshin 22356590Sshin realhostname_sa(hostname, sizeof(hostname) - 1, 22456590Sshin (struct sockaddr *)fromp, fromp->su_len); 22556590Sshin /* error check ? */ 22656590Sshin fromp->su_port = ntohs((u_short)fromp->su_port); 22724191Simp hostname[sizeof(hostname) - 1] = '\0'; 2281592Srgrimes 2291592Srgrimes { 23063959Sume if ((fromp->su_family != AF_INET 23156590Sshin#ifdef INET6 23263959Sume && fromp->su_family != AF_INET6 23356590Sshin#endif 23456590Sshin ) || 23556590Sshin fromp->su_port >= IPPORT_RESERVED || 23656590Sshin fromp->su_port < IPPORT_RESERVED/2) { 23756590Sshin getnameinfo((struct sockaddr *)fromp, 23856590Sshin fromp->su_len, 23956590Sshin nameinfo, sizeof(nameinfo), NULL, 0, 24056590Sshin NI_NUMERICHOST|NI_WITHSCOPEID); 24156590Sshin /* error check ? */ 2421592Srgrimes syslog(LOG_NOTICE, "Connection from %s on illegal port", 24356590Sshin nameinfo); 2441592Srgrimes fatal(f, "Permission denied", 0); 2451592Srgrimes } 2461592Srgrimes#ifdef IP_OPTIONS 24756590Sshin if (fromp->su_family == AF_INET) 24896196Sdes { 24922455Simp u_char optbuf[BUFSIZ/3]; 25022455Simp int optsize = sizeof(optbuf), ipproto, i; 2511592Srgrimes struct protoent *ip; 2521592Srgrimes 2531592Srgrimes if ((ip = getprotobyname("ip")) != NULL) 2541592Srgrimes ipproto = ip->p_proto; 2551592Srgrimes else 2561592Srgrimes ipproto = IPPROTO_IP; 2571592Srgrimes if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 2581592Srgrimes &optsize) == 0 && optsize != 0) { 25922455Simp for (i = 0; i < optsize; ) { 26022455Simp u_char c = optbuf[i]; 26122455Simp if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 26222455Simp syslog(LOG_NOTICE, 26322455Simp "Connection refused from %s with IP option %s", 26456590Sshin inet_ntoa(fromp->su_sin.sin_addr), 26522455Simp c == IPOPT_LSRR ? "LSRR" : "SSRR"); 26622455Simp exit(1); 26722455Simp } 26822455Simp if (c == IPOPT_EOL) 26922455Simp break; 27022455Simp i += (c == IPOPT_NOP) ? 1 : optbuf[i+1]; 2711592Srgrimes } 2721592Srgrimes } 27356590Sshin } 2741592Srgrimes#endif 2751592Srgrimes if (do_rlogin(fromp) == 0) 2761592Srgrimes authenticated++; 2771592Srgrimes } 2781592Srgrimes if (confirmed == 0) { 2791592Srgrimes write(f, "", 1); 2801592Srgrimes confirmed = 1; /* we sent the null! */ 2811592Srgrimes } 2821592Srgrimes#ifdef CRYPT 2831592Srgrimes if (doencrypt) 28429916Smarkm (void) des_enc_write(f, 28529916Smarkm SECURE_MESSAGE, 28629916Smarkm strlen(SECURE_MESSAGE), 28729916Smarkm schedule, &kdata->session); 2881592Srgrimes#endif 2891592Srgrimes netf = f; 2901592Srgrimes 2911592Srgrimes pid = forkpty(&master, line, NULL, &win); 2921592Srgrimes if (pid < 0) { 2931592Srgrimes if (errno == ENOENT) 2941592Srgrimes fatal(f, "Out of ptys", 0); 2951592Srgrimes else 2961592Srgrimes fatal(f, "Forkpty", 1); 2971592Srgrimes } 2981592Srgrimes if (pid == 0) { 2991592Srgrimes if (f > 2) /* f should always be 0, but... */ 3001592Srgrimes (void) close(f); 3011592Srgrimes setup_term(0); 30212575Snate if (*lusername=='-') { 3032076Sguido syslog(LOG_ERR, "tried to pass user \"%s\" to login", 3042076Sguido lusername); 3052076Sguido fatal(STDERR_FILENO, "invalid user", 0); 3062076Sguido } 3071592Srgrimes if (authenticated) { 3081592Srgrimes execl(_PATH_LOGIN, "login", "-p", 3091592Srgrimes "-h", hostname, "-f", lusername, (char *)NULL); 3101592Srgrimes } else 3111592Srgrimes execl(_PATH_LOGIN, "login", "-p", 3121592Srgrimes "-h", hostname, lusername, (char *)NULL); 3131592Srgrimes fatal(STDERR_FILENO, _PATH_LOGIN, 1); 3141592Srgrimes /*NOTREACHED*/ 3151592Srgrimes } 3161592Srgrimes#ifdef CRYPT 3171592Srgrimes /* 3181592Srgrimes * If encrypted, don't turn on NBIO or the des read/write 3191592Srgrimes * routines will croak. 3201592Srgrimes */ 3211592Srgrimes 3221592Srgrimes if (!doencrypt) 3231592Srgrimes#endif 3241592Srgrimes ioctl(f, FIONBIO, &on); 3251592Srgrimes ioctl(master, FIONBIO, &on); 3261592Srgrimes ioctl(master, TIOCPKT, &on); 3271592Srgrimes signal(SIGCHLD, cleanup); 3281592Srgrimes protocol(f, master); 3291592Srgrimes signal(SIGCHLD, SIG_IGN); 3301592Srgrimes cleanup(0); 3311592Srgrimes} 3321592Srgrimes 3331592Srgrimeschar magic[2] = { 0377, 0377 }; 3341592Srgrimeschar oobdata[] = {TIOCPKT_WINDOW}; 3351592Srgrimes 3361592Srgrimes/* 3371592Srgrimes * Handle a "control" request (signaled by magic being present) 3381592Srgrimes * in the data stream. For now, we are only willing to handle 3391592Srgrimes * window size changes. 3401592Srgrimes */ 3411592Srgrimesint 34290377Simpcontrol(int pty, char *cp, int n) 3431592Srgrimes{ 3441592Srgrimes struct winsize w; 3451592Srgrimes 3461592Srgrimes if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 3471592Srgrimes return (0); 3481592Srgrimes oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 3491592Srgrimes bcopy(cp+4, (char *)&w, sizeof(w)); 3501592Srgrimes w.ws_row = ntohs(w.ws_row); 3511592Srgrimes w.ws_col = ntohs(w.ws_col); 3521592Srgrimes w.ws_xpixel = ntohs(w.ws_xpixel); 3531592Srgrimes w.ws_ypixel = ntohs(w.ws_ypixel); 3541592Srgrimes (void)ioctl(pty, TIOCSWINSZ, &w); 3551592Srgrimes return (4+sizeof (w)); 3561592Srgrimes} 3571592Srgrimes 3581592Srgrimes/* 3591592Srgrimes * rlogin "protocol" machine. 3601592Srgrimes */ 3611592Srgrimesvoid 36290377Simpprotocol(int f, int p) 3631592Srgrimes{ 36469705Sru char pibuf[1024+1], fibuf[1024], *pbp = NULL, *fbp = NULL; 36546078Simp int pcc = 0, fcc = 0; 3661592Srgrimes int cc, nfd, n; 3671592Srgrimes char cntl; 3681592Srgrimes 3691592Srgrimes /* 3701592Srgrimes * Must ignore SIGTTOU, otherwise we'll stop 3711592Srgrimes * when we try and set slave pty's window shape 3721592Srgrimes * (our controlling tty is the master pty). 3731592Srgrimes */ 3741592Srgrimes (void) signal(SIGTTOU, SIG_IGN); 3751592Srgrimes send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 3761592Srgrimes if (f > p) 3771592Srgrimes nfd = f + 1; 3781592Srgrimes else 3791592Srgrimes nfd = p + 1; 3801592Srgrimes if (nfd > FD_SETSIZE) { 3811592Srgrimes syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 3821592Srgrimes fatal(f, "internal error (select mask too small)", 0); 3831592Srgrimes } 3841592Srgrimes for (;;) { 3851592Srgrimes fd_set ibits, obits, ebits, *omask; 3861592Srgrimes 3871592Srgrimes FD_ZERO(&ebits); 3881592Srgrimes FD_ZERO(&ibits); 3891592Srgrimes FD_ZERO(&obits); 3901592Srgrimes omask = (fd_set *)NULL; 3911592Srgrimes if (fcc) { 3921592Srgrimes FD_SET(p, &obits); 3931592Srgrimes omask = &obits; 3941592Srgrimes } else 3951592Srgrimes FD_SET(f, &ibits); 39646078Simp if (pcc >= 0) { 3971592Srgrimes if (pcc) { 3981592Srgrimes FD_SET(f, &obits); 3991592Srgrimes omask = &obits; 4001592Srgrimes } else 4011592Srgrimes FD_SET(p, &ibits); 40246078Simp } 4031592Srgrimes FD_SET(p, &ebits); 4041592Srgrimes if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 4051592Srgrimes if (errno == EINTR) 4061592Srgrimes continue; 4071592Srgrimes fatal(f, "select", 1); 4081592Srgrimes } 4091592Srgrimes if (n == 0) { 4101592Srgrimes /* shouldn't happen... */ 4111592Srgrimes sleep(5); 4121592Srgrimes continue; 4131592Srgrimes } 4141592Srgrimes#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 4151592Srgrimes if (FD_ISSET(p, &ebits)) { 4161592Srgrimes cc = read(p, &cntl, 1); 4171592Srgrimes if (cc == 1 && pkcontrol(cntl)) { 4181592Srgrimes cntl |= oobdata[0]; 4191592Srgrimes send(f, &cntl, 1, MSG_OOB); 4201592Srgrimes if (cntl & TIOCPKT_FLUSHWRITE) { 4211592Srgrimes pcc = 0; 4221592Srgrimes FD_CLR(p, &ibits); 4231592Srgrimes } 4241592Srgrimes } 4251592Srgrimes } 4261592Srgrimes if (FD_ISSET(f, &ibits)) { 4271592Srgrimes#ifdef CRYPT 4281592Srgrimes if (doencrypt) 42929916Smarkm fcc = des_enc_read(f, fibuf, sizeof(fibuf), 43029916Smarkm schedule, &kdata->session); 4311592Srgrimes else 4321592Srgrimes#endif 4331592Srgrimes fcc = read(f, fibuf, sizeof(fibuf)); 4341592Srgrimes if (fcc < 0 && errno == EWOULDBLOCK) 4351592Srgrimes fcc = 0; 4361592Srgrimes else { 43790377Simp char *cp; 4381592Srgrimes int left, n; 4391592Srgrimes 4401592Srgrimes if (fcc <= 0) 4411592Srgrimes break; 4421592Srgrimes fbp = fibuf; 4431592Srgrimes 4441592Srgrimes top: 4451592Srgrimes for (cp = fibuf; cp < fibuf+fcc-1; cp++) 4461592Srgrimes if (cp[0] == magic[0] && 4471592Srgrimes cp[1] == magic[1]) { 4481592Srgrimes left = fcc - (cp-fibuf); 4491592Srgrimes n = control(p, cp, left); 4501592Srgrimes if (n) { 4511592Srgrimes left -= n; 4521592Srgrimes if (left > 0) 4531592Srgrimes bcopy(cp+n, cp, left); 4541592Srgrimes fcc -= n; 4551592Srgrimes goto top; /* n^2 */ 4561592Srgrimes } 4571592Srgrimes } 4581592Srgrimes FD_SET(p, &obits); /* try write */ 4591592Srgrimes } 4601592Srgrimes } 4611592Srgrimes 4621592Srgrimes if (FD_ISSET(p, &obits) && fcc > 0) { 4631592Srgrimes cc = write(p, fbp, fcc); 4641592Srgrimes if (cc > 0) { 4651592Srgrimes fcc -= cc; 4661592Srgrimes fbp += cc; 4671592Srgrimes } 4681592Srgrimes } 4691592Srgrimes 4701592Srgrimes if (FD_ISSET(p, &ibits)) { 4711592Srgrimes pcc = read(p, pibuf, sizeof (pibuf)); 4721592Srgrimes pbp = pibuf; 4731592Srgrimes if (pcc < 0 && errno == EWOULDBLOCK) 4741592Srgrimes pcc = 0; 4751592Srgrimes else if (pcc <= 0) 4761592Srgrimes break; 4771592Srgrimes else if (pibuf[0] == 0) { 4781592Srgrimes pbp++, pcc--; 4791592Srgrimes#ifdef CRYPT 4801592Srgrimes if (!doencrypt) 4811592Srgrimes#endif 4821592Srgrimes FD_SET(f, &obits); /* try write */ 4831592Srgrimes } else { 4841592Srgrimes if (pkcontrol(pibuf[0])) { 4851592Srgrimes pibuf[0] |= oobdata[0]; 4861592Srgrimes send(f, &pibuf[0], 1, MSG_OOB); 4871592Srgrimes } 4881592Srgrimes pcc = 0; 4891592Srgrimes } 4901592Srgrimes } 4911592Srgrimes if ((FD_ISSET(f, &obits)) && pcc > 0) { 4921592Srgrimes#ifdef CRYPT 4931592Srgrimes if (doencrypt) 49429916Smarkm cc = des_enc_write(f, pbp, pcc, 49529916Smarkm schedule, &kdata->session); 4961592Srgrimes else 4971592Srgrimes#endif 4981592Srgrimes cc = write(f, pbp, pcc); 4991592Srgrimes if (cc < 0 && errno == EWOULDBLOCK) { 5001592Srgrimes /* 5011592Srgrimes * This happens when we try write after read 5021592Srgrimes * from p, but some old kernels balk at large 5031592Srgrimes * writes even when select returns true. 5041592Srgrimes */ 5051592Srgrimes if (!FD_ISSET(p, &ibits)) 5061592Srgrimes sleep(5); 5071592Srgrimes continue; 5081592Srgrimes } 5091592Srgrimes if (cc > 0) { 5101592Srgrimes pcc -= cc; 5111592Srgrimes pbp += cc; 5121592Srgrimes } 5131592Srgrimes } 5141592Srgrimes } 5151592Srgrimes} 5161592Srgrimes 5171592Srgrimesvoid 51890377Simpcleanup(int signo) 5191592Srgrimes{ 5201592Srgrimes char *p; 5211592Srgrimes 5221592Srgrimes p = line + sizeof(_PATH_DEV) - 1; 5231592Srgrimes if (logout(p)) 5241592Srgrimes logwtmp(p, "", ""); 52550132Simp (void)chflags(line, 0); 5261592Srgrimes (void)chmod(line, 0666); 5271592Srgrimes (void)chown(line, 0, 0); 5281592Srgrimes *p = 'p'; 52950132Simp (void)chflags(line, 0); 5301592Srgrimes (void)chmod(line, 0666); 5311592Srgrimes (void)chown(line, 0, 0); 5321592Srgrimes shutdown(netf, 2); 5331592Srgrimes exit(1); 5341592Srgrimes} 5351592Srgrimes 5361592Srgrimesvoid 53790377Simpfatal(int f, char *msg, int syserr) 5381592Srgrimes{ 5391592Srgrimes int len; 5401592Srgrimes char buf[BUFSIZ], *bp = buf; 5411592Srgrimes 5421592Srgrimes /* 5431592Srgrimes * Prepend binary one to message if we haven't sent 5441592Srgrimes * the magic null as confirmation. 5451592Srgrimes */ 5461592Srgrimes if (!confirmed) 5471592Srgrimes *bp++ = '\01'; /* error indicator */ 5481592Srgrimes if (syserr) 54964238Skris len = snprintf(bp, sizeof(buf), "rlogind: %s: %s.\r\n", 5501592Srgrimes msg, strerror(errno)); 5511592Srgrimes else 55264238Skris len = snprintf(bp, sizeof(buf), "rlogind: %s.\r\n", msg); 55381991Sbrian if (len < 0) 55481972Sbrian len = 0; 5551592Srgrimes (void) write(f, buf, bp + len - buf); 5561592Srgrimes exit(1); 5571592Srgrimes} 5581592Srgrimes 5591592Srgrimesint 56090377Simpdo_rlogin(union sockunion *dest) 5611592Srgrimes{ 56266755Sru 5631592Srgrimes getstr(rusername, sizeof(rusername), "remuser too long"); 5641592Srgrimes getstr(lusername, sizeof(lusername), "locuser too long"); 5651592Srgrimes getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 5661592Srgrimes 5671592Srgrimes pwd = getpwnam(lusername); 5681592Srgrimes if (pwd == NULL) 5691592Srgrimes return (-1); 5701592Srgrimes /* XXX why don't we syslog() failure? */ 57156590Sshin 57256939Sshin return (iruserok_sa(dest, dest->su_len, pwd->pw_uid == 0, rusername, 57356939Sshin lusername)); 5741592Srgrimes} 5751592Srgrimes 5761592Srgrimesvoid 57790377Simpgetstr(char *buf, int cnt, char *errmsg) 5781592Srgrimes{ 5791592Srgrimes char c; 5801592Srgrimes 5811592Srgrimes do { 58280381Ssheldonh if (read(STDIN_FILENO, &c, 1) != 1) 5831592Srgrimes exit(1); 5841592Srgrimes if (--cnt < 0) 5851592Srgrimes fatal(STDOUT_FILENO, errmsg, 0); 5861592Srgrimes *buf++ = c; 5871592Srgrimes } while (c != 0); 5881592Srgrimes} 5891592Srgrimes 5901592Srgrimesextern char **environ; 5911592Srgrimes 5921592Srgrimesvoid 59390377Simpsetup_term(int fd) 5941592Srgrimes{ 59590377Simp char *cp = index(term+ENVSIZE, '/'); 5961592Srgrimes char *speed; 5971592Srgrimes struct termios tt; 5981592Srgrimes 5991592Srgrimes#ifndef notyet 6001592Srgrimes tcgetattr(fd, &tt); 6011592Srgrimes if (cp) { 6021592Srgrimes *cp++ = '\0'; 6031592Srgrimes speed = cp; 6041592Srgrimes cp = index(speed, '/'); 6051592Srgrimes if (cp) 6061592Srgrimes *cp++ = '\0'; 6071592Srgrimes cfsetspeed(&tt, atoi(speed)); 6081592Srgrimes } 6091592Srgrimes 6101592Srgrimes tt.c_iflag = TTYDEF_IFLAG; 6111592Srgrimes tt.c_oflag = TTYDEF_OFLAG; 6121592Srgrimes tt.c_lflag = TTYDEF_LFLAG; 6131592Srgrimes tcsetattr(fd, TCSAFLUSH, &tt); 6141592Srgrimes#else 6151592Srgrimes if (cp) { 6161592Srgrimes *cp++ = '\0'; 6171592Srgrimes speed = cp; 6181592Srgrimes cp = index(speed, '/'); 6191592Srgrimes if (cp) 6201592Srgrimes *cp++ = '\0'; 6211592Srgrimes tcgetattr(fd, &tt); 6221592Srgrimes cfsetspeed(&tt, atoi(speed)); 6231592Srgrimes tcsetattr(fd, TCSAFLUSH, &tt); 6241592Srgrimes } 6251592Srgrimes#endif 6261592Srgrimes 6271592Srgrimes env[0] = term; 6281592Srgrimes env[1] = 0; 6291592Srgrimes environ = env; 6301592Srgrimes} 6311592Srgrimes 6321592Srgrimesvoid 63390377Simpusage(void) 6341592Srgrimes{ 63551433Smarkm syslog(LOG_ERR, "usage: rlogind [-" ARGSTR "]"); 6361592Srgrimes} 637