1*44262Sbostic /*-
2*44262Sbostic  * Copyright (c) 1990 The Regents of the University of California.
3*44262Sbostic  * All rights reserved.
4*44262Sbostic  *
5*44262Sbostic  * %sccs.include.redist.c%
6*44262Sbostic  */
7*44262Sbostic 
838272Ssam #ifndef lint
9*44262Sbostic char copyright[] =
10*44262Sbostic "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
11*44262Sbostic  All rights reserved.\n";
12*44262Sbostic #endif /* not lint */
13*44262Sbostic 
14*44262Sbostic #ifndef lint
15*44262Sbostic static char sccsid[] = "@(#)sliplogin.c	5.1 (Berkeley) 06/25/90";
16*44262Sbostic #endif /* not lint */
17*44262Sbostic 
1840016Ssam /* from static char *sccsid = "@(#)sliplogin.c	1.3	MS/ACF	89/04/18"; */
1938272Ssam 
2038272Ssam /*
2138272Ssam  * sliplogin.c
2238373Skarels  * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!]
2338272Ssam  *
2438272Ssam  * This program initializes its own tty port to be an async TCP/IP interface.
2538272Ssam  * It merely sets up the SLIP module all by its lonesome on the STREAMS stack,
2638272Ssam  * initializes the network interface, and pauses forever waiting for hangup.
2738272Ssam  *
2838272Ssam  * It is a remote descendant of several similar programs with incestuous ties:
2938272Ssam  * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL.
3038272Ssam  * - slattach, probably by Rick Adams but touched by countless hordes.
3138272Ssam  * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it.
3238272Ssam  * - a simple slattach-like program used to test the STREAMS SLIP code.
3338272Ssam  *
3438272Ssam  * There are three basic forms of usage:
3538272Ssam  *
3638272Ssam  * "sliplogin"
3738272Ssam  * Invoked simply as "sliplogin" and a realuid != 0, the program looks up
3838272Ssam  * the uid in /etc/passwd, and then the username in the file /etc/hosts.slip.
3938272Ssam  * If and entry is found, the line on fd0 is configured for SLIP operation
4038272Ssam  * as specified in the file.
4138272Ssam  *
4238272Ssam  * "sliplogin IPhost1 </dev/ttyb"
4338272Ssam  * Invoked by root with a username, the name is looked up in the
4438272Ssam  * /etc/hosts.slip file and if found fd0 is configured as in case 1.
4538272Ssam  *
4638272Ssam  * "sliplogin 192.100.1.1 192.100.1.2 255.255.255.0 < /dev/ttyb"
4738272Ssam  * Finally, if invoked with a remote addr, local addr, and optionally
4838272Ssam  * a net mask, the line on fd0 is setup as specified if the user is root.
4938272Ssam  *
5038272Ssam  * Doug Kingston 8810??		- logging + first pass at adding I_STR ioctl's
5138272Ssam  * Rayan Zachariassen 881011	- version for SunOS STREAMS SLIP
5238272Ssam  */
5338272Ssam 
5438272Ssam #include <sys/types.h>
5538272Ssam #include <sys/socket.h>
5638272Ssam #include <sys/termios.h>
5738372Ssam #include <sys/ioctl.h>
5838272Ssam #include <sys/file.h>
5938272Ssam #include <sys/syslog.h>
6038272Ssam 
6138272Ssam #include <netinet/in.h>
6238272Ssam #include <net/if.h>
6338373Skarels #include <net/if_slvar.h>	/* XXX */
6438272Ssam 
6538272Ssam #include <stdio.h>
6638272Ssam #include <errno.h>
6738272Ssam #include <ctype.h>
6838272Ssam #include <netdb.h>
6938272Ssam 
7038272Ssam #include <signal.h>
7138272Ssam #include <strings.h>
7238272Ssam #include <pwd.h>
7338272Ssam #include <ttyent.h>
7438272Ssam 
7538372Ssam #define	SLIPIFNAME	"sl"
7638372Ssam 
7738372Ssam #define ADDR	1
7838372Ssam #define MASK	2
7938372Ssam 
8040016Ssam #define	DCD_CHECK_INTERVAL 0	/* if > 0, time between automatic DCD checks */
8138272Ssam #define	DCD_SETTLING_TIME 1	/* time between DCD change and status check */
8238272Ssam 
8338272Ssam int gotalarm = 0;
8438272Ssam int timeleft = DCD_CHECK_INTERVAL;
8538272Ssam 
8638272Ssam #if	defined(SIGDCD) && SIGDCD > 0
8738272Ssam void
8838272Ssam dcd_handler()
8938272Ssam {
9038272Ssam #if	DCD_SETTLING_TIME > 0
9138272Ssam 	timeleft = alarm(DCD_SETTLING_TIME);
9238272Ssam #else
9338272Ssam 	gotalarm = 1;
9438272Ssam #endif	/* DCD_SETTLING_TIME */
9538272Ssam }
9638272Ssam #endif
9738272Ssam 
9840016Ssam #if DCD_CHECK_INTERVAL > 0
9940016Ssam void
10040016Ssam alarm_handler()
10140016Ssam {
10240016Ssam #ifdef SIGDCD
10340016Ssam 	if (timeleft > DCD_SETTLING_TIME)
10440016Ssam 		(void) alarm(timeleft-DCD_SETTLING_TIME);
10540016Ssam 	else
10640016Ssam #endif /* SIGDCD */
10740016Ssam 		(void) alarm(DCD_CHECK_INTERVAL);
10840016Ssam 	gotalarm = 1;
10940016Ssam 	timeleft = 0;
11040016Ssam }
11140016Ssam 
11238272Ssam /* Use TIOCMGET to test if DCD is low on the port of the passed descriptor */
11338272Ssam 
11438272Ssam int
11538272Ssam lowdcd(fd)
11638272Ssam 	int fd;
11738272Ssam {
11838272Ssam 	int mbits;
11938272Ssam 
12038272Ssam 	if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0)
12138272Ssam 		return 1;	/* port is dead, we die */
12238272Ssam 	return !(mbits & TIOCM_CAR);
12338272Ssam }
12440016Ssam #endif /* DCD_CHECK_INTERVAL > 0 */
12538272Ssam 
12638272Ssam char	*Accessfile = "/etc/hosts.slip";
12738272Ssam 
12838272Ssam extern char *malloc(), *ttyname();
12938272Ssam extern struct passwd *getpwuid();
13038272Ssam 
13138272Ssam char	*dstaddr, *localaddr, *netmask;
13238373Skarels int	slip_mode, unit;
13338272Ssam 
13438373Skarels struct slip_modes {
13538373Skarels 	char	*sm_name;
13638373Skarels 	int	sm_value;
13738373Skarels }	 modes[] = {
13838373Skarels 	"normal",	0,		/* slip "standard" ala Rick Adams */
13938373Skarels 	"compress",	SC_COMPRESS,	/* Van Jacobsen's tcp header comp. */
14038373Skarels 	"noicmp",	SC_NOICMP,	/* Sam's(?) ICMP suppression */
14138373Skarels } ;
14238373Skarels 
14338373Skarels void
14440016Ssam hup_handler(s)
14540016Ssam 	int s;
14638373Skarels {
14740016Ssam 
14840016Ssam 	syslog(LOG_INFO,
14940016Ssam 	    "%s%d: connection closed: process aborted, sig %d, remote %s\n",
15040016Ssam 	    SLIPIFNAME, unit, s, dstaddr);
15140016Ssam 	if (close(0) < 0)
15240016Ssam 		syslog(LOG_ERR, "(hup) close: %m");
15340016Ssam 	else
15440016Ssam 		syslog(LOG_INFO, "(hup) close completed");
15538373Skarels 	exit(1) ;
15638373Skarels }
15738373Skarels 
15838272Ssam main(argc, argv)
15938272Ssam 	int argc;
16038272Ssam 	char *argv[];
16138272Ssam {
16238373Skarels 	int	fd, s, ldisc, odisc;
16338373Skarels 	struct	termios tios, otios;
16438272Ssam 	struct	ifreq ifr;
16538272Ssam 
16638272Ssam 	s = getdtablesize();
16738272Ssam 	for (fd = 3 ; fd < s ; fd++)
16838272Ssam 		close(fd);
16938272Ssam 	openlog("sliplogin", LOG_PID, LOG_DAEMON);
17038272Ssam 	if (getuid() == 0) {
17138272Ssam 		if (argc <= 1) {
17238272Ssam 			fprintf(stderr, "Usage: %s loginname\n", argv[0]);
17338272Ssam 			fprintf(stderr, "   or: %s dstaddr localaddr [mask]\n",
17438272Ssam 					argv[0]);
17538272Ssam 			exit(1);
17638272Ssam 		} else if (argc == 2) {
17738272Ssam 			findid(argv[1]);
17838272Ssam 			fprintf(stderr, "local %s remote %s mask %s\n",
17938272Ssam 				localaddr, dstaddr, netmask);
18038272Ssam 		} if (argc > 2) {
18138272Ssam 			if (argc < 3 || argc > 4) {
18238272Ssam 				fprintf(stderr,
18338272Ssam 					"Usage: %s dstaddr localaddr [mask]\n",
18438272Ssam 					argv[0]);
18538272Ssam 				exit(1);
18638272Ssam 			}
18738272Ssam 			dstaddr = argv[1];
18838272Ssam 			localaddr = argv[2];
18938272Ssam 			if (argc == 4)
19038272Ssam 				netmask = argv[3];
19138272Ssam 			else
19238272Ssam 				netmask = "default";
19338272Ssam 		}
19440016Ssam 		/*
19540016Ssam 		 * Disassociate from current controlling terminal, if any,
19640016Ssam 		 * and ensure that the slip line is our controlling terminal.
19740016Ssam 		 */
19840016Ssam #if !defined(BSD) || BSD < 198810
19940016Ssam 		if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
20040016Ssam 			(void) ioctl(fd, TIOCNOTTY, 0);
20140016Ssam 			(void) close(fd);
20240016Ssam 			/* open slip tty again to acquire as controlling tty? */
20340016Ssam 			fd = open(ttyname(0), O_RDWR, 0);
20440016Ssam 			if (fd >= 0)
20540016Ssam 				(void) close(fd);
20640016Ssam 		}
20740016Ssam 		(void) setpgrp(0, getpid());
20840016Ssam #else
20940016Ssam 		(void) setsid();
21040016Ssam 		(void) ioctl(0, TIOCSCTTY, 0); /* not sure this will work */
21140016Ssam #endif
21238272Ssam 	} else
21338272Ssam 		findid((char *)0);
21438272Ssam 	fchmod(0, 0600);
21538272Ssam 	/* set up the line parameters */
21640016Ssam 	if (ioctl(0, TIOCGETA, (caddr_t)&tios) < 0) {
21740016Ssam 		syslog(LOG_ERR, "ioctl (TIOCGETA): %m");
21838272Ssam 		exit(1);
21938272Ssam 	}
22040016Ssam 	otios = tios;
22140016Ssam 	tios.c_cflag = CS8|CREAD|HUPCL;
22238272Ssam 	tios.c_iflag = IGNBRK;
22338372Ssam 	tios.c_oflag = tios.c_lflag = 0;
22440016Ssam 	if (ioctl(0, TIOCSETA, (caddr_t)&tios) < 0) {
22540016Ssam 		syslog(LOG_ERR, "ioctl (TIOCSETA) (1): %m");
22638272Ssam 		exit(1);
22738272Ssam 	}
22838373Skarels 	/* find out what ldisc we started with */
22938373Skarels 	if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) {
23038373Skarels 		syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m");
23138373Skarels 		exit(1);
23238373Skarels 	}
23338372Ssam 	ldisc = SLIPDISC;
23438372Ssam 	if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) {
23540016Ssam 		syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
23638272Ssam 		exit(1);
23738272Ssam 	}
23838272Ssam 	/* find out what unit number we were assigned */
23938372Ssam 	if (ioctl(0, TIOCGETD, (caddr_t)&unit) < 0) {
24038373Skarels 		syslog(LOG_ERR, "ioctl (TIOCGETD) (2): %m");
24138272Ssam 		exit(1);
24238272Ssam 	}
24340016Ssam 	syslog(LOG_INFO, "attaching %s%d: local %s remote %s mask %s\n",
24438372Ssam 		SLIPIFNAME, unit, localaddr, dstaddr, netmask);
24538372Ssam #ifdef notdef
24638272Ssam 	/* set the local and remote interface addresses */
24738272Ssam 	s = socket(AF_INET, SOCK_DGRAM, 0);
24838272Ssam 	if (getuid() != 0 || argc == 4) {
24938272Ssam 		(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
25038372Ssam 		in_getaddr(netmask, &ifr.ifr_addr, MASK);
25138272Ssam 		if (ioctl(s, SIOCSIFNETMASK, (caddr_t)&ifr) < 0) {
25238272Ssam 			syslog(LOG_ERR, "ioctl (SIOCSIFNETMASK): %m");
25338272Ssam 			exit(1);
25438272Ssam 		}
25538272Ssam 	}
25638272Ssam 	(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
25738372Ssam 	in_getaddr(dstaddr, &ifr.ifr_addr, ADDR);
25838272Ssam 	if (ioctl(s, SIOCSIFDSTADDR, (caddr_t)&ifr) < 0) {
25938272Ssam 		syslog(LOG_ERR, "ioctl (SIOCSIFDSTADDR): %m");
26038272Ssam 		exit(1);
26138272Ssam 	}
26238272Ssam 	(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
26338372Ssam 	in_getaddr(localaddr, &ifr.ifr_addr, ADDR);
26438272Ssam 	/* this has the side-effect of marking the interface up */
26538272Ssam 	if (ioctl(s, SIOCSIFADDR, (caddr_t)&ifr) < 0) {
26638272Ssam 		syslog(LOG_ERR, "ioctl (SIOCSIFADDR): %m");
26738272Ssam 		exit(1);
26838272Ssam 	}
26938372Ssam #else
27038372Ssam 	/* XXX -- give up for now and just invoke ifconfig XXX */
27138372Ssam 	{ char cmd[256];
27238372Ssam 	  sprintf(cmd, "/sbin/ifconfig %s%d inet %s %s netmask %s",
27338372Ssam 	      SLIPIFNAME, unit, localaddr, dstaddr, netmask);
27438372Ssam 	  system(cmd);
27538372Ssam 	}
27640016Ssam #endif
27738373Skarels 	if (ioctl(0, SLIOCSFLAGS, (caddr_t)&slip_mode) < 0) {
27838373Skarels 		syslog(LOG_ERR, "ioctl (SLIOCSFLAGS): %m");
27938373Skarels 		exit(1);
28038373Skarels 	}
28138272Ssam 
28238272Ssam 	/* set up signal handlers */
28338272Ssam #if	defined(SIGDCD) && SIGDCD > 0
28438272Ssam 	(void) signal(SIGDCD, dcd_handler);
28538272Ssam #endif
28638272Ssam 	(void) sigblock(sigmask(SIGALRM));
28738373Skarels 	(void) signal(SIGHUP, hup_handler);
28838373Skarels 	(void) signal(SIGTERM, hup_handler);
28938272Ssam 
29040016Ssam #if DCD_CHECK_INTERVAL > 0
29138272Ssam 	/* timeleft = 60 * 60 * 24 * 365 ; (void) alarm(timeleft); */
29240016Ssam 	(void) signal(SIGALRM, alarm_handler);
29338373Skarels 	(void) alarm(DCD_CHECK_INTERVAL);
29440016Ssam #endif
29538272Ssam 
29638272Ssam 	/* twiddle thumbs until we get a signal */
29738272Ssam 	while (1) {
29838272Ssam 		sigpause(0);
29940016Ssam #if DCD_CHECK_INTERVAL > 0
30038272Ssam 		(void) sigblock(sigmask(SIGALRM));
30138272Ssam 		if (gotalarm && lowdcd(0))
30238272Ssam 			break;
30338272Ssam 		gotalarm = 0;
30440016Ssam #endif /* DCD_CHECK_INTERVAL > 0 */
30538272Ssam 	}
30638272Ssam 
30740016Ssam #ifdef notdef
30838373Skarels 	if (lowdcd(0))
30938373Skarels 		syslog(LOG_NOTICE,
31038373Skarels 			"connection closed: loss of carrier %s%d: remote %s\n",
31138373Skarels 			SLIPIFNAME, unit, dstaddr);
31240016Ssam #endif
31338373Skarels 
31438373Skarels 	if (ioctl(0, TIOCSETD, (caddr_t)&odisc) < 0) {
31538373Skarels 		syslog(LOG_ERR, "ioctl(TIOCSETD) (2): %m");
31638373Skarels 		exit(1);
31738373Skarels 	}
31840016Ssam 	if (ioctl(0, TIOCSETA, (caddr_t)&otios) < 0) {
31940016Ssam 		syslog(LOG_ERR, "ioctl (TIOCSETA) (2): %m");
32038373Skarels 		exit(1);
32138373Skarels 	}
32240016Ssam 	if (close(0) < 0) {
32340016Ssam 		syslog(LOG_ERR, "close: %m");
32440016Ssam 		exit(1);
32540016Ssam 	}
32638272Ssam 	exit(0);
32738272Ssam }
32838272Ssam 
32938272Ssam findid(name)
33038272Ssam 	char *name;
33138272Ssam {
33238272Ssam 	char buf[BUFSIZ];
33338272Ssam 	static char mode[16];
33438272Ssam 	static char laddr[16];
33538272Ssam 	static char raddr[16];
33638272Ssam 	static char mask[16];
33738272Ssam 	char user[16];
33838272Ssam 	FILE *fp;
33938272Ssam 	struct passwd *pw;
34038272Ssam 	int n;
34138272Ssam 
34238272Ssam 	if (name == NULL && (pw = getpwuid(getuid())) == NULL) {
34338272Ssam 		fprintf(stderr, "Your UID (%d) is unknown\n", getuid());
34438272Ssam 		syslog(LOG_ERR, "UID (%d) is unknown\n", getuid());
34538272Ssam 		exit(1);
34638272Ssam 	} else if (name == NULL)
34738272Ssam 		name = pw->pw_name;
34838272Ssam 	if ((fp = fopen(Accessfile, "r")) == NULL) {
34938272Ssam 		perror(Accessfile);
35038272Ssam 		syslog(LOG_ERR, "%s: %m\n", Accessfile);
35138272Ssam 		exit(3);
35238272Ssam 	}
35338272Ssam 	while (fgets(buf, sizeof(buf) - 1, fp)) {
35438272Ssam 		if (ferror(fp))
35538272Ssam 			break;
35638272Ssam 		n = sscanf(buf, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
35738272Ssam 			user, mode, laddr, raddr, mask);
35838272Ssam 		if (user[0] == '#' || n != 5)
35938272Ssam 			continue;
36038272Ssam 		if (strcmp(user, name) == 0) {
36138373Skarels 			char *p,*q; int val, i, domore;
36238373Skarels 
36338373Skarels 			p = q = mode;	val = 0;
36438373Skarels 		loop:
36538373Skarels 			while (isalnum(*p)) p++;
36638373Skarels 			if(ispunct(*p) || *p == '\0') {
36738373Skarels 				if(ispunct(*p)) domore = 1; else domore = 0;
36838373Skarels 				*p++ = '\0' ;
36938373Skarels 				for (i = 0; i <
37038373Skarels 					sizeof(modes)/sizeof(struct slip_modes)
37138373Skarels 					 ; i++) {
37238373Skarels 					if (strcmp(modes[i].sm_name, q) == 0) {
37338373Skarels 						val |= modes[i].sm_value ;
37438373Skarels 						break;
37538373Skarels 					} ;
37638373Skarels }
37738373Skarels 				q = p;
37838373Skarels 				if(domore)goto loop;
37938373Skarels 			}
38038373Skarels 
38138373Skarels 			slip_mode = val ;
38238272Ssam 			localaddr = laddr;
38338272Ssam 			dstaddr = raddr;
38438272Ssam 			netmask = mask;
38538272Ssam 			fclose(fp);
38638272Ssam 			return 0;
38738272Ssam 		}
38838272Ssam 		if (feof(fp))
38938272Ssam 			break;
39038272Ssam 	}
39138272Ssam 	fputs("SLIP access denied\n", stderr);
39238272Ssam 	syslog(LOG_ERR, "SLIP access denied for %s\n", name);
39338272Ssam 	exit(4);
39438272Ssam }
39538272Ssam 
39638372Ssam in_getaddr(s, saddr, which)
39738272Ssam 	char *s;
39838272Ssam 	struct sockaddr *saddr;
39938372Ssam 	int which;
40038272Ssam {
40138272Ssam 	register struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
40238272Ssam 	struct hostent *hp;
40338272Ssam 	struct netent *np;
40438272Ssam 	int val;
40538272Ssam 	extern struct in_addr inet_makeaddr();
40638272Ssam 
40738272Ssam 	bzero((caddr_t)saddr, sizeof *saddr);
40838372Ssam 	if (which == ADDR) {
40938372Ssam 		sin->sin_len = sizeof (*sin);
41038372Ssam 		sin->sin_family = AF_INET;
41138372Ssam 	} else
41238372Ssam 		sin->sin_len = 8;
41338272Ssam 	val = inet_addr(s);
41438272Ssam 	if (val != -1) {
41538272Ssam 		sin->sin_addr.s_addr = val;
41638272Ssam 		return;
41738272Ssam 	}
41838272Ssam 	hp = gethostbyname(s);
41938272Ssam 	if (hp) {
42038272Ssam 		sin->sin_family = hp->h_addrtype;
42138272Ssam 		bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
42238272Ssam 		return;
42338272Ssam 	}
42438272Ssam 	np = getnetbyname(s);
42538272Ssam 	if (np) {
42638272Ssam 		sin->sin_family = np->n_addrtype;
42738272Ssam 		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
42838272Ssam 		return;
42938272Ssam 	}
43038272Ssam 	fprintf(stderr, "sliplogin: %s: bad value\n", s);
43138272Ssam 	syslog(LOG_ERR, "%s: bad value\n", s);
43238272Ssam 	exit(1);
43338272Ssam }
434