xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 36631)
1 /*
2  * Copyright (c) 1983, 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1983, 1988 The Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)rlogind.c	5.26 (Berkeley) 01/25/89";
26 #endif /* not lint */
27 
28 /*
29  * remote login server:
30  *	\0
31  *	remuser\0
32  *	locuser\0
33  *	terminal_type/speed\0
34  *	data
35  */
36 
37 #include <stdio.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/socket.h>
41 #include <sys/wait.h>
42 #include <sys/file.h>
43 #include <sys/param.h>
44 
45 #include <netinet/in.h>
46 
47 #include <errno.h>
48 #include <pwd.h>
49 #include <signal.h>
50 #include <sys/ioctl.h>
51 #include <sys/termios.h>
52 #include <stdio.h>
53 #include <netdb.h>
54 #include <syslog.h>
55 #include <strings.h>
56 
57 #ifndef TIOCPKT_WINDOW
58 #define TIOCPKT_WINDOW 0x80
59 #endif
60 
61 #ifdef	KERBEROS
62 #include <kerberos/krb.h>
63 #define	SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
64 
65 AUTH_DAT	*kdata;
66 KTEXT		ticket;
67 u_char		auth_buf[sizeof(AUTH_DAT)];
68 u_char		tick_buf[sizeof(KTEXT_ST)];
69 Key_schedule	schedule;
70 int		encrypt, retval, use_kerberos = 0, vacuous = 0;
71 int		do_krb_login();
72 
73 #define		OLD_RCMD		0x00
74 #define		KERB_RCMD		0x00
75 #define		KERB_RCMD_MUTUAL	0x03
76 
77 #define		ARGSTR			"lnkv"
78 #else
79 #define		ARGSTR			"ln"
80 #endif	/* KERBEROS */
81 
82 char	*env[2];
83 #define	NMAX 30
84 char	lusername[NMAX+1], rusername[NMAX+1];
85 static	char term[64] = "TERM=";
86 #define	ENVSIZE	(sizeof("TERM=")-1)	/* skip null for concatenation */
87 int	keepalive = 1;
88 
89 #define	SUPERUSER(pwd)	((pwd)->pw_uid == 0)
90 
91 extern	int errno;
92 int	reapchild();
93 struct	passwd *getpwnam(), *pwd;
94 char	*malloc();
95 
96 main(argc, argv)
97 	int argc;
98 	char **argv;
99 {
100 	extern int opterr, optind, _check_rhosts_file;
101 	int ch;
102 	int on = 1, fromlen;
103 	struct sockaddr_in from;
104 
105 	openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
106 
107 	opterr = 0;
108 	while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
109 		switch (ch) {
110 		case 'l':
111 			_check_rhosts_file = 0;
112 			break;
113 		case 'n':
114 			keepalive = 0;
115 			break;
116 #ifdef KERBEROS
117 		case 'k':
118 			use_kerberos = 1;
119 			break;
120 		case 'v':
121 			vacuous = 1;
122 			break;
123 #endif
124 		case '?':
125 		default:
126 			usage();
127 			break;
128 		}
129 	argc -= optind;
130 	argv += optind;
131 
132 #ifdef	KERBEROS
133 	if (use_kerberos && vacuous) {
134 		fprintf(stderr, "%s: only one of -k and -v allowed\n", argv[0]);
135 		usage();
136 		exit(1);
137 	}
138 #endif
139 	fromlen = sizeof (from);
140 	if (getpeername(0, &from, &fromlen) < 0) {
141 		syslog(LOG_ERR,"Couldn't get peer name of remote host: %m");
142 		exit(1);
143 	}
144 	if (keepalive &&
145 	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
146 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
147 	doit(0, &from);
148 }
149 
150 int	child;
151 int	cleanup();
152 int	netf;
153 char	*line;
154 extern	char	*inet_ntoa();
155 
156 struct winsize win = { 0, 0, 0, 0 };
157 
158 
159 doit(f, fromp)
160 	int f;
161 	struct sockaddr_in *fromp;
162 {
163 	int i, p, t, pid, on = 1;
164 	int authenticated = 0, hostok = 0;
165 	register struct hostent *hp;
166 	char remotehost[2 * MAXHOSTNAMELEN + 1];
167 	struct hostent hostent;
168 	char c;
169 
170 	alarm(60);
171 	read(f, &c, 1);
172 
173 #ifdef	KERBEROS
174 	/*
175 	 * XXX 1st char tells us which client we're talking to
176 	 */
177 	switch (c) {
178 
179 	case OLD_RCMD:		/* OLD_RCMD is same as KERB_RCMD */
180 		if (vacuous)
181 			fatal(f, "Remote host requires Kerberos authentication");
182 		break;
183 
184 	case KERB_RCMD_MUTUAL:
185 		encrypt = 1;
186 		break;
187 
188 	default:
189 		fatal(f, "Remote protocol error");
190 	}
191 #else
192 	if (c != 0)
193 		exit(1);
194 #endif
195 
196 	alarm(0);
197 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
198 	hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
199 		fromp->sin_family);
200 	if (hp == 0) {
201 		/*
202 		 * Only the name is used below.
203 		 */
204 		hp = &hostent;
205 		hp->h_name = inet_ntoa(fromp->sin_addr);
206 	} else if (local_domain(hp->h_name)) {
207 		/*
208 		 * If name returned by gethostbyaddr is in our domain,
209 		 * attempt to verify that we haven't been fooled by someone
210 		 * in a remote net; look up the name and check that this
211 		 * address corresponds to the name.
212 		 */
213 		strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
214 		remotehost[sizeof(remotehost) - 1] = 0;
215 		hp = gethostbyname(remotehost);
216 		if (hp)
217 		    for (; hp->h_addr_list[0]; hp->h_addr_list++) {
218 			if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr,
219 			    sizeof(fromp->sin_addr))) {
220 				hostok++;
221 				break;
222 			}
223 		}
224 	}
225 
226 #ifdef	KERBEROS
227 	if (use_kerberos) {
228 		retval = do_krb_login(hp->h_name, fromp, encrypt);
229 		write(f, &c, 1);
230 		if (retval == 0)
231 			authenticated++;
232 		else if (retval > 0)
233 			fatal(f, krb_err_txt[retval]);
234 	} else
235 #endif
236 	if (fromp->sin_family != AF_INET ||
237 	    fromp->sin_port >= IPPORT_RESERVED ||
238 	    fromp->sin_port < IPPORT_RESERVED/2) {
239 		syslog(LOG_NOTICE, "Connection from %s on illegal port",
240 			inet_ntoa(fromp->sin_addr));
241 		fatal(f, "Permission denied");
242 	} else {
243 		write(f, "", 1);
244 
245 		if (do_rlogin(hp->h_name) == 0) {
246 			if (hostok)
247 			    authenticated++;
248 			else
249 			    write(f, "rlogind: Host address mismatch.\r\n",
250 			     sizeof("rlogind: Host address mismatch.\r\n") - 1);
251 		}
252 	}
253 
254 	for (c = 'p'; c <= 's'; c++) {
255 		struct stat stb;
256 		line = "/dev/ptyXX";
257 		line[strlen("/dev/pty")] = c;
258 		line[strlen("/dev/ptyp")] = '0';
259 		if (stat(line, &stb) < 0)
260 			break;
261 		for (i = 0; i < 16; i++) {
262 			line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
263 			p = open(line, O_RDWR);
264 			if (p > 0)
265 				goto gotpty;
266 		}
267 	}
268 	fatal(f, "Out of ptys");
269 	/*NOTREACHED*/
270 gotpty:
271 	(void) ioctl(p, TIOCSWINSZ, &win);
272 	netf = f;
273 	line[strlen("/dev/")] = 't';
274 	t = open(line, O_RDWR);
275 	if (t < 0)
276 		fatalperror(f, line);
277 	if (fchmod(t, 0))
278 		fatalperror(f, line);
279 	(void)signal(SIGHUP, SIG_IGN);
280 	vhangup();
281 	(void)signal(SIGHUP, SIG_DFL);
282 	t = open(line, O_RDWR);
283 	if (t < 0)
284 		fatalperror(f, line);
285 	setup_term(t);
286 #ifdef DEBUG
287 	{
288 		int tt = open("/dev/tty", O_RDWR);
289 		if (tt > 0) {
290 			(void)ioctl(tt, TIOCNOTTY, 0);
291 			(void)close(tt);
292 		}
293 	}
294 #endif
295 	pid = fork();
296 	if (pid < 0)
297 		fatalperror(f, "");
298 	if (pid == 0) {
299 		if (setsid() < 0)
300 			fatalperror(f, "setsid");
301 		if (ioctl(t, TIOCSCTTY, 0) < 0)
302 			fatalperror(f, "ioctl(sctty)");
303 		close(f), close(p);
304 		dup2(t, 0), dup2(t, 1), dup2(t, 2);
305 		close(t);
306 		if (authenticated)
307 			execl("/bin/login", "login", "-p",
308 			    "-h", hp->h_name, "-f", lusername, 0);
309 		else
310 			execl("/bin/login", "login", "-p",
311 			    "-h", hp->h_name, lusername, 0);
312 		fatalperror(2, "/bin/login");
313 		/*NOTREACHED*/
314 	}
315 	close(t);
316 
317 #ifdef	KERBEROS
318 	/*
319 	 * If encrypted, don't turn on NBIO or the des read/write
320 	 * routines will croak.
321 	 */
322 
323 	if (encrypt)
324 		(void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE));
325 	else
326 #endif
327 		ioctl(f, FIONBIO, &on);
328 	ioctl(p, FIONBIO, &on);
329 	ioctl(p, TIOCPKT, &on);
330 	signal(SIGTSTP, SIG_IGN);
331 	signal(SIGCHLD, cleanup);
332 	setpgrp(0, 0);
333 	protocol(f, p);
334 	signal(SIGCHLD, SIG_IGN);
335 	cleanup();
336 }
337 
338 char	magic[2] = { 0377, 0377 };
339 char	oobdata[] = {TIOCPKT_WINDOW};
340 
341 /*
342  * Handle a "control" request (signaled by magic being present)
343  * in the data stream.  For now, we are only willing to handle
344  * window size changes.
345  */
346 control(pty, cp, n)
347 	int pty;
348 	char *cp;
349 	int n;
350 {
351 	struct winsize w;
352 
353 	if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
354 		return (0);
355 	oobdata[0] &= ~TIOCPKT_WINDOW;	/* we know he heard */
356 	bcopy(cp+4, (char *)&w, sizeof(w));
357 	w.ws_row = ntohs(w.ws_row);
358 	w.ws_col = ntohs(w.ws_col);
359 	w.ws_xpixel = ntohs(w.ws_xpixel);
360 	w.ws_ypixel = ntohs(w.ws_ypixel);
361 	(void)ioctl(pty, TIOCSWINSZ, &w);
362 	return (4+sizeof (w));
363 }
364 
365 /*
366  * rlogin "protocol" machine.
367  */
368 protocol(f, p)
369 	int f, p;
370 {
371 	char pibuf[1024], fibuf[1024], *pbp, *fbp;
372 	register pcc = 0, fcc = 0;
373 	int cc, nfd, pmask, fmask;
374 	char cntl;
375 
376 	/*
377 	 * Must ignore SIGTTOU, otherwise we'll stop
378 	 * when we try and set slave pty's window shape
379 	 * (our controlling tty is the master pty).
380 	 */
381 	(void) signal(SIGTTOU, SIG_IGN);
382 	send(f, oobdata, 1, MSG_OOB);	/* indicate new rlogin */
383 	if (f > p)
384 		nfd = f + 1;
385 	else
386 		nfd = p + 1;
387 	fmask = 1 << f;
388 	pmask = 1 << p;
389 	for (;;) {
390 		int ibits, obits, ebits;
391 
392 		ibits = 0;
393 		obits = 0;
394 		if (fcc)
395 			obits |= pmask;
396 		else
397 			ibits |= fmask;
398 		if (pcc >= 0)
399 			if (pcc)
400 				obits |= fmask;
401 			else
402 				ibits |= pmask;
403 		ebits = pmask;
404 		if (select(nfd, &ibits, obits ? &obits : (int *)NULL,
405 		    &ebits, 0) < 0) {
406 			if (errno == EINTR)
407 				continue;
408 			fatalperror(f, "select");
409 		}
410 		if (ibits == 0 && obits == 0 && ebits == 0) {
411 			/* shouldn't happen... */
412 			sleep(5);
413 			continue;
414 		}
415 #define	pkcontrol(c)	((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
416 		if (ebits & pmask) {
417 			cc = read(p, &cntl, 1);
418 			if (cc == 1 && pkcontrol(cntl)) {
419 				cntl |= oobdata[0];
420 				send(f, &cntl, 1, MSG_OOB);
421 				if (cntl & TIOCPKT_FLUSHWRITE) {
422 					pcc = 0;
423 					ibits &= ~pmask;
424 				}
425 			}
426 		}
427 		if (ibits & fmask) {
428 #ifdef	KERBEROS
429 			if (encrypt)
430 				fcc = des_read(f, fibuf, sizeof(fibuf));
431 			else
432 #endif
433 				fcc = read(f, fibuf, sizeof(fibuf));
434 			if (fcc < 0 && errno == EWOULDBLOCK)
435 				fcc = 0;
436 			else {
437 				register char *cp;
438 				int left, n;
439 
440 				if (fcc <= 0)
441 					break;
442 				fbp = fibuf;
443 
444 			top:
445 				for (cp = fibuf; cp < fibuf+fcc-1; cp++)
446 					if (cp[0] == magic[0] &&
447 					    cp[1] == magic[1]) {
448 						left = fcc - (cp-fibuf);
449 						n = control(p, cp, left);
450 						if (n) {
451 							left -= n;
452 							if (left > 0)
453 								bcopy(cp+n, cp, left);
454 							fcc -= n;
455 							goto top; /* n^2 */
456 						}
457 					}
458 				obits |= pmask;		/* try write */
459 			}
460 		}
461 
462 		if ((obits & pmask) && fcc > 0) {
463 			cc = write(p, fbp, fcc);
464 			if (cc > 0) {
465 				fcc -= cc;
466 				fbp += cc;
467 			}
468 		}
469 
470 		if (ibits & pmask) {
471 			pcc = read(p, pibuf, sizeof (pibuf));
472 			pbp = pibuf;
473 			if (pcc < 0 && errno == EWOULDBLOCK)
474 				pcc = 0;
475 			else if (pcc <= 0)
476 				break;
477 			else if (pibuf[0] == 0) {
478 				pbp++, pcc--;
479 #ifdef	KERBEROS
480 				if (!encrypt)
481 #endif
482 					obits |= fmask;	/* try a write */
483 			} else {
484 				if (pkcontrol(pibuf[0])) {
485 					pibuf[0] |= oobdata[0];
486 					send(f, &pibuf[0], 1, MSG_OOB);
487 				}
488 				pcc = 0;
489 			}
490 		}
491 		if ((obits & fmask) && pcc > 0) {
492 #ifdef	KERBEROS
493 			if (encrypt)
494 				cc = des_write(f, pbp, pcc);
495 			else
496 #endif
497 				cc = write(f, pbp, pcc);
498 			if (cc < 0 && errno == EWOULDBLOCK) {
499 				/* also shouldn't happen */
500 				sleep(5);
501 				continue;
502 			}
503 			if (cc > 0) {
504 				pcc -= cc;
505 				pbp += cc;
506 			}
507 		}
508 	}
509 }
510 
511 cleanup()
512 {
513 	char *p;
514 
515 	p = line + sizeof("/dev/") - 1;
516 	if (logout(p))
517 		logwtmp(p, "", "");
518 	(void)chmod(line, 0666);
519 	(void)chown(line, 0, 0);
520 	*p = 'p';
521 	(void)chmod(line, 0666);
522 	(void)chown(line, 0, 0);
523 	shutdown(netf, 2);
524 	exit(1);
525 }
526 
527 fatal(f, msg)
528 	int f;
529 	char *msg;
530 {
531 	char buf[BUFSIZ];
532 
533 	buf[0] = '\01';		/* error indicator */
534 	(void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
535 	(void) write(f, buf, strlen(buf));
536 	exit(1);
537 }
538 
539 fatalperror(f, msg)
540 	int f;
541 	char *msg;
542 {
543 	char buf[BUFSIZ];
544 	extern int sys_nerr;
545 	extern char *sys_errlist[];
546 
547 	if ((unsigned)errno < sys_nerr)
548 		(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
549 	else
550 		(void) sprintf(buf, "%s: Error %d", msg, errno);
551 	fatal(f, buf);
552 }
553 
554 do_rlogin(host)
555 	char *host;
556 {
557 
558 	getstr(rusername, sizeof(rusername), "remuser too long");
559 	getstr(lusername, sizeof(lusername), "locuser too long");
560 	getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
561 
562 	if (getuid())
563 		return(-1);
564 	pwd = getpwnam(lusername);
565 	if (pwd == NULL)
566 		return(-1);
567 	return(ruserok(host, SUPERUSER(pwd), rusername, lusername));
568 }
569 
570 
571 getstr(buf, cnt, errmsg)
572 	char *buf;
573 	int cnt;
574 	char *errmsg;
575 {
576 	char c;
577 
578 	do {
579 		if (read(0, &c, 1) != 1)
580 			exit(1);
581 		if (--cnt < 0)
582 			fatal(1, errmsg);
583 		*buf++ = c;
584 	} while (c != 0);
585 }
586 
587 extern	char **environ;
588 
589 setup_term(fd)
590 	int fd;
591 {
592 	struct termios tt;
593 	register char *cp = index(term+ENVSIZE, '/');
594 	char *speed;
595 
596 	tcgetattr(fd, &tt);
597 	if (cp) {
598 		*cp++ = '\0';
599 		speed = cp;
600 		cp = index(speed, '/');
601 		if (cp)
602 			*cp++ = '\0';
603 		cfsetspeed(&tt, atoi(speed));
604 	}
605 	tt.c_iflag = BRKINT|ICRNL|IXON|ISTRIP|IEXTEN|IMAXBEL;
606 	tt.c_oflag = OPOST|ONLCR|OXTABS;
607 	tt.c_lflag = ISIG|ICANON|ECHO;
608 	tcsetattr(fd, TCSADFLUSH, &tt);
609 
610 	env[0] = term;
611 	env[1] = 0;
612 	environ = env;
613 }
614 
615 #ifdef	KERBEROS
616 #define	VERSION_SIZE	9
617 
618 /*
619  * Do the remote kerberos login to the named host with the
620  * given inet address
621  *
622  * Return 0 on valid authorization
623  * Return -1 on valid authentication, no authorization
624  * Return >0 for error conditions
625  */
626 do_krb_login(host, dest, encrypt)
627 	char *host;
628 	struct sockaddr_in *dest;
629 	int encrypt;
630 {
631 	int rc;
632 	char instance[INST_SZ], version[VERSION_SIZE];
633 	long authopts = 0L;	/* !mutual */
634 	struct sockaddr_in faddr;
635 
636 	if (getuid())
637 		return(KFAILURE);
638 
639 	kdata = (AUTH_DAT *) auth_buf;
640 	ticket = (KTEXT) tick_buf;
641 	strcpy(instance, "*");
642 
643 	if (encrypt) {
644 		rc = sizeof(faddr);
645 		if (getsockname(0, &faddr, &rc))
646 			return(-1);
647 		authopts = KOPT_DO_MUTUAL;
648 		rc = krb_recvauth(
649 			authopts, 0,
650 			ticket, "rcmd",
651 			instance, dest, &faddr,
652 			kdata, "", schedule, version);
653 		 des_set_key(kdata->session, schedule);
654 
655 	} else {
656 		rc = krb_recvauth(
657 			authopts, 0,
658 			ticket, "rcmd",
659 			instance, dest, (struct sockaddr_in *) 0,
660 			kdata, "", (bit_64 *) 0, version);
661 	}
662 
663 	if (rc != KSUCCESS)
664 		return(rc);
665 
666 	if ((rc = krb_kntoln(kdata, rusername)) != KSUCCESS)
667 		return(rc);
668 
669 	getstr(lusername, sizeof(lusername), "locuser");
670 	/* get the "cmd" in the rcmd protocol */
671 	getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type");
672 
673 	pwd = getpwnam(lusername);
674 	if (pwd == NULL)
675 		return(-1);
676 
677 	/* returns nonzero for no access */
678 	/* return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); */
679 	if (kuserok(kdata,lusername) != 0)
680 		return(-1);
681 
682 	return(0);
683 
684 }
685 
686 #endif /* KERBEROS */
687 
688 usage()
689 {
690 #ifdef	KERBEROS
691 	syslog(LOG_ERR, "usage: rlogind [-k | -v] [-l] [-n]");
692 #else
693 	syslog(LOG_ERR, "usage: rlogind [-l] [-n]");
694 #endif
695 }
696 
697 /*
698  * Check whether host h is in our local domain,
699  * as determined by the part of the name following
700  * the first '.' in its name and in ours.
701  * If either name is unqualified (contains no '.'),
702  * assume that the host is local, as it will be
703  * interpreted as such.
704  */
705 local_domain(h)
706 	char *h;
707 {
708 	char localhost[MAXHOSTNAMELEN];
709 	char *p1, *p2 = index(h, '.');
710 
711 	(void) gethostname(localhost, sizeof(localhost));
712 	p1 = index(localhost, '.');
713 	if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
714 		return(1);
715 	return(0);
716 }
717