rlogind.c revision 50476
1193323Sed/*-
2193323Sed * Copyright (c) 1983, 1988, 1989, 1993
3193323Sed *	The Regents of the University of California.  All rights reserved.
4193323Sed *
5193323Sed * Redistribution and use in source and binary forms, with or without
6193323Sed * modification, are permitted provided that the following conditions
7193323Sed * are met:
8193323Sed * 1. Redistributions of source code must retain the above copyright
9193323Sed *    notice, this list of conditions and the following disclaimer.
10193323Sed * 2. Redistributions in binary form must reproduce the above copyright
11193323Sed *    notice, this list of conditions and the following disclaimer in the
12193323Sed *    documentation and/or other materials provided with the distribution.
13204961Srdivacky * 3. All advertising materials mentioning features or use of this software
14198090Srdivacky *    must display the following acknowledgement:
15193323Sed *	This product includes software developed by the University of
16206274Srdivacky *	California, Berkeley and its contributors.
17206274Srdivacky * 4. Neither the name of the University nor the names of its contributors
18193323Sed *    may be used to endorse or promote products derived from this software
19218893Sdim *    without specific prior written permission.
20198090Srdivacky *
21193323Sed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22204961Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23198090Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24198090Srdivacky * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25204961Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26202878Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27198090Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28218893Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29198090Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30206274Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31198090Srdivacky * SUCH DAMAGE.
32207618Srdivacky */
33206274Srdivacky
34218893Sdim#ifndef lint
35205218Srdivackystatic const char copyright[] =
36198090Srdivacky"@(#) Copyright (c) 1983, 1988, 1989, 1993\n\
37207618Srdivacky	The Regents of the University of California.  All rights reserved.\n";
38198090Srdivacky#endif /* not lint */
39198090Srdivacky
40203954Srdivacky#ifndef lint
41202878Srdivacky#if 0
42193323Sedstatic const char sccsid[] = "@(#)rlogind.c	8.1 (Berkeley) 6/4/93";
43218893Sdim#endif
44193323Sedstatic const char rcsid[] =
45193323Sed  "$FreeBSD: head/libexec/rlogind/rlogind.c 50476 1999-08-28 00:22:10Z peter $";
46207618Srdivacky#endif /* not lint */
47207618Srdivacky
48207618Srdivacky/*
49212904Sdim * remote login server:
50210299Sed *	\0
51207618Srdivacky *	remuser\0
52207618Srdivacky *	locuser\0
53208599Srdivacky *	terminal_type/speed\0
54208599Srdivacky *	data
55208599Srdivacky */
56208599Srdivacky
57218893Sdim#define	FD_SETSIZE	16		/* don't need many bits for select */
58218893Sdim#include <sys/types.h>
59218893Sdim#include <sys/param.h>
60218893Sdim#include <sys/stat.h>
61207618Srdivacky#include <sys/ioctl.h>
62207618Srdivacky#include <signal.h>
63207618Srdivacky#include <termios.h>
64207618Srdivacky
65207618Srdivacky#include <sys/socket.h>
66193323Sed#include <netinet/in.h>
67193323Sed#include <netinet/in_systm.h>
68193323Sed#include <netinet/ip.h>
69193323Sed#include <netinet/tcp.h>
70193323Sed#include <arpa/inet.h>
71193323Sed#include <netdb.h>
72193323Sed
73193323Sed#include <errno.h>
74193323Sed#include <libutil.h>
75193323Sed#include <pwd.h>
76193323Sed#include <syslog.h>
77199481Srdivacky#include <stdio.h>
78193323Sed#include <stdlib.h>
79193323Sed#include <string.h>
80193323Sed#include <unistd.h>
81193323Sed#include "pathnames.h"
82193323Sed
83193323Sed#ifndef TIOCPKT_WINDOW
84205218Srdivacky#define TIOCPKT_WINDOW 0x80
85193323Sed#endif
86205218Srdivacky
87199989Srdivacky#ifdef	KERBEROS
88199989Srdivacky#include <des.h>
89210299Sed#include <krb.h>
90193323Sed#define	SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
91210299Sed
92193323SedAUTH_DAT	*kdata;
93210299SedKTEXT		ticket;
94193323Sedu_char		auth_buf[sizeof(AUTH_DAT)];
95210299Sedu_char		tick_buf[sizeof(KTEXT_ST)];
96193323SedKey_schedule	schedule;
97193323Sedint		doencrypt, retval, use_kerberos, vacuous;
98193323Sed
99193323Sed#define		ARGSTR			"Dalnkvx"
100193323Sed#else
101199989Srdivacky#define		ARGSTR			"Daln"
102193323Sed#endif	/* KERBEROS */
103199989Srdivacky
104199989Srdivackychar	*env[2];
105193323Sed#define	NMAX 30
106193323Sedchar	lusername[NMAX+1], rusername[NMAX+1];
107199989Srdivackystatic	char term[64] = "TERM=";
108193323Sed#define	ENVSIZE	(sizeof("TERM=")-1)	/* skip null for concatenation */
109193323Sedint	keepalive = 1;
110199989Srdivackyint	check_all = 0;
111205218Srdivackyint	no_delay;
112199989Srdivacky
113199989Srdivackystruct	passwd *pwd;
114193323Sed
115193323Sedvoid	doit __P((int, struct sockaddr_in *));
116193323Sedint	control __P((int, char *, int));
117199989Srdivackyvoid	protocol __P((int, int));
118193323Sedvoid	cleanup __P((int));
119199989Srdivackyvoid	fatal __P((int, char *, int));
120193323Sedint	do_rlogin __P((struct sockaddr_in *));
121206083Srdivackyvoid	getstr __P((char *, int, char *));
122193323Sedvoid	setup_term __P((int));
123199989Srdivackyint	do_krb_login __P((struct sockaddr_in *));
124199989Srdivackyvoid	usage __P((void));
125212904Sdim
126212904Sdimint
127199989Srdivackymain(argc, argv)
128199989Srdivacky	int argc;
129199989Srdivacky	char *argv[];
130193323Sed{
131210299Sed	extern int __check_rhosts_file;
132193323Sed	struct sockaddr_in from;
133199989Srdivacky	int ch, fromlen, on;
134208599Srdivacky
135210299Sed	openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
136193323Sed
137193323Sed	opterr = 0;
138199989Srdivacky	while ((ch = getopt(argc, argv, ARGSTR)) != -1)
139199989Srdivacky		switch (ch) {
140212904Sdim		case 'D':
141212904Sdim			no_delay = 1;
142212904Sdim			break;
143210299Sed		case 'a':
144201360Srdivacky			check_all = 1;
145201360Srdivacky			break;
146201360Srdivacky		case 'l':
147199989Srdivacky			__check_rhosts_file = 0;
148199989Srdivacky			break;
149208599Srdivacky		case 'n':
150210299Sed			keepalive = 0;
151199989Srdivacky			break;
152199989Srdivacky#ifdef KERBEROS
153199989Srdivacky		case 'k':
154193323Sed			use_kerberos = 1;
155199989Srdivacky			break;
156199989Srdivacky		case 'v':
157199989Srdivacky			vacuous = 1;
158193323Sed			break;
159199989Srdivacky#ifdef CRYPT
160199989Srdivacky		case 'x':
161199989Srdivacky			doencrypt = 1;
162199989Srdivacky			break;
163193323Sed#endif
164199989Srdivacky#endif
165199989Srdivacky		case '?':
166199989Srdivacky		default:
167199989Srdivacky			usage();
168193323Sed			break;
169199989Srdivacky		}
170193323Sed	argc -= optind;
171193323Sed	argv += optind;
172193323Sed
173193323Sed#ifdef	KERBEROS
174193323Sed	if (use_kerberos && vacuous) {
175198892Srdivacky		usage();
176193323Sed		fatal(STDERR_FILENO, "only one of -k and -v allowed", 0);
177208599Srdivacky	}
178208599Srdivacky#endif
179193323Sed	fromlen = sizeof (from);
180205218Srdivacky	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
181208599Srdivacky		syslog(LOG_ERR,"Can't get peer name of remote host: %m");
182193323Sed		fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
183193323Sed	}
184199481Srdivacky	on = 1;
185199481Srdivacky	if (keepalive &&
186199481Srdivacky	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
187208599Srdivacky		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
188208599Srdivacky	if (no_delay &&
189212904Sdim	    setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
190212904Sdim		syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
191212904Sdim	on = IPTOS_LOWDELAY;
192212904Sdim	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
193212904Sdim		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
194212904Sdim
195212904Sdim	doit(0, &from);
196212904Sdim	return 0;
197212904Sdim}
198212904Sdim
199212904Sdimint	child;
200212904Sdimint	netf;
201212904Sdimchar	line[MAXPATHLEN];
202212904Sdimint	confirmed;
203212904Sdim
204212904Sdimstruct winsize win = { 0, 0, 0, 0 };
205212904Sdim
206212904Sdim
207212904Sdimvoid
208212904Sdimdoit(f, fromp)
209212904Sdim	int f;
210212904Sdim	struct sockaddr_in *fromp;
211212904Sdim{
212212904Sdim	int master, pid, on = 1;
213212904Sdim	int authenticated = 0;
214212904Sdim	char hostname[MAXHOSTNAMELEN];
215212904Sdim	char c;
216212904Sdim
217212904Sdim	alarm(60);
218212904Sdim	read(f, &c, 1);
219212904Sdim
220212904Sdim	if (c != 0)
221212904Sdim		exit(1);
222212904Sdim#ifdef	KERBEROS
223212904Sdim	if (vacuous)
224212904Sdim		fatal(f, "Remote host requires Kerberos authentication", 0);
225212904Sdim#endif
226212904Sdim
227212904Sdim	alarm(0);
228212904Sdim	fromp->sin_port = ntohs((u_short)fromp->sin_port);
229212904Sdim	realhostname(hostname, sizeof(hostname) - 1, &fromp->sin_addr);
230212904Sdim	hostname[sizeof(hostname) - 1] = '\0';
231212904Sdim
232212904Sdim#ifdef	KERBEROS
233212904Sdim	if (use_kerberos) {
234212904Sdim		retval = do_krb_login(fromp);
235212904Sdim		if (retval == 0)
236212904Sdim			authenticated++;
237212904Sdim		else if (retval > 0)
238212904Sdim			fatal(f, krb_err_txt[retval], 0);
239212904Sdim		write(f, &c, 1);
240212904Sdim		confirmed = 1;		/* we sent the null! */
241212904Sdim	} else
242212904Sdim#endif
243212904Sdim	{
244212904Sdim		if (fromp->sin_family != AF_INET ||
245212904Sdim		    fromp->sin_port >= IPPORT_RESERVED ||
246212904Sdim		    fromp->sin_port < IPPORT_RESERVED/2) {
247212904Sdim			syslog(LOG_NOTICE, "Connection from %s on illegal port",
248212904Sdim				inet_ntoa(fromp->sin_addr));
249212904Sdim			fatal(f, "Permission denied", 0);
250212904Sdim		}
251212904Sdim#ifdef IP_OPTIONS
252212904Sdim		{
253212904Sdim		u_char optbuf[BUFSIZ/3];
254212904Sdim		int optsize = sizeof(optbuf), ipproto, i;
255212904Sdim		struct protoent *ip;
256193323Sed
257193323Sed		if ((ip = getprotobyname("ip")) != NULL)
258193323Sed			ipproto = ip->p_proto;
259207618Srdivacky		else
260207618Srdivacky			ipproto = IPPROTO_IP;
261207618Srdivacky		if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf,
262207618Srdivacky		    &optsize) == 0 && optsize != 0) {
263207618Srdivacky			for (i = 0; i < optsize; ) {
264207618Srdivacky				u_char c = optbuf[i];
265193323Sed				if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
266193323Sed					syslog(LOG_NOTICE,
267198892Srdivacky						"Connection refused from %s with IP option %s",
268193323Sed						inet_ntoa(fromp->sin_addr),
269199989Srdivacky						c == IPOPT_LSRR ? "LSRR" : "SSRR");
270203954Srdivacky					exit(1);
271212904Sdim				}
272199481Srdivacky				if (c == IPOPT_EOL)
273198090Srdivacky					break;
274198090Srdivacky				i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
275207618Srdivacky			}
276205218Srdivacky		}
277205218Srdivacky		}
278205218Srdivacky#endif
279205218Srdivacky		if (do_rlogin(fromp) == 0)
280207618Srdivacky			authenticated++;
281195098Sed	}
282195098Sed	if (confirmed == 0) {
283193323Sed		write(f, "", 1);
284208599Srdivacky		confirmed = 1;		/* we sent the null! */
285199481Srdivacky	}
286207618Srdivacky#ifdef	KERBEROS
287207618Srdivacky#ifdef	CRYPT
288193323Sed	if (doencrypt)
289193323Sed		(void) des_enc_write(f,
290193323Sed				     SECURE_MESSAGE,
291193323Sed				     strlen(SECURE_MESSAGE),
292199481Srdivacky				     schedule, &kdata->session);
293193323Sed#endif
294208599Srdivacky#endif
295208599Srdivacky	netf = f;
296205218Srdivacky
297212904Sdim	pid = forkpty(&master, line, NULL, &win);
298207618Srdivacky	if (pid < 0) {
299207618Srdivacky		if (errno == ENOENT)
300207618Srdivacky			fatal(f, "Out of ptys", 0);
301207618Srdivacky		else
302212904Sdim			fatal(f, "Forkpty", 1);
303207618Srdivacky	}
304212904Sdim	if (pid == 0) {
305207618Srdivacky		if (f > 2)	/* f should always be 0, but... */
306207618Srdivacky			(void) close(f);
307207618Srdivacky		setup_term(0);
308207618Srdivacky		 if (*lusername=='-') {
309212904Sdim			syslog(LOG_ERR, "tried to pass user \"%s\" to login",
310207618Srdivacky			       lusername);
311207618Srdivacky			fatal(STDERR_FILENO, "invalid user", 0);
312207618Srdivacky		}
313207618Srdivacky		if (authenticated) {
314207618Srdivacky#ifdef	KERBEROS
315207618Srdivacky			if (use_kerberos && (pwd->pw_uid == 0))
316207618Srdivacky				syslog(LOG_INFO|LOG_AUTH,
317207618Srdivacky				    "ROOT Kerberos login from %s.%s@%s on %s\n",
318207618Srdivacky				    kdata->pname, kdata->pinst, kdata->prealm,
319207618Srdivacky				    hostname);
320207618Srdivacky#endif
321207618Srdivacky
322207618Srdivacky			execl(_PATH_LOGIN, "login", "-p",
323207618Srdivacky			    "-h", hostname, "-f", lusername, (char *)NULL);
324212904Sdim		} else
325207618Srdivacky			execl(_PATH_LOGIN, "login", "-p",
326212904Sdim			    "-h", hostname, lusername, (char *)NULL);
327207618Srdivacky		fatal(STDERR_FILENO, _PATH_LOGIN, 1);
328207618Srdivacky		/*NOTREACHED*/
329207618Srdivacky	}
330207618Srdivacky#ifdef	CRYPT
331207618Srdivacky#ifdef	KERBEROS
332199481Srdivacky	/*
333199481Srdivacky	 * If encrypted, don't turn on NBIO or the des read/write
334199481Srdivacky	 * routines will croak.
335207618Srdivacky	 */
336207618Srdivacky
337207618Srdivacky	if (!doencrypt)
338207618Srdivacky#endif
339207618Srdivacky#endif
340207618Srdivacky		ioctl(f, FIONBIO, &on);
341212904Sdim	ioctl(master, FIONBIO, &on);
342207618Srdivacky	ioctl(master, TIOCPKT, &on);
343207618Srdivacky	signal(SIGCHLD, cleanup);
344207618Srdivacky	protocol(f, master);
345207618Srdivacky	signal(SIGCHLD, SIG_IGN);
346207618Srdivacky	cleanup(0);
347207618Srdivacky}
348199989Srdivacky
349193323Sedchar	magic[2] = { 0377, 0377 };
350199989Srdivackychar	oobdata[] = {TIOCPKT_WINDOW};
351193323Sed
352199989Srdivacky/*
353193323Sed * Handle a "control" request (signaled by magic being present)
354199989Srdivacky * in the data stream.  For now, we are only willing to handle
355193323Sed * window size changes.
356193323Sed */
357193323Sedint
358193323Sedcontrol(pty, cp, n)
359193323Sed	int pty;
360207618Srdivacky	char *cp;
361206274Srdivacky	int n;
362193323Sed{
363193323Sed	struct winsize w;
364193323Sed
365201360Srdivacky	if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
366198090Srdivacky		return (0);
367208599Srdivacky	oobdata[0] &= ~TIOCPKT_WINDOW;	/* we know he heard */
368199481Srdivacky	bcopy(cp+4, (char *)&w, sizeof(w));
369199481Srdivacky	w.ws_row = ntohs(w.ws_row);
370199481Srdivacky	w.ws_col = ntohs(w.ws_col);
371193323Sed	w.ws_xpixel = ntohs(w.ws_xpixel);
372193323Sed	w.ws_ypixel = ntohs(w.ws_ypixel);
373199481Srdivacky	(void)ioctl(pty, TIOCSWINSZ, &w);
374199481Srdivacky	return (4+sizeof (w));
375193323Sed}
376193323Sed
377193323Sed/*
378193323Sed * rlogin "protocol" machine.
379193323Sed */
380193323Sedvoid
381193323Sedprotocol(f, p)
382193323Sed	register int f, p;
383193323Sed{
384193323Sed	char pibuf[1024+1], fibuf[1024], *pbp, *fbp;
385193323Sed	int pcc = 0, fcc = 0;
386193323Sed	int cc, nfd, n;
387193323Sed	char cntl;
388206274Srdivacky
389208599Srdivacky	/*
390212904Sdim	 * Must ignore SIGTTOU, otherwise we'll stop
391207618Srdivacky	 * when we try and set slave pty's window shape
392205218Srdivacky	 * (our controlling tty is the master pty).
393212904Sdim	 */
394206274Srdivacky	(void) signal(SIGTTOU, SIG_IGN);
395206274Srdivacky	send(f, oobdata, 1, MSG_OOB);	/* indicate new rlogin */
396212904Sdim	if (f > p)
397208599Srdivacky		nfd = f + 1;
398210299Sed	else
399210299Sed		nfd = p + 1;
400210299Sed	if (nfd > FD_SETSIZE) {
401210299Sed		syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE");
402207618Srdivacky		fatal(f, "internal error (select mask too small)", 0);
403193323Sed	}
404193323Sed	for (;;) {
405206083Srdivacky		fd_set ibits, obits, ebits, *omask;
406206083Srdivacky
407193323Sed		FD_ZERO(&ebits);
408193323Sed		FD_ZERO(&ibits);
409205218Srdivacky		FD_ZERO(&obits);
410205218Srdivacky		omask = (fd_set *)NULL;
411205218Srdivacky		if (fcc) {
412205218Srdivacky			FD_SET(p, &obits);
413205218Srdivacky			omask = &obits;
414206274Srdivacky		} else
415205218Srdivacky			FD_SET(f, &ibits);
416205218Srdivacky		if (pcc >= 0) {
417205218Srdivacky			if (pcc) {
418199989Srdivacky				FD_SET(f, &obits);
419193323Sed				omask = &obits;
420199989Srdivacky			} else
421193323Sed				FD_SET(p, &ibits);
422193323Sed		}
423193323Sed		FD_SET(p, &ebits);
424193323Sed		if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) {
425193323Sed			if (errno == EINTR)
426193323Sed				continue;
427193323Sed			fatal(f, "select", 1);
428193323Sed		}
429193323Sed		if (n == 0) {
430193323Sed			/* shouldn't happen... */
431193323Sed			sleep(5);
432193323Sed			continue;
433193323Sed		}
434193323Sed#define	pkcontrol(c)	((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
435193323Sed		if (FD_ISSET(p, &ebits)) {
436193323Sed			cc = read(p, &cntl, 1);
437193323Sed			if (cc == 1 && pkcontrol(cntl)) {
438193323Sed				cntl |= oobdata[0];
439193323Sed				send(f, &cntl, 1, MSG_OOB);
440193323Sed				if (cntl & TIOCPKT_FLUSHWRITE) {
441199989Srdivacky					pcc = 0;
442193323Sed					FD_CLR(p, &ibits);
443199989Srdivacky				}
444206083Srdivacky			}
445193323Sed		}
446193323Sed		if (FD_ISSET(f, &ibits)) {
447193323Sed#ifdef	CRYPT
448199989Srdivacky#ifdef	KERBEROS
449193323Sed			if (doencrypt)
450199989Srdivacky				fcc = des_enc_read(f, fibuf, sizeof(fibuf),
451193323Sed					schedule, &kdata->session);
452193323Sed			else
453212904Sdim#endif
454210299Sed#endif
455199989Srdivacky				fcc = read(f, fibuf, sizeof(fibuf));
456193323Sed			if (fcc < 0 && errno == EWOULDBLOCK)
457193323Sed				fcc = 0;
458199989Srdivacky			else {
459193323Sed				register char *cp;
460199989Srdivacky				int left, n;
461193323Sed
462193323Sed				if (fcc <= 0)
463206083Srdivacky					break;
464199989Srdivacky				fbp = fibuf;
465193323Sed
466193323Sed			top:
467200581Srdivacky				for (cp = fibuf; cp < fibuf+fcc-1; cp++)
468212904Sdim					if (cp[0] == magic[0] &&
469199989Srdivacky					    cp[1] == magic[1]) {
470202878Srdivacky						left = fcc - (cp-fibuf);
471206083Srdivacky						n = control(p, cp, left);
472199989Srdivacky						if (n) {
473193323Sed							left -= n;
474193323Sed							if (left > 0)
475199989Srdivacky								bcopy(cp+n, cp, left);
476193323Sed							fcc -= n;
477199989Srdivacky							goto top; /* n^2 */
478204961Srdivacky						}
479206083Srdivacky					}
480199989Srdivacky				FD_SET(p, &obits);		/* try write */
481193323Sed			}
482193323Sed		}
483199989Srdivacky
484193323Sed		if (FD_ISSET(p, &obits) && fcc > 0) {
485199989Srdivacky			cc = write(p, fbp, fcc);
486204961Srdivacky			if (cc > 0) {
487206083Srdivacky				fcc -= cc;
488199989Srdivacky				fbp += cc;
489193323Sed			}
490193323Sed		}
491206274Srdivacky
492206274Srdivacky		if (FD_ISSET(p, &ibits)) {
493206274Srdivacky			pcc = read(p, pibuf, sizeof (pibuf));
494206274Srdivacky			pbp = pibuf;
495206274Srdivacky			if (pcc < 0 && errno == EWOULDBLOCK)
496206274Srdivacky				pcc = 0;
497206274Srdivacky			else if (pcc <= 0)
498206274Srdivacky				break;
499199989Srdivacky			else if (pibuf[0] == 0) {
500193323Sed				pbp++, pcc--;
501199989Srdivacky#ifdef	CRYPT
502193323Sed#ifdef	KERBEROS
503206274Srdivacky				if (!doencrypt)
504206083Srdivacky#endif
505199989Srdivacky#endif
506193323Sed					FD_SET(f, &obits);	/* try write */
507193323Sed			} else {
508199989Srdivacky				if (pkcontrol(pibuf[0])) {
509193323Sed					pibuf[0] |= oobdata[0];
510212904Sdim					send(f, &pibuf[0], 1, MSG_OOB);
511208599Srdivacky				}
512212904Sdim				pcc = 0;
513193323Sed			}
514193323Sed		}
515212904Sdim		if ((FD_ISSET(f, &obits)) && pcc > 0) {
516218893Sdim#ifdef	CRYPT
517218893Sdim#ifdef	KERBEROS
518218893Sdim			if (doencrypt)
519193323Sed				cc = des_enc_write(f, pbp, pcc,
520199989Srdivacky					schedule, &kdata->session);
521199989Srdivacky			else
522193323Sed#endif
523193323Sed#endif
524199989Srdivacky				cc = write(f, pbp, pcc);
525193323Sed			if (cc < 0 && errno == EWOULDBLOCK) {
526212904Sdim				/*
527208599Srdivacky				 * This happens when we try write after read
528212904Sdim				 * from p, but some old kernels balk at large
529193323Sed				 * writes even when select returns true.
530193323Sed				 */
531212904Sdim				if (!FD_ISSET(p, &ibits))
532218893Sdim					sleep(5);
533218893Sdim				continue;
534218893Sdim			}
535193323Sed			if (cc > 0) {
536199989Srdivacky				pcc -= cc;
537199989Srdivacky				pbp += cc;
538193323Sed			}
539198090Srdivacky		}
540199989Srdivacky	}
541198090Srdivacky}
542212904Sdim
543208599Srdivackyvoid
544212904Sdimcleanup(signo)
545198090Srdivacky	int signo;
546198090Srdivacky{
547212904Sdim	char *p;
548198090Srdivacky
549198090Srdivacky	p = line + sizeof(_PATH_DEV) - 1;
550212904Sdim	if (logout(p))
551212904Sdim		logwtmp(p, "", "");
552204961Srdivacky	(void)chflags(line, 0);
553218893Sdim	(void)chmod(line, 0666);
554198090Srdivacky	(void)chown(line, 0, 0);
555199989Srdivacky	*p = 'p';
556199989Srdivacky	(void)chflags(line, 0);
557198090Srdivacky	(void)chmod(line, 0666);
558198090Srdivacky	(void)chown(line, 0, 0);
559199989Srdivacky	shutdown(netf, 2);
560198090Srdivacky	exit(1);
561212904Sdim}
562208599Srdivacky
563212904Sdimvoid
564193323Sedfatal(f, msg, syserr)
565193323Sed	int f;
566212904Sdim	char *msg;
567218893Sdim	int syserr;
568204961Srdivacky{
569218893Sdim	int len;
570193323Sed	char buf[BUFSIZ], *bp = buf;
571199989Srdivacky
572199989Srdivacky	/*
573193323Sed	 * Prepend binary one to message if we haven't sent
574193323Sed	 * the magic null as confirmation.
575201360Srdivacky	 */
576201360Srdivacky	if (!confirmed)
577212904Sdim		*bp++ = '\01';		/* error indicator */
578208599Srdivacky	if (syserr)
579212904Sdim		len = sprintf(bp, "rlogind: %s: %s.\r\n",
580201360Srdivacky		    msg, strerror(errno));
581201360Srdivacky	else
582212904Sdim		len = sprintf(bp, "rlogind: %s.\r\n", msg);
583218893Sdim	(void) write(f, buf, bp + len - buf);
584218893Sdim	exit(1);
585212904Sdim}
586201360Srdivacky
587218893Sdimint
588201360Srdivackydo_rlogin(dest)
589201360Srdivacky	struct sockaddr_in *dest;
590201360Srdivacky{
591201360Srdivacky	getstr(rusername, sizeof(rusername), "remuser too long");
592201360Srdivacky	getstr(lusername, sizeof(lusername), "locuser too long");
593212904Sdim	getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
594212904Sdim
595212904Sdim	pwd = getpwnam(lusername);
596212904Sdim	if (pwd == NULL)
597212904Sdim		return (-1);
598218893Sdim	/* XXX why don't we syslog() failure? */
599218893Sdim	return (iruserok(dest->sin_addr.s_addr, pwd->pw_uid == 0,
600212904Sdim		rusername, lusername));
601198090Srdivacky}
602212904Sdim
603212904Sdimvoid
604212904Sdimgetstr(buf, cnt, errmsg)
605212904Sdim	char *buf;
606212904Sdim	int cnt;
607212904Sdim	char *errmsg;
608198090Srdivacky{
609198090Srdivacky	char c;
610199989Srdivacky
611198090Srdivacky	do {
612198090Srdivacky		if (read(0, &c, 1) != 1)
613198090Srdivacky			exit(1);
614198090Srdivacky		if (--cnt < 0)
615199989Srdivacky			fatal(STDOUT_FILENO, errmsg, 0);
616198090Srdivacky		*buf++ = c;
617198090Srdivacky	} while (c != 0);
618212904Sdim}
619198090Srdivacky
620198090Srdivackyextern	char **environ;
621198090Srdivacky
622206274Srdivackyvoid
623198090Srdivackysetup_term(fd)
624206083Srdivacky	int fd;
625198090Srdivacky{
626198090Srdivacky	register char *cp = index(term+ENVSIZE, '/');
627198090Srdivacky	char *speed;
628199989Srdivacky	struct termios tt;
629198090Srdivacky
630218893Sdim#ifndef notyet
631199989Srdivacky	tcgetattr(fd, &tt);
632198090Srdivacky	if (cp) {
633198090Srdivacky		*cp++ = '\0';
634198090Srdivacky		speed = cp;
635199989Srdivacky		cp = index(speed, '/');
636198090Srdivacky		if (cp)
637199989Srdivacky			*cp++ = '\0';
638199989Srdivacky		cfsetspeed(&tt, atoi(speed));
639198090Srdivacky	}
640198090Srdivacky
641199989Srdivacky	tt.c_iflag = TTYDEF_IFLAG;
642198090Srdivacky	tt.c_oflag = TTYDEF_OFLAG;
643198090Srdivacky	tt.c_lflag = TTYDEF_LFLAG;
644212904Sdim	tcsetattr(fd, TCSAFLUSH, &tt);
645212904Sdim#else
646198090Srdivacky	if (cp) {
647198090Srdivacky		*cp++ = '\0';
648199989Srdivacky		speed = cp;
649212904Sdim		cp = index(speed, '/');
650198090Srdivacky		if (cp)
651199989Srdivacky			*cp++ = '\0';
652198090Srdivacky		tcgetattr(fd, &tt);
653198090Srdivacky		cfsetspeed(&tt, atoi(speed));
654198090Srdivacky		tcsetattr(fd, TCSAFLUSH, &tt);
655198090Srdivacky	}
656199989Srdivacky#endif
657198090Srdivacky
658198090Srdivacky	env[0] = term;
659198090Srdivacky	env[1] = 0;
660198090Srdivacky	environ = env;
661198090Srdivacky}
662198090Srdivacky
663198090Srdivacky#ifdef	KERBEROS
664198090Srdivacky#define	VERSION_SIZE	9
665198090Srdivacky
666198090Srdivacky/*
667198090Srdivacky * Do the remote kerberos login to the named host with the
668199989Srdivacky * given inet address
669198090Srdivacky *
670198090Srdivacky * Return 0 on valid authorization
671198090Srdivacky * Return -1 on valid authentication, no authorization
672198090Srdivacky * Return >0 for error conditions
673198090Srdivacky */
674198090Srdivackyint
675198090Srdivackydo_krb_login(dest)
676198090Srdivacky	struct sockaddr_in *dest;
677198090Srdivacky{
678198090Srdivacky	int rc;
679198090Srdivacky	char instance[INST_SZ], version[VERSION_SIZE];
680198090Srdivacky	long authopts = 0L;	/* !mutual */
681198090Srdivacky	struct sockaddr_in faddr;
682198090Srdivacky
683198090Srdivacky	kdata = (AUTH_DAT *) auth_buf;
684198090Srdivacky	ticket = (KTEXT) tick_buf;
685198090Srdivacky
686198090Srdivacky	instance[0] = '*';
687198090Srdivacky	instance[1] = '\0';
688198090Srdivacky
689198090Srdivacky#ifdef	CRYPT
690198090Srdivacky	if (doencrypt) {
691198090Srdivacky		rc = sizeof(faddr);
692198090Srdivacky		if (getsockname(0, (struct sockaddr *)&faddr, &rc))
693198090Srdivacky			return (-1);
694198090Srdivacky		authopts = KOPT_DO_MUTUAL;
695198090Srdivacky		rc = krb_recvauth(
696203954Srdivacky			authopts, 0,
697198090Srdivacky			ticket, "rcmd",
698198090Srdivacky			instance, dest, &faddr,
699198090Srdivacky			kdata, "", schedule, version);
700198090Srdivacky		 des_set_key(&kdata->session, schedule);
701198090Srdivacky
702198090Srdivacky	} else
703198090Srdivacky#endif
704198090Srdivacky		rc = krb_recvauth(
705198090Srdivacky			authopts, 0,
706198090Srdivacky			ticket, "rcmd",
707198090Srdivacky			instance, dest, (struct sockaddr_in *) 0,
708198090Srdivacky			kdata, "", NULL, version);
709198090Srdivacky
710198090Srdivacky	if (rc != KSUCCESS)
711198090Srdivacky		return (rc);
712198090Srdivacky
713199989Srdivacky	getstr(lusername, sizeof(lusername), "locuser");
714198090Srdivacky	/* get the "cmd" in the rcmd protocol */
715198090Srdivacky	getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type");
716198090Srdivacky
717198090Srdivacky	pwd = getpwnam(lusername);
718198090Srdivacky	if (pwd == NULL)
719199989Srdivacky		return (-1);
720198090Srdivacky
721198090Srdivacky	/* returns nonzero for no access */
722212904Sdim	if (kuserok(kdata, lusername) != 0)
723198090Srdivacky		return (-1);
724198090Srdivacky
725198090Srdivacky	return (0);
726198090Srdivacky
727212904Sdim}
728198090Srdivacky#endif /* KERBEROS */
729198090Srdivacky
730208599Srdivackyvoid
731198090Srdivackyusage()
732198090Srdivacky{
733198090Srdivacky#ifdef KERBEROS
734198090Srdivacky	syslog(LOG_ERR, "usage: rlogind [-Daln] [-k | -v]");
735208599Srdivacky#else
736198090Srdivacky	syslog(LOG_ERR, "usage: rlogind [-Daln]");
737198090Srdivacky#endif
738198090Srdivacky}
739198090Srdivacky