xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 54554)
1 /*-
2  * Copyright (c) 1983, 1988, 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1983, 1988, 1989 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)rlogind.c	5.55 (Berkeley) 06/29/92";
16 #endif /* not lint */
17 
18 /*
19  * remote login server:
20  *	\0
21  *	remuser\0
22  *	locuser\0
23  *	terminal_type/speed\0
24  *	data
25  */
26 
27 #define	FD_SETSIZE	16		/* don't need many bits for select */
28 #include <sys/param.h>
29 #include <sys/stat.h>
30 #include <sys/ioctl.h>
31 #include <signal.h>
32 #include <termios.h>
33 
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <netinet/in_systm.h>
37 #include <netinet/ip.h>
38 #include <arpa/inet.h>
39 #include <netdb.h>
40 
41 #include <pwd.h>
42 #include <syslog.h>
43 #include <errno.h>
44 #include <stdio.h>
45 #include <unistd.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include "pathnames.h"
49 
50 #ifndef TIOCPKT_WINDOW
51 #define TIOCPKT_WINDOW 0x80
52 #endif
53 
54 #ifdef	KERBEROS
55 #include <kerberosIV/des.h>
56 #include <kerberosIV/krb.h>
57 #define	SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
58 
59 AUTH_DAT	*kdata;
60 KTEXT		ticket;
61 u_char		auth_buf[sizeof(AUTH_DAT)];
62 u_char		tick_buf[sizeof(KTEXT_ST)];
63 Key_schedule	schedule;
64 int		doencrypt, retval, use_kerberos, vacuous;
65 
66 #define		ARGSTR			"alnkvx"
67 #else
68 #define		ARGSTR			"aln"
69 #endif	/* KERBEROS */
70 
71 char	*env[2];
72 #define	NMAX 30
73 char	lusername[NMAX+1], rusername[NMAX+1];
74 static	char term[64] = "TERM=";
75 #define	ENVSIZE	(sizeof("TERM=")-1)	/* skip null for concatenation */
76 int	keepalive = 1;
77 int	check_all = 0;
78 
79 struct	passwd *pwd;
80 
81 void	doit __P((int, struct sockaddr_in *));
82 int	control __P((int, char *, int));
83 void	protocol __P((int, int));
84 void	cleanup __P((int));
85 void	fatal __P((int, char *, int));
86 int	do_rlogin __P((struct sockaddr_in *));
87 void	getstr __P((char *, int, char *));
88 void	setup_term __P((int));
89 int	do_krb_login __P((struct sockaddr_in *));
90 void	usage __P((void));
91 int	local_domain __P((char *));
92 char	*topdomain __P((char *));
93 
94 int
95 main(argc, argv)
96 	int argc;
97 	char *argv[];
98 {
99 	extern int __check_rhosts_file;
100 	struct sockaddr_in from;
101 	int ch, fromlen, on;
102 
103 	openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
104 
105 	opterr = 0;
106 	while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
107 		switch (ch) {
108 		case 'a':
109 			check_all = 1;
110 			break;
111 		case 'l':
112 			__check_rhosts_file = 0;
113 			break;
114 		case 'n':
115 			keepalive = 0;
116 			break;
117 #ifdef KERBEROS
118 		case 'k':
119 			use_kerberos = 1;
120 			break;
121 		case 'v':
122 			vacuous = 1;
123 			break;
124 #ifdef CRYPT
125 		case 'x':
126 			doencrypt = 1;
127 			break;
128 #endif
129 #endif
130 		case '?':
131 		default:
132 			usage();
133 			break;
134 		}
135 	argc -= optind;
136 	argv += optind;
137 
138 #ifdef	KERBEROS
139 	if (use_kerberos && vacuous) {
140 		usage();
141 		fatal(STDERR_FILENO, "only one of -k and -v allowed", 0);
142 	}
143 #endif
144 	fromlen = sizeof (from);
145 	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
146 		syslog(LOG_ERR,"Can't get peer name of remote host: %m");
147 		fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
148 	}
149 	on = 1;
150 	if (keepalive &&
151 	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
152 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
153 	on = IPTOS_LOWDELAY;
154 	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
155 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
156 	doit(0, &from);
157 }
158 
159 int	child;
160 int	netf;
161 char	line[MAXPATHLEN];
162 int	confirmed;
163 
164 struct winsize win = { 0, 0, 0, 0 };
165 
166 
167 void
168 doit(f, fromp)
169 	int f;
170 	struct sockaddr_in *fromp;
171 {
172 	int master, pid, on = 1;
173 	int authenticated = 0;
174 	register struct hostent *hp;
175 	register char *hostname;
176 	char remotehost[2 * MAXHOSTNAMELEN + 1];
177 	char c;
178 
179 	alarm(60);
180 	read(f, &c, 1);
181 
182 	if (c != 0)
183 		exit(1);
184 #ifdef	KERBEROS
185 	if (vacuous)
186 		fatal(f, "Remote host requires Kerberos authentication", 0);
187 #endif
188 
189 	alarm(0);
190 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
191 	hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr),
192 	    fromp->sin_family);
193 	if (hp)
194 		hostname = hp->h_name;
195 	else
196 		hostname = strcpy(remotehost, inet_ntoa(fromp->sin_addr));
197 
198 #ifdef	KERBEROS
199 	if (use_kerberos) {
200 		retval = do_krb_login(fromp);
201 		if (retval == 0)
202 			authenticated++;
203 		else if (retval > 0)
204 			fatal(f, krb_err_txt[retval], 0);
205 		write(f, &c, 1);
206 		confirmed = 1;		/* we sent the null! */
207 	} else
208 #endif
209 	{
210 		if (fromp->sin_family != AF_INET ||
211 		    fromp->sin_port >= IPPORT_RESERVED ||
212 		    fromp->sin_port < IPPORT_RESERVED/2) {
213 			syslog(LOG_NOTICE, "Connection from %s on illegal port",
214 				inet_ntoa(fromp->sin_addr));
215 			fatal(f, "Permission denied", 0);
216 		}
217 #ifdef IP_OPTIONS
218 		{
219 		u_char optbuf[BUFSIZ/3], *cp;
220 		char lbuf[BUFSIZ], *lp;
221 		int optsize = sizeof(optbuf), ipproto;
222 		struct protoent *ip;
223 
224 		if ((ip = getprotobyname("ip")) != NULL)
225 			ipproto = ip->p_proto;
226 		else
227 			ipproto = IPPROTO_IP;
228 		if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf,
229 		    &optsize) == 0 && optsize != 0) {
230 			lp = lbuf;
231 			for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
232 				sprintf(lp, " %2.2x", *cp);
233 			syslog(LOG_NOTICE,
234 			    "Connection received using IP options (ignored):%s",
235 			    lbuf);
236 			if (setsockopt(0, ipproto, IP_OPTIONS,
237 			    (char *)NULL, optsize) != 0) {
238 				syslog(LOG_ERR,
239 				    "setsockopt IP_OPTIONS NULL: %m");
240 				exit(1);
241 			}
242 		}
243 		}
244 #endif
245 		if (do_rlogin(fromp) == 0)
246 			authenticated++;
247 	}
248 	if (confirmed == 0) {
249 		write(f, "", 1);
250 		confirmed = 1;		/* we sent the null! */
251 	}
252 #ifdef	KERBEROS
253 #ifdef	CRYPT
254 	if (doencrypt)
255 		(void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE));
256 #endif
257 #endif
258 	netf = f;
259 
260 	pid = forkpty(&master, line, NULL, &win);
261 	if (pid < 0) {
262 		if (errno == ENOENT)
263 			fatal(f, "Out of ptys", 0);
264 		else
265 			fatal(f, "Forkpty", 1);
266 	}
267 	if (pid == 0) {
268 		if (f > 2)	/* f should always be 0, but... */
269 			(void) close(f);
270 		setup_term(0);
271 		if (authenticated) {
272 #ifdef	KERBEROS
273 			if (use_kerberos && (pwd->pw_uid == 0))
274 				syslog(LOG_INFO|LOG_AUTH,
275 				    "ROOT Kerberos login from %s.%s@%s on %s\n",
276 				    kdata->pname, kdata->pinst, kdata->prealm,
277 				    hostname);
278 #endif
279 
280 			execl(_PATH_LOGIN, "login", "-p",
281 			    "-h", hostname, "-f", lusername, (char *)NULL);
282 		} else
283 			execl(_PATH_LOGIN, "login", "-p",
284 			    "-h", hostname, lusername, (char *)NULL);
285 		fatal(STDERR_FILENO, _PATH_LOGIN, 1);
286 		/*NOTREACHED*/
287 	}
288 #ifdef	CRYPT
289 #ifdef	KERBEROS
290 	/*
291 	 * If encrypted, don't turn on NBIO or the des read/write
292 	 * routines will croak.
293 	 */
294 
295 	if (!doencrypt)
296 #endif
297 #endif
298 		ioctl(f, FIONBIO, &on);
299 	ioctl(master, FIONBIO, &on);
300 	ioctl(master, TIOCPKT, &on);
301 	signal(SIGCHLD, cleanup);
302 	protocol(f, master);
303 	signal(SIGCHLD, SIG_IGN);
304 	cleanup(0);
305 }
306 
307 char	magic[2] = { 0377, 0377 };
308 char	oobdata[] = {TIOCPKT_WINDOW};
309 
310 /*
311  * Handle a "control" request (signaled by magic being present)
312  * in the data stream.  For now, we are only willing to handle
313  * window size changes.
314  */
315 int
316 control(pty, cp, n)
317 	int pty;
318 	char *cp;
319 	int n;
320 {
321 	struct winsize w;
322 
323 	if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
324 		return (0);
325 	oobdata[0] &= ~TIOCPKT_WINDOW;	/* we know he heard */
326 	bcopy(cp+4, (char *)&w, sizeof(w));
327 	w.ws_row = ntohs(w.ws_row);
328 	w.ws_col = ntohs(w.ws_col);
329 	w.ws_xpixel = ntohs(w.ws_xpixel);
330 	w.ws_ypixel = ntohs(w.ws_ypixel);
331 	(void)ioctl(pty, TIOCSWINSZ, &w);
332 	return (4+sizeof (w));
333 }
334 
335 /*
336  * rlogin "protocol" machine.
337  */
338 void
339 protocol(f, p)
340 	register int f, p;
341 {
342 	char pibuf[1024+1], fibuf[1024], *pbp, *fbp;
343 	register pcc = 0, fcc = 0;
344 	int cc, nfd, n;
345 	char cntl;
346 
347 	/*
348 	 * Must ignore SIGTTOU, otherwise we'll stop
349 	 * when we try and set slave pty's window shape
350 	 * (our controlling tty is the master pty).
351 	 */
352 	(void) signal(SIGTTOU, SIG_IGN);
353 	send(f, oobdata, 1, MSG_OOB);	/* indicate new rlogin */
354 	if (f > p)
355 		nfd = f + 1;
356 	else
357 		nfd = p + 1;
358 	if (nfd > FD_SETSIZE) {
359 		syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE");
360 		fatal(f, "internal error (select mask too small)", 0);
361 	}
362 	for (;;) {
363 		fd_set ibits, obits, ebits, *omask;
364 
365 		FD_ZERO(&ebits);
366 		FD_ZERO(&ibits);
367 		FD_ZERO(&obits);
368 		omask = (fd_set *)NULL;
369 		if (fcc) {
370 			FD_SET(p, &obits);
371 			omask = &obits;
372 		} else
373 			FD_SET(f, &ibits);
374 		if (pcc >= 0)
375 			if (pcc) {
376 				FD_SET(f, &obits);
377 				omask = &obits;
378 			} else
379 				FD_SET(p, &ibits);
380 		FD_SET(p, &ebits);
381 		if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) {
382 			if (errno == EINTR)
383 				continue;
384 			fatal(f, "select", 1);
385 		}
386 		if (n == 0) {
387 			/* shouldn't happen... */
388 			sleep(5);
389 			continue;
390 		}
391 #define	pkcontrol(c)	((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
392 		if (FD_ISSET(p, &ebits)) {
393 			cc = read(p, &cntl, 1);
394 			if (cc == 1 && pkcontrol(cntl)) {
395 				cntl |= oobdata[0];
396 				send(f, &cntl, 1, MSG_OOB);
397 				if (cntl & TIOCPKT_FLUSHWRITE) {
398 					pcc = 0;
399 					FD_CLR(p, &ibits);
400 				}
401 			}
402 		}
403 		if (FD_ISSET(f, &ibits)) {
404 #ifdef	CRYPT
405 #ifdef	KERBEROS
406 			if (doencrypt)
407 				fcc = des_read(f, fibuf, sizeof(fibuf));
408 			else
409 #endif
410 #endif
411 				fcc = read(f, fibuf, sizeof(fibuf));
412 			if (fcc < 0 && errno == EWOULDBLOCK)
413 				fcc = 0;
414 			else {
415 				register char *cp;
416 				int left, n;
417 
418 				if (fcc <= 0)
419 					break;
420 				fbp = fibuf;
421 
422 			top:
423 				for (cp = fibuf; cp < fibuf+fcc-1; cp++)
424 					if (cp[0] == magic[0] &&
425 					    cp[1] == magic[1]) {
426 						left = fcc - (cp-fibuf);
427 						n = control(p, cp, left);
428 						if (n) {
429 							left -= n;
430 							if (left > 0)
431 								bcopy(cp+n, cp, left);
432 							fcc -= n;
433 							goto top; /* n^2 */
434 						}
435 					}
436 				FD_SET(p, &obits);		/* try write */
437 			}
438 		}
439 
440 		if (FD_ISSET(p, &obits) && fcc > 0) {
441 			cc = write(p, fbp, fcc);
442 			if (cc > 0) {
443 				fcc -= cc;
444 				fbp += cc;
445 			}
446 		}
447 
448 		if (FD_ISSET(p, &ibits)) {
449 			pcc = read(p, pibuf, sizeof (pibuf));
450 			pbp = pibuf;
451 			if (pcc < 0 && errno == EWOULDBLOCK)
452 				pcc = 0;
453 			else if (pcc <= 0)
454 				break;
455 			else if (pibuf[0] == 0) {
456 				pbp++, pcc--;
457 #ifdef	CRYPT
458 #ifdef	KERBEROS
459 				if (!doencrypt)
460 #endif
461 #endif
462 					FD_SET(f, &obits);	/* try write */
463 			} else {
464 				if (pkcontrol(pibuf[0])) {
465 					pibuf[0] |= oobdata[0];
466 					send(f, &pibuf[0], 1, MSG_OOB);
467 				}
468 				pcc = 0;
469 			}
470 		}
471 		if ((FD_ISSET(f, &obits)) && pcc > 0) {
472 #ifdef	CRYPT
473 #ifdef	KERBEROS
474 			if (doencrypt)
475 				cc = des_write(f, pbp, pcc);
476 			else
477 #endif
478 #endif
479 				cc = write(f, pbp, pcc);
480 			if (cc < 0 && errno == EWOULDBLOCK) {
481 				/*
482 				 * This happens when we try write after read
483 				 * from p, but some old kernels balk at large
484 				 * writes even when select returns true.
485 				 */
486 				if (!FD_ISSET(p, &ibits))
487 					sleep(5);
488 				continue;
489 			}
490 			if (cc > 0) {
491 				pcc -= cc;
492 				pbp += cc;
493 			}
494 		}
495 	}
496 }
497 
498 void
499 cleanup(signo)
500 	int signo;
501 {
502 	char *p;
503 
504 	p = line + sizeof(_PATH_DEV) - 1;
505 	if (logout(p))
506 		logwtmp(p, "", "");
507 	(void)chmod(line, 0666);
508 	(void)chown(line, 0, 0);
509 	*p = 'p';
510 	(void)chmod(line, 0666);
511 	(void)chown(line, 0, 0);
512 	shutdown(netf, 2);
513 	exit(1);
514 }
515 
516 void
517 fatal(f, msg, syserr)
518 	int f;
519 	char *msg;
520 	int syserr;
521 {
522 	int len;
523 	char buf[BUFSIZ], *bp = buf;
524 
525 	/*
526 	 * Prepend binary one to message if we haven't sent
527 	 * the magic null as confirmation.
528 	 */
529 	if (!confirmed)
530 		*bp++ = '\01';		/* error indicator */
531 	if (syserr)
532 		len = sprintf(bp, "rlogind: %s: %s.\r\n",
533 		    msg, strerror(errno));
534 	else
535 		len = sprintf(bp, "rlogind: %s.\r\n", msg);
536 	(void) write(f, buf, bp + len - buf);
537 	exit(1);
538 }
539 
540 int
541 do_rlogin(dest)
542 	struct sockaddr_in *dest;
543 {
544 	getstr(rusername, sizeof(rusername), "remuser too long");
545 	getstr(lusername, sizeof(lusername), "locuser too long");
546 	getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
547 
548 	pwd = getpwnam(lusername);
549 	if (pwd == NULL)
550 		return (-1);
551 	if (pwd->pw_uid == 0)
552 		return (-1);
553 	/* XXX why don't we syslog() failure? */
554 	return (iruserok(dest->sin_addr.s_addr, 0, rusername, lusername));
555 }
556 
557 void
558 getstr(buf, cnt, errmsg)
559 	char *buf;
560 	int cnt;
561 	char *errmsg;
562 {
563 	char c;
564 
565 	do {
566 		if (read(0, &c, 1) != 1)
567 			exit(1);
568 		if (--cnt < 0)
569 			fatal(STDOUT_FILENO, errmsg, 0);
570 		*buf++ = c;
571 	} while (c != 0);
572 }
573 
574 extern	char **environ;
575 
576 void
577 setup_term(fd)
578 	int fd;
579 {
580 	register char *cp = index(term+ENVSIZE, '/');
581 	char *speed;
582 	struct termios tt;
583 
584 #ifndef notyet
585 	tcgetattr(fd, &tt);
586 	if (cp) {
587 		*cp++ = '\0';
588 		speed = cp;
589 		cp = index(speed, '/');
590 		if (cp)
591 			*cp++ = '\0';
592 		cfsetspeed(&tt, atoi(speed));
593 	}
594 
595 	tt.c_iflag = TTYDEF_IFLAG;
596 	tt.c_oflag = TTYDEF_OFLAG;
597 	tt.c_lflag = TTYDEF_LFLAG;
598 	tcsetattr(fd, TCSAFLUSH, &tt);
599 #else
600 	if (cp) {
601 		*cp++ = '\0';
602 		speed = cp;
603 		cp = index(speed, '/');
604 		if (cp)
605 			*cp++ = '\0';
606 		tcgetattr(fd, &tt);
607 		cfsetspeed(&tt, atoi(speed));
608 		tcsetattr(fd, TCSAFLUSH, &tt);
609 	}
610 #endif
611 
612 	env[0] = term;
613 	env[1] = 0;
614 	environ = env;
615 }
616 
617 #ifdef	KERBEROS
618 #define	VERSION_SIZE	9
619 
620 /*
621  * Do the remote kerberos login to the named host with the
622  * given inet address
623  *
624  * Return 0 on valid authorization
625  * Return -1 on valid authentication, no authorization
626  * Return >0 for error conditions
627  */
628 int
629 do_krb_login(dest)
630 	struct sockaddr_in *dest;
631 {
632 	int rc;
633 	char instance[INST_SZ], version[VERSION_SIZE];
634 	long authopts = 0L;	/* !mutual */
635 	struct sockaddr_in faddr;
636 
637 	kdata = (AUTH_DAT *) auth_buf;
638 	ticket = (KTEXT) tick_buf;
639 
640 	instance[0] = '*';
641 	instance[1] = '\0';
642 
643 #ifdef	CRYPT
644 	if (doencrypt) {
645 		rc = sizeof(faddr);
646 		if (getsockname(0, (struct sockaddr *)&faddr, &rc))
647 			return (-1);
648 		authopts = KOPT_DO_MUTUAL;
649 		rc = krb_recvauth(
650 			authopts, 0,
651 			ticket, "rcmd",
652 			instance, dest, &faddr,
653 			kdata, "", schedule, version);
654 		 des_set_key(kdata->session, schedule);
655 
656 	} else
657 #endif
658 		rc = krb_recvauth(
659 			authopts, 0,
660 			ticket, "rcmd",
661 			instance, dest, (struct sockaddr_in *) 0,
662 			kdata, "", (bit_64 *) 0, version);
663 
664 	if (rc != KSUCCESS)
665 		return (rc);
666 
667 	getstr(lusername, sizeof(lusername), "locuser");
668 	/* get the "cmd" in the rcmd protocol */
669 	getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type");
670 
671 	pwd = getpwnam(lusername);
672 	if (pwd == NULL)
673 		return (-1);
674 
675 	/* returns nonzero for no access */
676 	if (kuserok(kdata, lusername) != 0)
677 		return (-1);
678 
679 	return (0);
680 
681 }
682 #endif /* KERBEROS */
683 
684 void
685 usage()
686 {
687 #ifdef KERBEROS
688 	syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]");
689 #else
690 	syslog(LOG_ERR, "usage: rlogind [-aln]");
691 #endif
692 }
693 
694 /*
695  * Check whether host h is in our local domain,
696  * defined as sharing the last two components of the domain part,
697  * or the entire domain part if the local domain has only one component.
698  * If either name is unqualified (contains no '.'),
699  * assume that the host is local, as it will be
700  * interpreted as such.
701  */
702 int
703 local_domain(h)
704 	char *h;
705 {
706 	char localhost[MAXHOSTNAMELEN];
707 	char *p1, *p2;
708 
709 	localhost[0] = 0;
710 	(void) gethostname(localhost, sizeof(localhost));
711 	p1 = topdomain(localhost);
712 	p2 = topdomain(h);
713 	if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
714 		return (1);
715 	return (0);
716 }
717 
718 char *
719 topdomain(h)
720 	char *h;
721 {
722 	register char *p;
723 	char *maybe = NULL;
724 	int dots = 0;
725 
726 	for (p = h + strlen(h); p >= h; p--) {
727 		if (*p == '.') {
728 			if (++dots == 2)
729 				return (p);
730 			maybe = p;
731 		}
732 	}
733 	return (maybe);
734 }
735