144262Sbostic /*-
261877Sbostic  * Copyright (c) 1990, 1993
361877Sbostic  *	The Regents of the University of California.  All rights reserved.
444262Sbostic  *
544262Sbostic  * %sccs.include.redist.c%
644262Sbostic  */
744262Sbostic 
838272Ssam #ifndef lint
961877Sbostic static char copyright[] =
1061877Sbostic "@(#) Copyright (c) 1990, 1993\n\
1161877Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1244262Sbostic #endif /* not lint */
1344262Sbostic 
1444262Sbostic #ifndef lint
15*65967Scgd static char sccsid[] = "@(#)sliplogin.c	8.2 (Berkeley) 02/01/94";
1644262Sbostic #endif /* not lint */
1744262Sbostic 
1838272Ssam /*
1938272Ssam  * sliplogin.c
2038373Skarels  * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!]
2138272Ssam  *
2238272Ssam  * This program initializes its own tty port to be an async TCP/IP interface.
2344851Strent  * It sets the line discipline to slip, invokes a shell script to initialize
2444851Strent  * the network interface, then pauses forever waiting for hangup.
2538272Ssam  *
2638272Ssam  * It is a remote descendant of several similar programs with incestuous ties:
2738272Ssam  * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL.
2838272Ssam  * - slattach, probably by Rick Adams but touched by countless hordes.
2938272Ssam  * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it.
3038272Ssam  *
3144851Strent  * There are two forms of usage:
3238272Ssam  *
3338272Ssam  * "sliplogin"
3446400Skarels  * Invoked simply as "sliplogin", the program looks up the username
3546400Skarels  * in the file /etc/slip.hosts.
3646400Skarels  * If an entry is found, the line on fd0 is configured for SLIP operation
3738272Ssam  * as specified in the file.
3838272Ssam  *
3946400Skarels  * "sliplogin IPhostlogin </dev/ttyb"
4038272Ssam  * Invoked by root with a username, the name is looked up in the
4146400Skarels  * /etc/slip.hosts file and if found fd0 is configured as in case 1.
4238272Ssam  */
4338272Ssam 
4444851Strent #include <sys/param.h>
4538272Ssam #include <sys/socket.h>
4644860Sbostic #include <sys/signal.h>
4738272Ssam #include <sys/file.h>
4838272Ssam #include <sys/syslog.h>
4938272Ssam #include <netdb.h>
5044860Sbostic 
5146400Skarels #if BSD >= 199006
5246400Skarels #define POSIX
5344851Strent #endif
5446400Skarels #ifdef POSIX
5544851Strent #include <sys/termios.h>
5646400Skarels #include <sys/ioctl.h>
5738272Ssam #include <ttyent.h>
5846400Skarels #else
5946400Skarels #include <sgtty.h>
6044851Strent #endif
61*65967Scgd #include <net/slip.h>
6238272Ssam 
6344860Sbostic #include <stdio.h>
6444860Sbostic #include <errno.h>
6544860Sbostic #include <ctype.h>
6644860Sbostic #include <string.h>
6744860Sbostic #include "pathnames.h"
6838372Ssam 
6944851Strent int	unit;
7044851Strent int	speed;
7146400Skarels int	uid;
7244851Strent char	loginargs[BUFSIZ];
7346400Skarels char	loginfile[MAXPATHLEN];
7444851Strent char	loginname[BUFSIZ];
7538272Ssam 
7638272Ssam void
findid(name)7744851Strent findid(name)
7844851Strent 	char *name;
7938272Ssam {
8044851Strent 	FILE *fp;
8144851Strent 	static char slopt[5][16];
8244851Strent 	static char laddr[16];
8344851Strent 	static char raddr[16];
8444851Strent 	static char mask[16];
8544851Strent 	char user[16];
8644851Strent 	int i, j, n;
8738272Ssam 
8844851Strent 	(void)strcpy(loginname, name);
8944860Sbostic 	if ((fp = fopen(_PATH_ACCESS, "r")) == NULL) {
9044860Sbostic 		(void)fprintf(stderr, "sliplogin: %s: %s\n",
9144860Sbostic 		    _PATH_ACCESS, strerror(errno));
9244860Sbostic 		syslog(LOG_ERR, "%s: %m\n", _PATH_ACCESS);
9344860Sbostic 		exit(1);
9444851Strent 	}
9544851Strent 	while (fgets(loginargs, sizeof(loginargs) - 1, fp)) {
9644851Strent 		if (ferror(fp))
9744851Strent 			break;
9844851Strent 		n = sscanf(loginargs, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
9944851Strent                         user, laddr, raddr, mask, slopt[0], slopt[1],
10044851Strent 			slopt[2], slopt[3], slopt[4]);
10144851Strent 		if (user[0] == '#' || isspace(user[0]))
10244851Strent 			continue;
10344851Strent 		if (strcmp(user, name) != 0)
10444851Strent 			continue;
10538272Ssam 
10644851Strent 		/*
10744851Strent 		 * we've found the guy we're looking for -- see if
10844851Strent 		 * there's a login file we can use.  First check for
10944851Strent 		 * one specific to this host.  If none found, try for
11044851Strent 		 * a generic one.
11144851Strent 		 */
11244860Sbostic 		(void)sprintf(loginfile, "%s.%s", _PATH_LOGIN, name);
11346400Skarels 		if (access(loginfile, R_OK|X_OK) != 0) {
11444860Sbostic 			(void)strcpy(loginfile, _PATH_LOGIN);
11544851Strent 			if (access(loginfile, R_OK|X_OK)) {
11644851Strent 				fputs("access denied - no login file\n",
11744851Strent 				      stderr);
11844851Strent 				syslog(LOG_ERR,
11944851Strent 				       "access denied for %s - no %s\n",
12044860Sbostic 				       name, _PATH_LOGIN);
12144851Strent 				exit(5);
12244851Strent 			}
12346400Skarels 		}
12444851Strent 
12544851Strent 		(void) fclose(fp);
12644851Strent 		return;
12744851Strent 	}
12844851Strent 	(void)fprintf(stderr, "SLIP access denied for %s\n", name);
12944851Strent 	syslog(LOG_ERR, "SLIP access denied for %s\n", name);
13044851Strent 	exit(4);
13144851Strent 	/* NOTREACHED */
13238272Ssam }
13338272Ssam 
13444851Strent char *
sigstr(s)13544851Strent sigstr(s)
13644851Strent 	int s;
13744851Strent {
13844851Strent 	static char buf[32];
13938272Ssam 
14044851Strent 	switch (s) {
14144851Strent 	case SIGHUP:	return("HUP");
14244851Strent 	case SIGINT:	return("INT");
14344851Strent 	case SIGQUIT:	return("QUIT");
14444851Strent 	case SIGILL:	return("ILL");
14544851Strent 	case SIGTRAP:	return("TRAP");
14644851Strent 	case SIGIOT:	return("IOT");
14744851Strent 	case SIGEMT:	return("EMT");
14844851Strent 	case SIGFPE:	return("FPE");
14944851Strent 	case SIGKILL:	return("KILL");
15044851Strent 	case SIGBUS:	return("BUS");
15144851Strent 	case SIGSEGV:	return("SEGV");
15244851Strent 	case SIGSYS:	return("SYS");
15344851Strent 	case SIGPIPE:	return("PIPE");
15444851Strent 	case SIGALRM:	return("ALRM");
15544851Strent 	case SIGTERM:	return("TERM");
15644851Strent 	case SIGURG:	return("URG");
15744851Strent 	case SIGSTOP:	return("STOP");
15844851Strent 	case SIGTSTP:	return("TSTP");
15944851Strent 	case SIGCONT:	return("CONT");
16044851Strent 	case SIGCHLD:	return("CHLD");
16144851Strent 	case SIGTTIN:	return("TTIN");
16244851Strent 	case SIGTTOU:	return("TTOU");
16344851Strent 	case SIGIO:	return("IO");
16444851Strent 	case SIGXCPU:	return("XCPU");
16544851Strent 	case SIGXFSZ:	return("XFSZ");
16644851Strent 	case SIGVTALRM:	return("VTALRM");
16744851Strent 	case SIGPROF:	return("PROF");
16844851Strent 	case SIGWINCH:	return("WINCH");
16944851Strent #ifdef SIGLOST
17044851Strent 	case SIGLOST:	return("LOST");
17144851Strent #endif
17244851Strent 	case SIGUSR1:	return("USR1");
17344851Strent 	case SIGUSR2:	return("USR2");
17444851Strent 	}
17544851Strent 	(void)sprintf(buf, "sig %d", s);
17644851Strent 	return(buf);
17744851Strent }
17838272Ssam 
17946929Sbostic void
hup_handler(s)18040016Ssam hup_handler(s)
18140016Ssam 	int s;
18238373Skarels {
18346400Skarels 	char logoutfile[MAXPATHLEN];
18446400Skarels 
18546400Skarels 	(void)sprintf(logoutfile, "%s.%s", _PATH_LOGOUT, loginname);
18646400Skarels 	if (access(logoutfile, R_OK|X_OK) != 0)
18746400Skarels 		(void)strcpy(logoutfile, _PATH_LOGOUT);
18844851Strent 	if (access(logoutfile, R_OK|X_OK) == 0) {
18946400Skarels 		char logincmd[2*MAXPATHLEN+32];
19040016Ssam 
19146400Skarels 		(void) sprintf(logincmd, "%s %d %d %s", logoutfile, unit, speed,
19244851Strent 			      loginargs);
19346400Skarels 		(void) system(logincmd);
19444851Strent 	}
19546400Skarels 	(void) close(0);
19644851Strent 	syslog(LOG_INFO, "closed %s slip unit %d (%s)\n", loginname, unit,
19744851Strent 	       sigstr(s));
19844851Strent 	exit(1);
19944851Strent 	/* NOTREACHED */
20038373Skarels }
20138373Skarels 
main(argc,argv)20238272Ssam main(argc, argv)
20338272Ssam 	int argc;
20438272Ssam 	char *argv[];
20538272Ssam {
20646400Skarels 	int fd, s, ldisc, odisc;
20744851Strent 	char *name;
20846400Skarels #ifdef POSIX
20946400Skarels 	struct termios tios, otios;
21044851Strent #else
21146400Skarels 	struct sgttyb tty, otty;
21244851Strent #endif
21344851Strent 	char logincmd[2*BUFSIZ+32];
21444851Strent 	extern uid_t getuid();
21538272Ssam 
21644851Strent 	if ((name = strrchr(argv[0], '/')) == NULL)
21744851Strent 		name = argv[0];
21838272Ssam 	s = getdtablesize();
21938272Ssam 	for (fd = 3 ; fd < s ; fd++)
22044851Strent 		(void) close(fd);
22144851Strent 	openlog(name, LOG_PID, LOG_DAEMON);
22246400Skarels 	uid = getuid();
22344851Strent 	if (argc > 1) {
22444851Strent 		findid(argv[1]);
22544851Strent 
22640016Ssam 		/*
22740016Ssam 		 * Disassociate from current controlling terminal, if any,
22840016Ssam 		 * and ensure that the slip line is our controlling terminal.
22940016Ssam 		 */
23046400Skarels #ifdef POSIX
23146400Skarels 		if (fork() > 0)
23246400Skarels 			exit(0);
23346400Skarels 		if (setsid() != 0)
23446400Skarels 			perror("setsid");
23544851Strent #else
23640016Ssam 		if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
23744851Strent 			extern char *ttyname();
23844851Strent 
23944851Strent 			(void) ioctl(fd, TIOCNOTTY, (caddr_t)0);
24040016Ssam 			(void) close(fd);
24140016Ssam 			/* open slip tty again to acquire as controlling tty? */
24240016Ssam 			fd = open(ttyname(0), O_RDWR, 0);
24340016Ssam 			if (fd >= 0)
24440016Ssam 				(void) close(fd);
24540016Ssam 		}
24640016Ssam 		(void) setpgrp(0, getpid());
24740016Ssam #endif
24846400Skarels 		if (argc > 2) {
24946400Skarels 			if ((fd = open(argv[2], O_RDWR)) == -1) {
25046400Skarels 				perror(argv[2]);
25146400Skarels 				exit(2);
25246400Skarels 			}
25346400Skarels 			(void) dup2(fd, 0);
25446400Skarels 			if (fd > 2)
25546400Skarels 				close(fd);
25646400Skarels 		}
25746400Skarels #ifdef TIOCSCTTY
25846400Skarels 		if (ioctl(0, TIOCSCTTY, (caddr_t)0) != 0)
25946400Skarels 			perror("ioctl (TIOCSCTTY)");
26046400Skarels #endif
26144851Strent 	} else {
26246400Skarels 		extern char *getlogin();
26344851Strent 
26446400Skarels 		if ((name = getlogin()) == NULL) {
26544851Strent 			(void) fprintf(stderr, "access denied - no username\n");
26646400Skarels 			syslog(LOG_ERR, "access denied - getlogin returned 0\n");
26744851Strent 			exit(1);
26844851Strent 		}
26944851Strent 		findid(name);
27044851Strent 	}
27144851Strent 	(void) fchmod(0, 0600);
27244851Strent 	(void) fprintf(stderr, "starting slip login for %s\n", loginname);
27346400Skarels #ifdef POSIX
27438272Ssam 	/* set up the line parameters */
27546400Skarels 	if (tcgetattr(0, &tios) < 0) {
27646400Skarels 		syslog(LOG_ERR, "tcgetattr: %m");
27738272Ssam 		exit(1);
27838272Ssam 	}
27940016Ssam 	otios = tios;
28046400Skarels 	cfmakeraw(&tios);
28146400Skarels 	tios.c_iflag &= ~IMAXBEL;
28246400Skarels 	if (tcsetattr(0, TCSAFLUSH, &tios) < 0) {
28346400Skarels 		syslog(LOG_ERR, "tcsetattr: %m");
28438272Ssam 		exit(1);
28538272Ssam 	}
28646400Skarels 	speed = cfgetispeed(&tios);
28744851Strent #else
28844851Strent 	/* set up the line parameters */
28944851Strent 	if (ioctl(0, TIOCGETP, (caddr_t)&tty) < 0) {
29044851Strent 		syslog(LOG_ERR, "ioctl (TIOCGETP): %m");
29144851Strent 		exit(1);
29244851Strent 	}
29344851Strent 	otty = tty;
29444851Strent 	speed = tty.sg_ispeed;
29544851Strent 	tty.sg_flags = RAW | ANYP;
29644851Strent 	if (ioctl(0, TIOCSETP, (caddr_t)&tty) < 0) {
29744851Strent 		syslog(LOG_ERR, "ioctl (TIOCSETP): %m");
29844851Strent 		exit(1);
29944851Strent 	}
30044851Strent #endif
30138373Skarels 	/* find out what ldisc we started with */
30238373Skarels 	if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) {
30338373Skarels 		syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m");
30438373Skarels 		exit(1);
30538373Skarels 	}
30638372Ssam 	ldisc = SLIPDISC;
30738372Ssam 	if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) {
30840016Ssam 		syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
30938272Ssam 		exit(1);
31038272Ssam 	}
31138272Ssam 	/* find out what unit number we were assigned */
31246400Skarels 	if (ioctl(0, SLIOCGUNIT, (caddr_t)&unit) < 0) {
31346684Skarels 		syslog(LOG_ERR, "ioctl (SLIOCGUNIT): %m");
31438272Ssam 		exit(1);
31538272Ssam 	}
31644851Strent 	(void) signal(SIGHUP, hup_handler);
31744851Strent 	(void) signal(SIGTERM, hup_handler);
31844851Strent 
31944851Strent 	syslog(LOG_INFO, "attaching slip unit %d for %s\n", unit, loginname);
32044851Strent 	(void)sprintf(logincmd, "%s %d %d %s", loginfile, unit, speed,
32144851Strent 		      loginargs);
32244851Strent 	/*
32344851Strent 	 * aim stdout and errout at /dev/null so logincmd output won't
32444851Strent 	 * babble into the slip tty line.
32544851Strent 	 */
32646400Skarels 	(void) close(1);
32746929Sbostic 	if ((fd = open(_PATH_DEVNULL, O_WRONLY)) != 1) {
32844851Strent 		if (fd < 0) {
32944851Strent 			syslog(LOG_ERR, "open /dev/null: %m");
33038272Ssam 			exit(1);
33138272Ssam 		}
33246400Skarels 		(void) dup2(fd, 1);
33346400Skarels 		(void) close(fd);
33438272Ssam 	}
33546400Skarels 	(void) dup2(1, 2);
33646400Skarels 
33746400Skarels 	/*
33846400Skarels 	 * Run login and logout scripts as root (real and effective);
33946400Skarels 	 * current route(8) is setuid root, and checks the real uid
34046400Skarels 	 * to see whether changes are allowed (or just "route get").
34146400Skarels 	 */
34246400Skarels 	(void) setuid(0);
34344851Strent 	if (s = system(logincmd)) {
34444851Strent 		syslog(LOG_ERR, "%s login failed: exit status %d from %s",
34544851Strent 		       loginname, s, loginfile);
34644851Strent 		(void) ioctl(0, TIOCSETD, (caddr_t)&odisc);
34744851Strent 		exit(6);
34838272Ssam 	}
34938272Ssam 
35038272Ssam 	/* twiddle thumbs until we get a signal */
35144851Strent 	while (1)
35238272Ssam 		sigpause(0);
35338272Ssam 
35444851Strent 	/* NOTREACHED */
35538272Ssam }
356