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