144262Sbostic /*-
244262Sbostic  * Copyright (c) 1990 The Regents of the University of California.
344262Sbostic  * All rights reserved.
444262Sbostic  *
544262Sbostic  * %sccs.include.redist.c%
644262Sbostic  */
744262Sbostic 
838272Ssam #ifndef lint
944262Sbostic char copyright[] =
1044262Sbostic "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
1144262Sbostic  All rights reserved.\n";
1244262Sbostic #endif /* not lint */
1344262Sbostic 
1444262Sbostic #ifndef lint
15*44860Sbostic static char sccsid[] = "@(#)sliplogin.c	5.3 (Berkeley) 07/01/90";
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"
3438272Ssam  * Invoked simply as "sliplogin" and a realuid != 0, the program looks up
3538272Ssam  * the uid in /etc/passwd, and then the username in the file /etc/hosts.slip.
3638272Ssam  * If and entry is found, the line on fd0 is configured for SLIP operation
3738272Ssam  * as specified in the file.
3838272Ssam  *
3938272Ssam  * "sliplogin IPhost1 </dev/ttyb"
4038272Ssam  * Invoked by root with a username, the name is looked up in the
4138272Ssam  * /etc/hosts.slip file and if found fd0 is configured as in case 1.
4238272Ssam  */
4338272Ssam 
4444851Strent #include <sys/param.h>
4538272Ssam #include <sys/socket.h>
4638372Ssam #include <sys/ioctl.h>
47*44860Sbostic #include <sys/signal.h>
4838272Ssam #include <sys/file.h>
4938272Ssam #include <sys/syslog.h>
5038272Ssam #include <netdb.h>
51*44860Sbostic 
5244851Strent #if defined(BSD4_4)
5344851Strent #define TERMIOS
5444851Strent #endif
5544851Strent #ifdef TERMIOS
5644851Strent #include <sys/termios.h>
5738272Ssam #include <ttyent.h>
5844851Strent #endif
5944851Strent #include <netinet/in.h>
6044851Strent #include <net/if.h>
6144851Strent #include <net/if_slvar.h>
6238272Ssam 
63*44860Sbostic #include <stdio.h>
64*44860Sbostic #include <errno.h>
65*44860Sbostic #include <ctype.h>
66*44860Sbostic #include <string.h>
67*44860Sbostic #include "pathnames.h"
6838372Ssam 
6944851Strent int	unit;
70*44860Sbostic int	slip_mode;
7144851Strent int	speed;
7244851Strent char	loginargs[BUFSIZ];
7344851Strent char	loginfile[BUFSIZ];
7444851Strent char	logoutfile[BUFSIZ];
7544851Strent char	loginname[BUFSIZ];
7638272Ssam 
7744851Strent struct slip_modes {
7844851Strent 	char	*sm_name;
7944851Strent 	int	sm_value;
8044851Strent }	 modes[] = {
8144851Strent 	"normal",	0,
8244851Strent 	"compress",	SC_COMPRESS,
8344851Strent 	"noicmp",	SC_NOICMP,
8444851Strent 	"autocomp",	SC_AUTOCOMP
8544851Strent };
8638272Ssam 
8738272Ssam void
8844851Strent findid(name)
8944851Strent 	char *name;
9038272Ssam {
9144851Strent 	FILE *fp;
9244851Strent 	static char slopt[5][16];
9344851Strent 	static char laddr[16];
9444851Strent 	static char raddr[16];
9544851Strent 	static char mask[16];
9644851Strent 	char user[16];
9744851Strent 	int i, j, n;
9838272Ssam 
9944851Strent 	(void)strcpy(loginname, name);
100*44860Sbostic 	if ((fp = fopen(_PATH_ACCESS, "r")) == NULL) {
101*44860Sbostic 		(void)fprintf(stderr, "sliplogin: %s: %s\n",
102*44860Sbostic 		    _PATH_ACCESS, strerror(errno));
103*44860Sbostic 		syslog(LOG_ERR, "%s: %m\n", _PATH_ACCESS);
104*44860Sbostic 		exit(1);
10544851Strent 	}
10644851Strent 	while (fgets(loginargs, sizeof(loginargs) - 1, fp)) {
10744851Strent 		if (ferror(fp))
10844851Strent 			break;
10944851Strent 		n = sscanf(loginargs, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
11044851Strent                         user, laddr, raddr, mask, slopt[0], slopt[1],
11144851Strent 			slopt[2], slopt[3], slopt[4]);
11244851Strent 		if (user[0] == '#' || isspace(user[0]))
11344851Strent 			continue;
11444851Strent 		if (strcmp(user, name) != 0)
11544851Strent 			continue;
11638272Ssam 
11744851Strent 		slip_mode = 0;
11844851Strent 		for (i = 0; i < n - 4; i++) {
11944851Strent 			for (j = 0; j < sizeof(modes)/sizeof(struct slip_modes);
12044851Strent 				j++) {
12144851Strent 				if (strcmp(modes[j].sm_name, slopt[i]) == 0) {
12244851Strent 					slip_mode |= modes[j].sm_value;
12344851Strent 					break;
12444851Strent 				}
12544851Strent 			}
12644851Strent 		}
12738272Ssam 
12844851Strent 		/*
12944851Strent 		 * we've found the guy we're looking for -- see if
13044851Strent 		 * there's a login file we can use.  First check for
13144851Strent 		 * one specific to this host.  If none found, try for
13244851Strent 		 * a generic one.
13344851Strent 		 */
134*44860Sbostic 		(void)sprintf(loginfile, "%s.%s", _PATH_LOGIN, name);
13544851Strent 		if (access(loginfile, R_OK|X_OK)) {
136*44860Sbostic 			(void)strcpy(loginfile, _PATH_LOGIN);
137*44860Sbostic 			(void)strcpy(logoutfile, _PATH_LOGOUT);
13844851Strent 			if (access(loginfile, R_OK|X_OK)) {
13944851Strent 				fputs("access denied - no login file\n",
14044851Strent 				      stderr);
14144851Strent 				syslog(LOG_ERR,
14244851Strent 				       "access denied for %s - no %s\n",
143*44860Sbostic 				       name, _PATH_LOGIN);
14444851Strent 				exit(5);
14544851Strent 			}
14644851Strent 		} else
147*44860Sbostic 			(void)sprintf(logoutfile, "%s.%s", _PATH_LOGOUT, name);
14844851Strent 
14944851Strent 		(void) fclose(fp);
15044851Strent 		return;
15144851Strent 	}
15244851Strent 	(void)fprintf(stderr, "SLIP access denied for %s\n", name);
15344851Strent 	syslog(LOG_ERR, "SLIP access denied for %s\n", name);
15444851Strent 	exit(4);
15544851Strent 	/* NOTREACHED */
15638272Ssam }
15738272Ssam 
15844851Strent char *
15944851Strent sigstr(s)
16044851Strent 	int s;
16144851Strent {
16244851Strent 	static char buf[32];
16338272Ssam 
16444851Strent 	switch (s) {
16544851Strent 	case SIGHUP:	return("HUP");
16644851Strent 	case SIGINT:	return("INT");
16744851Strent 	case SIGQUIT:	return("QUIT");
16844851Strent 	case SIGILL:	return("ILL");
16944851Strent 	case SIGTRAP:	return("TRAP");
17044851Strent 	case SIGIOT:	return("IOT");
17144851Strent 	case SIGEMT:	return("EMT");
17244851Strent 	case SIGFPE:	return("FPE");
17344851Strent 	case SIGKILL:	return("KILL");
17444851Strent 	case SIGBUS:	return("BUS");
17544851Strent 	case SIGSEGV:	return("SEGV");
17644851Strent 	case SIGSYS:	return("SYS");
17744851Strent 	case SIGPIPE:	return("PIPE");
17844851Strent 	case SIGALRM:	return("ALRM");
17944851Strent 	case SIGTERM:	return("TERM");
18044851Strent 	case SIGURG:	return("URG");
18144851Strent 	case SIGSTOP:	return("STOP");
18244851Strent 	case SIGTSTP:	return("TSTP");
18344851Strent 	case SIGCONT:	return("CONT");
18444851Strent 	case SIGCHLD:	return("CHLD");
18544851Strent 	case SIGTTIN:	return("TTIN");
18644851Strent 	case SIGTTOU:	return("TTOU");
18744851Strent 	case SIGIO:	return("IO");
18844851Strent 	case SIGXCPU:	return("XCPU");
18944851Strent 	case SIGXFSZ:	return("XFSZ");
19044851Strent 	case SIGVTALRM:	return("VTALRM");
19144851Strent 	case SIGPROF:	return("PROF");
19244851Strent 	case SIGWINCH:	return("WINCH");
19344851Strent #ifdef SIGLOST
19444851Strent 	case SIGLOST:	return("LOST");
19544851Strent #endif
19644851Strent 	case SIGUSR1:	return("USR1");
19744851Strent 	case SIGUSR2:	return("USR2");
19844851Strent 	}
19944851Strent 	(void)sprintf(buf, "sig %d", s);
20044851Strent 	return(buf);
20144851Strent }
20238272Ssam 
20344851Strent int
20440016Ssam hup_handler(s)
20540016Ssam 	int s;
20638373Skarels {
20744851Strent 	if (access(logoutfile, R_OK|X_OK) == 0) {
20844851Strent 		char logincmd[2*BUFSIZ+32];
20940016Ssam 
21044851Strent 		(void)sprintf(logincmd, "%s %d %d %s", logoutfile, unit, speed,
21144851Strent 			      loginargs);
21244851Strent 		(void)system(logincmd);
21344851Strent 	}
21444851Strent 	(void)close(0);
21544851Strent 	syslog(LOG_INFO, "closed %s slip unit %d (%s)\n", loginname, unit,
21644851Strent 	       sigstr(s));
21744851Strent 	exit(1);
21844851Strent 	/* NOTREACHED */
21938373Skarels }
22038373Skarels 
22138272Ssam main(argc, argv)
22238272Ssam 	int argc;
22338272Ssam 	char *argv[];
22438272Ssam {
22538373Skarels 	int	fd, s, ldisc, odisc;
22644851Strent 	char *name;
22744851Strent #ifdef TERMIOS
22838373Skarels 	struct	termios tios, otios;
22944851Strent #else
23044851Strent 	struct	sgttyb tty, otty;
23144851Strent #endif
23244851Strent 	char logincmd[2*BUFSIZ+32];
23344851Strent 	extern uid_t getuid();
23438272Ssam 
23544851Strent 	if ((name = strrchr(argv[0], '/')) == NULL)
23644851Strent 		name = argv[0];
23738272Ssam 	s = getdtablesize();
23838272Ssam 	for (fd = 3 ; fd < s ; fd++)
23944851Strent 		(void) close(fd);
24044851Strent 	openlog(name, LOG_PID, LOG_DAEMON);
24144851Strent 	if (argc > 1) {
24244851Strent 		if (argc > 2) {
24344851Strent 			(void)fprintf(stderr, "Usage: %s loginname\n", argv[0]);
24438272Ssam 			exit(1);
24538272Ssam 		}
24644851Strent 		findid(argv[1]);
24744851Strent 
24840016Ssam 		/*
24940016Ssam 		 * Disassociate from current controlling terminal, if any,
25040016Ssam 		 * and ensure that the slip line is our controlling terminal.
25140016Ssam 		 */
25244851Strent #ifdef TERMIOS
25344851Strent 		(void) setsid();
25444851Strent 		(void) ioctl(0, TIOCSCTTY, (caddr_t)0);
25544851Strent #else
25640016Ssam 		if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
25744851Strent 			extern char *ttyname();
25844851Strent 
25944851Strent 			(void) ioctl(fd, TIOCNOTTY, (caddr_t)0);
26040016Ssam 			(void) close(fd);
26140016Ssam 			/* open slip tty again to acquire as controlling tty? */
26240016Ssam 			fd = open(ttyname(0), O_RDWR, 0);
26340016Ssam 			if (fd >= 0)
26440016Ssam 				(void) close(fd);
26540016Ssam 		}
26640016Ssam 		(void) setpgrp(0, getpid());
26740016Ssam #endif
26844851Strent 	} else {
26944851Strent 		extern char *getenv();
27044851Strent 
27144851Strent 		if ((name = getenv("USER")) == NULL) {
27244851Strent 			(void) fprintf(stderr, "access denied - no username\n");
27344851Strent 			syslog(LOG_ERR, "access denied - no username\n");
27444851Strent 			exit(1);
27544851Strent 		}
27644851Strent 		findid(name);
27744851Strent 	}
27844851Strent 	(void) fchmod(0, 0600);
27944851Strent 	(void) fprintf(stderr, "starting slip login for %s\n", loginname);
28044851Strent #ifdef TERMIOS
28138272Ssam 	/* set up the line parameters */
28240016Ssam 	if (ioctl(0, TIOCGETA, (caddr_t)&tios) < 0) {
28340016Ssam 		syslog(LOG_ERR, "ioctl (TIOCGETA): %m");
28438272Ssam 		exit(1);
28538272Ssam 	}
28640016Ssam 	otios = tios;
28740016Ssam 	tios.c_cflag = CS8|CREAD|HUPCL;
28838272Ssam 	tios.c_iflag = IGNBRK;
28938372Ssam 	tios.c_oflag = tios.c_lflag = 0;
29040016Ssam 	if (ioctl(0, TIOCSETA, (caddr_t)&tios) < 0) {
29140016Ssam 		syslog(LOG_ERR, "ioctl (TIOCSETA) (1): %m");
29238272Ssam 		exit(1);
29338272Ssam 	}
29444851Strent #else
29544851Strent 	/* set up the line parameters */
29644851Strent 	if (ioctl(0, TIOCGETP, (caddr_t)&tty) < 0) {
29744851Strent 		syslog(LOG_ERR, "ioctl (TIOCGETP): %m");
29844851Strent 		exit(1);
29944851Strent 	}
30044851Strent 	otty = tty;
30144851Strent 	speed = tty.sg_ispeed;
30244851Strent 	tty.sg_flags = RAW | ANYP;
30344851Strent 	if (ioctl(0, TIOCSETP, (caddr_t)&tty) < 0) {
30444851Strent 		syslog(LOG_ERR, "ioctl (TIOCSETP): %m");
30544851Strent 		exit(1);
30644851Strent 	}
30744851Strent #endif
30838373Skarels 	/* find out what ldisc we started with */
30938373Skarels 	if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) {
31038373Skarels 		syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m");
31138373Skarels 		exit(1);
31238373Skarels 	}
31338372Ssam 	ldisc = SLIPDISC;
31438372Ssam 	if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) {
31540016Ssam 		syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
31638272Ssam 		exit(1);
31738272Ssam 	}
31838272Ssam 	/* find out what unit number we were assigned */
31938372Ssam 	if (ioctl(0, TIOCGETD, (caddr_t)&unit) < 0) {
32038373Skarels 		syslog(LOG_ERR, "ioctl (TIOCGETD) (2): %m");
32138272Ssam 		exit(1);
32238272Ssam 	}
32344851Strent 	(void) signal(SIGHUP, hup_handler);
32444851Strent 	(void) signal(SIGTERM, hup_handler);
32544851Strent 
32644851Strent 	syslog(LOG_INFO, "attaching slip unit %d for %s\n", unit, loginname);
32744851Strent 	(void)sprintf(logincmd, "%s %d %d %s", loginfile, unit, speed,
32844851Strent 		      loginargs);
32944851Strent 	/*
33044851Strent 	 * aim stdout and errout at /dev/null so logincmd output won't
33144851Strent 	 * babble into the slip tty line.
33244851Strent 	 */
33344851Strent 	(void)close(1);
33444851Strent 	if ((fd = open("/dev/null", O_WRONLY, 0)) != 1) {
33544851Strent 		if (fd < 0) {
33644851Strent 			syslog(LOG_ERR, "open /dev/null: %m");
33738272Ssam 			exit(1);
33838272Ssam 		}
33944851Strent 		(void)dup2(fd, 1);
34044851Strent 		(void)close(fd);
34138272Ssam 	}
34244851Strent 	(void)dup2(1,2);
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 	}
34938373Skarels 	if (ioctl(0, SLIOCSFLAGS, (caddr_t)&slip_mode) < 0) {
35038373Skarels 		syslog(LOG_ERR, "ioctl (SLIOCSFLAGS): %m");
35138373Skarels 		exit(1);
35238373Skarels 	}
35338272Ssam 
35438272Ssam 	/* twiddle thumbs until we get a signal */
35544851Strent 	while (1)
35638272Ssam 		sigpause(0);
35738272Ssam 
35844851Strent 	/* NOTREACHED */
35938272Ssam }
360