138272Ssam #ifndef lint
238272Ssam static char *sccsid = "@(#)sliplogin.c	1.3	MS/ACF	89/04/18";
338272Ssam #endif
438272Ssam 
538272Ssam /*
638272Ssam  * sliplogin.c
7*38373Skarels  * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!]
838272Ssam  *
938272Ssam  * This program initializes its own tty port to be an async TCP/IP interface.
1038272Ssam  * It merely sets up the SLIP module all by its lonesome on the STREAMS stack,
1138272Ssam  * initializes the network interface, and pauses forever waiting for hangup.
1238272Ssam  *
1338272Ssam  * It is a remote descendant of several similar programs with incestuous ties:
1438272Ssam  * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL.
1538272Ssam  * - slattach, probably by Rick Adams but touched by countless hordes.
1638272Ssam  * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it.
1738272Ssam  * - a simple slattach-like program used to test the STREAMS SLIP code.
1838272Ssam  *
1938272Ssam  * There are three basic forms of usage:
2038272Ssam  *
2138272Ssam  * "sliplogin"
2238272Ssam  * Invoked simply as "sliplogin" and a realuid != 0, the program looks up
2338272Ssam  * the uid in /etc/passwd, and then the username in the file /etc/hosts.slip.
2438272Ssam  * If and entry is found, the line on fd0 is configured for SLIP operation
2538272Ssam  * as specified in the file.
2638272Ssam  *
2738272Ssam  * "sliplogin IPhost1 </dev/ttyb"
2838272Ssam  * Invoked by root with a username, the name is looked up in the
2938272Ssam  * /etc/hosts.slip file and if found fd0 is configured as in case 1.
3038272Ssam  *
3138272Ssam  * "sliplogin 192.100.1.1 192.100.1.2 255.255.255.0 < /dev/ttyb"
3238272Ssam  * Finally, if invoked with a remote addr, local addr, and optionally
3338272Ssam  * a net mask, the line on fd0 is setup as specified if the user is root.
3438272Ssam  *
3538272Ssam  * Doug Kingston 8810??		- logging + first pass at adding I_STR ioctl's
3638272Ssam  * Rayan Zachariassen 881011	- version for SunOS STREAMS SLIP
3738272Ssam  */
3838272Ssam 
3938272Ssam #include <sys/types.h>
4038272Ssam #include <sys/socket.h>
4138272Ssam #include <sys/termios.h>
4238372Ssam #include <sys/ioctl.h>
4338272Ssam #include <sys/file.h>
4438272Ssam #include <sys/syslog.h>
4538272Ssam 
4638272Ssam #include <netinet/in.h>
4738272Ssam #include <net/if.h>
48*38373Skarels #include <net/if_slvar.h>	/* XXX */
4938272Ssam 
5038272Ssam #include <stdio.h>
5138272Ssam #include <errno.h>
5238272Ssam #include <ctype.h>
5338272Ssam #include <netdb.h>
5438272Ssam 
5538272Ssam #include <signal.h>
5638272Ssam #include <strings.h>
5738272Ssam #include <pwd.h>
5838272Ssam #include <ttyent.h>
5938272Ssam 
6038372Ssam #define	SLIPIFNAME	"sl"
6138372Ssam 
6238372Ssam #define ADDR	1
6338372Ssam #define MASK	2
6438372Ssam 
65*38373Skarels #define	DCD_CHECK_INTERVAL 5	/* if > 0, time between automatic DCD checks */
6638272Ssam #define	DCD_SETTLING_TIME 1	/* time between DCD change and status check */
6738272Ssam 
6838272Ssam int gotalarm = 0;
6938272Ssam int timeleft = DCD_CHECK_INTERVAL;
7038272Ssam 
7138272Ssam void
7238272Ssam alarm_handler()
7338272Ssam {
74*38373Skarels 	/*if (timeleft > DCD_SETTLING_TIME)
7538272Ssam 		(void) alarm(timeleft-DCD_SETTLING_TIME);
76*38373Skarels 	else */
7738272Ssam 		(void) alarm(DCD_CHECK_INTERVAL);
7838272Ssam 	gotalarm = 1;
7938272Ssam 	timeleft = 0;
8038272Ssam }
8138272Ssam 
8238272Ssam #if	defined(SIGDCD) && SIGDCD > 0
8338272Ssam void
8438272Ssam dcd_handler()
8538272Ssam {
8638272Ssam #if	DCD_SETTLING_TIME > 0
8738272Ssam 	timeleft = alarm(DCD_SETTLING_TIME);
8838272Ssam #else
8938272Ssam 	gotalarm = 1;
9038272Ssam #endif	/* DCD_SETTLING_TIME */
9138272Ssam }
9238272Ssam #endif
9338272Ssam 
9438272Ssam /* Use TIOCMGET to test if DCD is low on the port of the passed descriptor */
9538272Ssam 
9638272Ssam int
9738272Ssam lowdcd(fd)
9838272Ssam 	int fd;
9938272Ssam {
10038272Ssam 	int mbits;
10138272Ssam 
10238272Ssam 	if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0)
10338272Ssam 		return 1;	/* port is dead, we die */
10438272Ssam 	return !(mbits & TIOCM_CAR);
10538272Ssam }
10638272Ssam 
107*38373Skarels /* Use TIOCMGET to test if DTR is low on the port of the passed descriptor */
108*38373Skarels 
109*38373Skarels int
110*38373Skarels lowdtr(fd)
111*38373Skarels 	int fd;
112*38373Skarels {
113*38373Skarels 	int mbits;
114*38373Skarels 
115*38373Skarels 	if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0)
116*38373Skarels 		return 1;	/* port is dead, we die */
117*38373Skarels 	return ((mbits & TIOCM_DTR) == TIOCM_DTR);
118*38373Skarels }
119*38373Skarels 
12038272Ssam char	*Accessfile = "/etc/hosts.slip";
12138272Ssam 
12238272Ssam extern char *malloc(), *ttyname();
12338272Ssam extern struct passwd *getpwuid();
12438272Ssam 
12538272Ssam char	*dstaddr, *localaddr, *netmask;
126*38373Skarels int	slip_mode, unit;
12738272Ssam 
128*38373Skarels struct slip_modes {
129*38373Skarels 	char	*sm_name;
130*38373Skarels 	int	sm_value;
131*38373Skarels }	 modes[] = {
132*38373Skarels 	"normal",	0,		/* slip "standard" ala Rick Adams */
133*38373Skarels 	"compress",	SC_COMPRESS,	/* Van Jacobsen's tcp header comp. */
134*38373Skarels 	"noicmp",	SC_NOICMP,	/* Sam's(?) ICMP suppression */
135*38373Skarels } ;
136*38373Skarels 
137*38373Skarels /*
138*38373Skarels  * If we are uncerimoniously dumped, bitch
139*38373Skarels  */
140*38373Skarels void
141*38373Skarels hup_handler()
142*38373Skarels {
143*38373Skarels syslog(LOG_NOTICE, "connection closed: process aborted %s%d: remote %s\n",
144*38373Skarels 		SLIPIFNAME, unit, dstaddr);
145*38373Skarels 	exit(1) ;
146*38373Skarels }
147*38373Skarels 
14838272Ssam main(argc, argv)
14938272Ssam 	int argc;
15038272Ssam 	char *argv[];
15138272Ssam {
152*38373Skarels 	int	fd, s, ldisc, odisc;
153*38373Skarels 	struct	termios tios, otios;
15438272Ssam 	struct	ifreq ifr;
15538272Ssam 
15638272Ssam 	s = getdtablesize();
15738272Ssam 	for (fd = 3 ; fd < s ; fd++)
15838272Ssam 		close(fd);
15938272Ssam 	openlog("sliplogin", LOG_PID, LOG_DAEMON);
16038272Ssam 	if (getuid() == 0) {
16138272Ssam 		if (argc <= 1) {
16238272Ssam 			fprintf(stderr, "Usage: %s loginname\n", argv[0]);
16338272Ssam 			fprintf(stderr, "   or: %s dstaddr localaddr [mask]\n",
16438272Ssam 					argv[0]);
16538272Ssam 			exit(1);
16638272Ssam 		} else if (argc == 2) {
16738272Ssam 			findid(argv[1]);
16838272Ssam 			fprintf(stderr, "local %s remote %s mask %s\n",
16938272Ssam 				localaddr, dstaddr, netmask);
17038272Ssam 		} if (argc > 2) {
17138272Ssam 			if (argc < 3 || argc > 4) {
17238272Ssam 				fprintf(stderr,
17338272Ssam 					"Usage: %s dstaddr localaddr [mask]\n",
17438272Ssam 					argv[0]);
17538272Ssam 				exit(1);
17638272Ssam 			}
17738272Ssam 			dstaddr = argv[1];
17838272Ssam 			localaddr = argv[2];
17938272Ssam 			if (argc == 4)
18038272Ssam 				netmask = argv[3];
18138272Ssam 			else
18238272Ssam 				netmask = "default";
18338272Ssam 		}
18438272Ssam 	} else
18538272Ssam 		findid((char *)0);
186*38373Skarels 	/* ensure that the slip line is our controlling terminal */
18738272Ssam 	if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
18838272Ssam 		(void) ioctl(fd, TIOCNOTTY, 0);
18938272Ssam 		(void) close(fd);
190*38373Skarels 		fd = open(ttyname(0), O_RDWR, 0);
191*38373Skarels 		if (fd >= 0)
192*38373Skarels 			(void) close(fd);
193*38373Skarels 		(void) setpgrp(0, getpid());
19438272Ssam 	}
19538272Ssam 	fchmod(0, 0600);
19638272Ssam 	/* set up the line parameters */
19738372Ssam 	if (ioctl(0, TCGETA, (caddr_t)&tios) < 0) {
19838372Ssam 		syslog(LOG_ERR, "ioctl (TCGETA): %m");
19938272Ssam 		exit(1);
20038272Ssam 	}
201*38373Skarels 	otios = tios ;
20238272Ssam 	tios.c_cflag &= 0xf;	/* only save the speed */
20338272Ssam 	tios.c_cflag |= CS8|CREAD|HUPCL;
20438272Ssam 	tios.c_iflag = IGNBRK;
20538372Ssam 	tios.c_oflag = tios.c_lflag = 0;
20638372Ssam 	if (ioctl(0, TCSETA, (caddr_t)&tios) < 0) {
207*38373Skarels 		syslog(LOG_ERR, "ioctl (TCSETA) (1): %m");
20838272Ssam 		exit(1);
20938272Ssam 	}
210*38373Skarels 	/* find out what ldisc we started with */
211*38373Skarels 	if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) {
212*38373Skarels 		syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m");
213*38373Skarels 		exit(1);
214*38373Skarels 	}
21538372Ssam 	ldisc = SLIPDISC;
21638372Ssam 	if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) {
217*38373Skarels 		syslog(LOG_ERR, "ioctl(TIOCSETD) (1): %m");
21838272Ssam 		exit(1);
21938272Ssam 	}
22038272Ssam 	/* find out what unit number we were assigned */
22138372Ssam 	if (ioctl(0, TIOCGETD, (caddr_t)&unit) < 0) {
222*38373Skarels 		syslog(LOG_ERR, "ioctl (TIOCGETD) (2): %m");
22338272Ssam 		exit(1);
22438272Ssam 	}
22538372Ssam 	syslog(LOG_NOTICE, "attaching %s%d: local %s remote %s mask %s\n",
22638372Ssam 		SLIPIFNAME, unit, localaddr, dstaddr, netmask);
22738372Ssam #ifdef notdef
22838272Ssam 	/* set the local and remote interface addresses */
22938272Ssam 	s = socket(AF_INET, SOCK_DGRAM, 0);
23038272Ssam 	if (getuid() != 0 || argc == 4) {
23138272Ssam 		(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
23238372Ssam 		in_getaddr(netmask, &ifr.ifr_addr, MASK);
23338272Ssam 		if (ioctl(s, SIOCSIFNETMASK, (caddr_t)&ifr) < 0) {
23438272Ssam 			syslog(LOG_ERR, "ioctl (SIOCSIFNETMASK): %m");
23538272Ssam 			exit(1);
23638272Ssam 		}
23738272Ssam 	}
23838272Ssam 	(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
23938372Ssam 	in_getaddr(dstaddr, &ifr.ifr_addr, ADDR);
24038272Ssam 	if (ioctl(s, SIOCSIFDSTADDR, (caddr_t)&ifr) < 0) {
24138272Ssam 		syslog(LOG_ERR, "ioctl (SIOCSIFDSTADDR): %m");
24238272Ssam 		exit(1);
24338272Ssam 	}
24438272Ssam 	(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
24538372Ssam 	in_getaddr(localaddr, &ifr.ifr_addr, ADDR);
24638272Ssam 	/* this has the side-effect of marking the interface up */
24738272Ssam 	if (ioctl(s, SIOCSIFADDR, (caddr_t)&ifr) < 0) {
24838272Ssam 		syslog(LOG_ERR, "ioctl (SIOCSIFADDR): %m");
24938272Ssam 		exit(1);
25038272Ssam 	}
25138372Ssam #else
25238372Ssam 	/* XXX -- give up for now and just invoke ifconfig XXX */
25338372Ssam 	{ char cmd[256];
25438372Ssam 	  sprintf(cmd, "/sbin/ifconfig %s%d inet %s %s netmask %s",
25538372Ssam 	      SLIPIFNAME, unit, localaddr, dstaddr, netmask);
25638372Ssam 	  system(cmd);
25738372Ssam 	}
258*38373Skarels 	if (ioctl(0, SLIOCSFLAGS, (caddr_t)&slip_mode) < 0) {
259*38373Skarels 		syslog(LOG_ERR, "ioctl (SLIOCSFLAGS): %m");
260*38373Skarels 		exit(1);
261*38373Skarels 	}
26238372Ssam #endif
26338272Ssam 
26438272Ssam 	/* set up signal handlers */
26538272Ssam #if	defined(SIGDCD) && SIGDCD > 0
26638272Ssam 	(void) signal(SIGDCD, dcd_handler);
26738272Ssam #endif
26838272Ssam 	(void) sigblock(sigmask(SIGALRM));
26938272Ssam 	(void) signal(SIGALRM, alarm_handler);
27038272Ssam 	/* a SIGHUP will kill us */
271*38373Skarels 	(void) signal(SIGHUP, hup_handler);
272*38373Skarels 	(void) signal(SIGTERM, hup_handler);
27338272Ssam 
27438272Ssam 	/* timeleft = 60 * 60 * 24 * 365 ; (void) alarm(timeleft); */
275*38373Skarels 	(void) alarm(DCD_CHECK_INTERVAL);
27638272Ssam 
27738272Ssam 	/* twiddle thumbs until we get a signal */
27838272Ssam 	while (1) {
27938272Ssam 		sigpause(0);
28038272Ssam 		(void) sigblock(sigmask(SIGALRM));
28138272Ssam 		if (gotalarm && lowdcd(0))
28238272Ssam 			break;
283*38373Skarels 		if (gotalarm && lowdtr(0))
284*38373Skarels 			break;
28538272Ssam 		gotalarm = 0;
28638272Ssam 	}
28738272Ssam 
288*38373Skarels 	if (lowdcd(0))
289*38373Skarels 		syslog(LOG_NOTICE,
290*38373Skarels 			"connection closed: loss of carrier %s%d: remote %s\n",
291*38373Skarels 			SLIPIFNAME, unit, dstaddr);
292*38373Skarels 	else if (lowdtr(0))
293*38373Skarels 		syslog(LOG_NOTICE,
294*38373Skarels 			"connection closed by foreign host %s%d: remote %s\n",
295*38373Skarels 			SLIPIFNAME, unit, dstaddr);
296*38373Skarels 
297*38373Skarels 	if (ioctl(0, TIOCSETD, (caddr_t)&odisc) < 0) {
298*38373Skarels 		syslog(LOG_ERR, "ioctl(TIOCSETD) (2): %m");
299*38373Skarels 		exit(1);
300*38373Skarels 	}
301*38373Skarels 	if (ioctl(0, TCSETA, (caddr_t)&otios) < 0) {
302*38373Skarels 		syslog(LOG_ERR, "ioctl (TCSETA) (2): %m");
303*38373Skarels 		exit(1);
304*38373Skarels 	}
30538272Ssam 	exit(0);
30638272Ssam }
30738272Ssam 
30838272Ssam findid(name)
30938272Ssam 	char *name;
31038272Ssam {
31138272Ssam 	char buf[BUFSIZ];
31238272Ssam 	static char mode[16];
31338272Ssam 	static char laddr[16];
31438272Ssam 	static char raddr[16];
31538272Ssam 	static char mask[16];
31638272Ssam 	char user[16];
31738272Ssam 	FILE *fp;
31838272Ssam 	struct passwd *pw;
31938272Ssam 	int n;
32038272Ssam 
32138272Ssam 	if (name == NULL && (pw = getpwuid(getuid())) == NULL) {
32238272Ssam 		fprintf(stderr, "Your UID (%d) is unknown\n", getuid());
32338272Ssam 		syslog(LOG_ERR, "UID (%d) is unknown\n", getuid());
32438272Ssam 		exit(1);
32538272Ssam 	} else if (name == NULL)
32638272Ssam 		name = pw->pw_name;
32738272Ssam 	if ((fp = fopen(Accessfile, "r")) == NULL) {
32838272Ssam 		perror(Accessfile);
32938272Ssam 		syslog(LOG_ERR, "%s: %m\n", Accessfile);
33038272Ssam 		exit(3);
33138272Ssam 	}
33238272Ssam 	while (fgets(buf, sizeof(buf) - 1, fp)) {
33338272Ssam 		if (ferror(fp))
33438272Ssam 			break;
33538272Ssam 		n = sscanf(buf, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
33638272Ssam 			user, mode, laddr, raddr, mask);
33738272Ssam 		if (user[0] == '#' || n != 5)
33838272Ssam 			continue;
33938272Ssam 		if (strcmp(user, name) == 0) {
340*38373Skarels 			char *p,*q; int val, i, domore;
341*38373Skarels 
342*38373Skarels 			p = q = mode;	val = 0;
343*38373Skarels 		loop:
344*38373Skarels 			while (isalnum(*p)) p++;
345*38373Skarels 			if(ispunct(*p) || *p == '\0') {
346*38373Skarels 				if(ispunct(*p)) domore = 1; else domore = 0;
347*38373Skarels 				*p++ = '\0' ;
348*38373Skarels 				for (i = 0; i <
349*38373Skarels 					sizeof(modes)/sizeof(struct slip_modes)
350*38373Skarels 					 ; i++) {
351*38373Skarels 					if (strcmp(modes[i].sm_name, q) == 0) {
352*38373Skarels 						val |= modes[i].sm_value ;
353*38373Skarels 						break;
354*38373Skarels 					} ;
355*38373Skarels }
356*38373Skarels 				q = p;
357*38373Skarels 				if(domore)goto loop;
358*38373Skarels 			}
359*38373Skarels 
360*38373Skarels 			slip_mode = val ;
36138272Ssam 			localaddr = laddr;
36238272Ssam 			dstaddr = raddr;
36338272Ssam 			netmask = mask;
36438272Ssam 			fclose(fp);
36538272Ssam 			return 0;
36638272Ssam 		}
36738272Ssam 		if (feof(fp))
36838272Ssam 			break;
36938272Ssam 	}
37038272Ssam 	fputs("SLIP access denied\n", stderr);
37138272Ssam 	syslog(LOG_ERR, "SLIP access denied for %s\n", name);
37238272Ssam 	exit(4);
37338272Ssam }
37438272Ssam 
37538372Ssam in_getaddr(s, saddr, which)
37638272Ssam 	char *s;
37738272Ssam 	struct sockaddr *saddr;
37838372Ssam 	int which;
37938272Ssam {
38038272Ssam 	register struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
38138272Ssam 	struct hostent *hp;
38238272Ssam 	struct netent *np;
38338272Ssam 	int val;
38438272Ssam 	extern struct in_addr inet_makeaddr();
38538272Ssam 
38638272Ssam 	bzero((caddr_t)saddr, sizeof *saddr);
38738372Ssam 	if (which == ADDR) {
38838372Ssam 		sin->sin_len = sizeof (*sin);
38938372Ssam 		sin->sin_family = AF_INET;
39038372Ssam 	} else
39138372Ssam 		sin->sin_len = 8;
39238272Ssam 	val = inet_addr(s);
39338272Ssam 	if (val != -1) {
39438272Ssam 		sin->sin_addr.s_addr = val;
39538272Ssam 		return;
39638272Ssam 	}
39738272Ssam 	hp = gethostbyname(s);
39838272Ssam 	if (hp) {
39938272Ssam 		sin->sin_family = hp->h_addrtype;
40038272Ssam 		bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
40138272Ssam 		return;
40238272Ssam 	}
40338272Ssam 	np = getnetbyname(s);
40438272Ssam 	if (np) {
40538272Ssam 		sin->sin_family = np->n_addrtype;
40638272Ssam 		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
40738272Ssam 		return;
40838272Ssam 	}
40938272Ssam 	fprintf(stderr, "sliplogin: %s: bad value\n", s);
41038272Ssam 	syslog(LOG_ERR, "%s: bad value\n", s);
41138272Ssam 	exit(1);
41238272Ssam }
413