138272Ssam #ifndef lint
238272Ssam static char *sccsid = "@(#)sliplogin.c	1.3	MS/ACF	89/04/18";
338272Ssam #endif
438272Ssam 
538272Ssam /*
638272Ssam  * sliplogin.c
738272Ssam  *
838272Ssam  * This program initializes its own tty port to be an async TCP/IP interface.
938272Ssam  * It merely sets up the SLIP module all by its lonesome on the STREAMS stack,
1038272Ssam  * initializes the network interface, and pauses forever waiting for hangup.
1138272Ssam  *
1238272Ssam  * It is a remote descendant of several similar programs with incestuous ties:
1338272Ssam  * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL.
1438272Ssam  * - slattach, probably by Rick Adams but touched by countless hordes.
1538272Ssam  * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it.
1638272Ssam  * - a simple slattach-like program used to test the STREAMS SLIP code.
1738272Ssam  *
1838272Ssam  * There are three basic forms of usage:
1938272Ssam  *
2038272Ssam  * "sliplogin"
2138272Ssam  * Invoked simply as "sliplogin" and a realuid != 0, the program looks up
2238272Ssam  * the uid in /etc/passwd, and then the username in the file /etc/hosts.slip.
2338272Ssam  * If and entry is found, the line on fd0 is configured for SLIP operation
2438272Ssam  * as specified in the file.
2538272Ssam  *
2638272Ssam  * "sliplogin IPhost1 </dev/ttyb"
2738272Ssam  * Invoked by root with a username, the name is looked up in the
2838272Ssam  * /etc/hosts.slip file and if found fd0 is configured as in case 1.
2938272Ssam  *
3038272Ssam  * "sliplogin 192.100.1.1 192.100.1.2 255.255.255.0 < /dev/ttyb"
3138272Ssam  * Finally, if invoked with a remote addr, local addr, and optionally
3238272Ssam  * a net mask, the line on fd0 is setup as specified if the user is root.
3338272Ssam  *
3438272Ssam  * Doug Kingston 8810??		- logging + first pass at adding I_STR ioctl's
3538272Ssam  * Rayan Zachariassen 881011	- version for SunOS STREAMS SLIP
3638272Ssam  */
3738272Ssam 
3838272Ssam #include <sys/types.h>
3938272Ssam #include <sys/socket.h>
4038272Ssam #include <sys/termios.h>
41*38372Ssam #include <sys/ioctl.h>
4238272Ssam #include <sys/file.h>
4338272Ssam #include <sys/syslog.h>
4438272Ssam 
4538272Ssam #include <netinet/in.h>
4638272Ssam #include <net/if.h>
4738272Ssam 
4838272Ssam #include <stdio.h>
4938272Ssam #include <errno.h>
5038272Ssam #include <ctype.h>
5138272Ssam #include <netdb.h>
5238272Ssam 
5338272Ssam #include <signal.h>
5438272Ssam #include <strings.h>
5538272Ssam #include <pwd.h>
5638272Ssam #include <ttyent.h>
5738272Ssam 
58*38372Ssam #define	SLIPIFNAME	"sl"
59*38372Ssam 
60*38372Ssam #define ADDR	1
61*38372Ssam #define MASK	2
62*38372Ssam 
6338272Ssam #define	DCD_CHECK_INTERVAL 0	/* if > 0, time between automatic DCD checks */
6438272Ssam #define	DCD_SETTLING_TIME 1	/* time between DCD change and status check */
6538272Ssam 
6638272Ssam int gotalarm = 0;
6738272Ssam int timeleft = DCD_CHECK_INTERVAL;
6838272Ssam 
6938272Ssam void
7038272Ssam alarm_handler()
7138272Ssam {
7238272Ssam 	if (timeleft > DCD_SETTLING_TIME)
7338272Ssam 		(void) alarm(timeleft-DCD_SETTLING_TIME);
7438272Ssam 	else
7538272Ssam 		(void) alarm(DCD_CHECK_INTERVAL);
7638272Ssam 	gotalarm = 1;
7738272Ssam 	timeleft = 0;
7838272Ssam }
7938272Ssam 
8038272Ssam #if	defined(SIGDCD) && SIGDCD > 0
8138272Ssam void
8238272Ssam dcd_handler()
8338272Ssam {
8438272Ssam #if	DCD_SETTLING_TIME > 0
8538272Ssam 	timeleft = alarm(DCD_SETTLING_TIME);
8638272Ssam #else
8738272Ssam 	gotalarm = 1;
8838272Ssam #endif	/* DCD_SETTLING_TIME */
8938272Ssam }
9038272Ssam #endif
9138272Ssam 
9238272Ssam /* Use TIOCMGET to test if DCD is low on the port of the passed descriptor */
9338272Ssam 
9438272Ssam int
9538272Ssam lowdcd(fd)
9638272Ssam 	int fd;
9738272Ssam {
9838272Ssam 	int mbits;
9938272Ssam 
10038272Ssam 	if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0)
10138272Ssam 		return 1;	/* port is dead, we die */
10238272Ssam 	return !(mbits & TIOCM_CAR);
10338272Ssam }
10438272Ssam 
10538272Ssam char	*Accessfile = "/etc/hosts.slip";
10638272Ssam 
10738272Ssam extern char *malloc(), *ttyname();
10838272Ssam extern struct passwd *getpwuid();
10938272Ssam 
11038272Ssam char	*dstaddr, *localaddr, *netmask;
11138272Ssam 
11238272Ssam main(argc, argv)
11338272Ssam 	int argc;
11438272Ssam 	char *argv[];
11538272Ssam {
116*38372Ssam 	int	fd, s, unit, ldisc;
11738272Ssam 	struct	termios tios;
11838272Ssam 	struct	ifreq ifr;
11938272Ssam 
12038272Ssam 	s = getdtablesize();
12138272Ssam 	for (fd = 3 ; fd < s ; fd++)
12238272Ssam 		close(fd);
12338272Ssam 	openlog("sliplogin", LOG_PID, LOG_DAEMON);
12438272Ssam 	if (getuid() == 0) {
12538272Ssam 		if (argc <= 1) {
12638272Ssam 			fprintf(stderr, "Usage: %s loginname\n", argv[0]);
12738272Ssam 			fprintf(stderr, "   or: %s dstaddr localaddr [mask]\n",
12838272Ssam 					argv[0]);
12938272Ssam 			exit(1);
13038272Ssam 		} else if (argc == 2) {
13138272Ssam 			findid(argv[1]);
13238272Ssam 			fprintf(stderr, "local %s remote %s mask %s\n",
13338272Ssam 				localaddr, dstaddr, netmask);
13438272Ssam 		} if (argc > 2) {
13538272Ssam 			if (argc < 3 || argc > 4) {
13638272Ssam 				fprintf(stderr,
13738272Ssam 					"Usage: %s dstaddr localaddr [mask]\n",
13838272Ssam 					argv[0]);
13938272Ssam 				exit(1);
14038272Ssam 			}
14138272Ssam 			dstaddr = argv[1];
14238272Ssam 			localaddr = argv[2];
14338272Ssam 			if (argc == 4)
14438272Ssam 				netmask = argv[3];
14538272Ssam 			else
14638272Ssam 				netmask = "default";
14738272Ssam 		}
14838272Ssam 	} else
14938272Ssam 		findid((char *)0);
150*38372Ssam 	/* disassociate from current controlling terminal */
15138272Ssam 	if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
15238272Ssam 		(void) ioctl(fd, TIOCNOTTY, 0);
15338272Ssam 		(void) close(fd);
15438272Ssam 	}
155*38372Ssam 	/* ensure that the slip line is our new controlling terminal */
156*38372Ssam 	(void) setpgrp(0, getpid());
157*38372Ssam 	(void) ioctl(0, TIOCSCTTY, 0);
15838272Ssam 	fchmod(0, 0600);
15938272Ssam 	/* set up the line parameters */
160*38372Ssam 	if (ioctl(0, TCGETA, (caddr_t)&tios) < 0) {
161*38372Ssam 		syslog(LOG_ERR, "ioctl (TCGETA): %m");
16238272Ssam 		exit(1);
16338272Ssam 	}
16438272Ssam 	tios.c_cflag &= 0xf;	/* only save the speed */
16538272Ssam 	tios.c_cflag |= CS8|CREAD|HUPCL;
16638272Ssam 	tios.c_iflag = IGNBRK;
167*38372Ssam 	tios.c_oflag = tios.c_lflag = 0;
168*38372Ssam 	if (ioctl(0, TCSETA, (caddr_t)&tios) < 0) {
169*38372Ssam 		syslog(LOG_ERR, "ioctl (TCSETA): %m");
17038272Ssam 		exit(1);
17138272Ssam 	}
172*38372Ssam 	ldisc = SLIPDISC;
173*38372Ssam 	if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) {
174*38372Ssam 		syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
17538272Ssam 		exit(1);
17638272Ssam 	}
17738272Ssam 	/* find out what unit number we were assigned */
178*38372Ssam 	if (ioctl(0, TIOCGETD, (caddr_t)&unit) < 0) {
179*38372Ssam 		syslog(LOG_ERR, "ioctl (TIOCGETD): %m");
18038272Ssam 		exit(1);
18138272Ssam 	}
182*38372Ssam 	syslog(LOG_NOTICE, "attaching %s%d: local %s remote %s mask %s\n",
183*38372Ssam 		SLIPIFNAME, unit, localaddr, dstaddr, netmask);
184*38372Ssam #ifdef notdef
18538272Ssam 	/* set the local and remote interface addresses */
18638272Ssam 	s = socket(AF_INET, SOCK_DGRAM, 0);
18738272Ssam 	if (getuid() != 0 || argc == 4) {
18838272Ssam 		(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
189*38372Ssam 		in_getaddr(netmask, &ifr.ifr_addr, MASK);
19038272Ssam 		if (ioctl(s, SIOCSIFNETMASK, (caddr_t)&ifr) < 0) {
19138272Ssam 			syslog(LOG_ERR, "ioctl (SIOCSIFNETMASK): %m");
19238272Ssam 			exit(1);
19338272Ssam 		}
19438272Ssam 	}
19538272Ssam 	(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
196*38372Ssam 	in_getaddr(dstaddr, &ifr.ifr_addr, ADDR);
19738272Ssam 	if (ioctl(s, SIOCSIFDSTADDR, (caddr_t)&ifr) < 0) {
19838272Ssam 		syslog(LOG_ERR, "ioctl (SIOCSIFDSTADDR): %m");
19938272Ssam 		exit(1);
20038272Ssam 	}
20138272Ssam 	(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
202*38372Ssam 	in_getaddr(localaddr, &ifr.ifr_addr, ADDR);
20338272Ssam 	/* this has the side-effect of marking the interface up */
20438272Ssam 	if (ioctl(s, SIOCSIFADDR, (caddr_t)&ifr) < 0) {
20538272Ssam 		syslog(LOG_ERR, "ioctl (SIOCSIFADDR): %m");
20638272Ssam 		exit(1);
20738272Ssam 	}
208*38372Ssam #else
209*38372Ssam 	/* XXX -- give up for now and just invoke ifconfig XXX */
210*38372Ssam 	{ char cmd[256];
211*38372Ssam 	  sprintf(cmd, "/sbin/ifconfig %s%d inet %s %s netmask %s",
212*38372Ssam 	      SLIPIFNAME, unit, localaddr, dstaddr, netmask);
213*38372Ssam 	  system(cmd);
214*38372Ssam 	}
215*38372Ssam #endif
21638272Ssam 
21738272Ssam 	/* set up signal handlers */
21838272Ssam #if	defined(SIGDCD) && SIGDCD > 0
21938272Ssam 	(void) signal(SIGDCD, dcd_handler);
22038272Ssam #endif
22138272Ssam 	(void) sigblock(sigmask(SIGALRM));
22238272Ssam 	(void) signal(SIGALRM, alarm_handler);
22338272Ssam 	/* a SIGHUP will kill us */
22438272Ssam 
22538272Ssam 	/* timeleft = 60 * 60 * 24 * 365 ; (void) alarm(timeleft); */
22638272Ssam 
22738272Ssam 	/* twiddle thumbs until we get a signal */
22838272Ssam 	while (1) {
22938272Ssam 		sigpause(0);
23038272Ssam 		(void) sigblock(sigmask(SIGALRM));
23138272Ssam 		if (gotalarm && lowdcd(0))
23238272Ssam 			break;
23338272Ssam 		gotalarm = 0;
23438272Ssam 	}
23538272Ssam 
23638272Ssam 	/* closing the descriptor should pop the slip module */
23738272Ssam 	exit(0);
23838272Ssam }
23938272Ssam 
24038272Ssam findid(name)
24138272Ssam 	char *name;
24238272Ssam {
24338272Ssam 	char buf[BUFSIZ];
24438272Ssam 	static char mode[16];
24538272Ssam 	static char laddr[16];
24638272Ssam 	static char raddr[16];
24738272Ssam 	static char mask[16];
24838272Ssam 	char user[16];
24938272Ssam 	FILE *fp;
25038272Ssam 	struct passwd *pw;
25138272Ssam 	int n;
25238272Ssam 
25338272Ssam 	if (name == NULL && (pw = getpwuid(getuid())) == NULL) {
25438272Ssam 		fprintf(stderr, "Your UID (%d) is unknown\n", getuid());
25538272Ssam 		syslog(LOG_ERR, "UID (%d) is unknown\n", getuid());
25638272Ssam 		exit(1);
25738272Ssam 	} else if (name == NULL)
25838272Ssam 		name = pw->pw_name;
25938272Ssam 	if ((fp = fopen(Accessfile, "r")) == NULL) {
26038272Ssam 		perror(Accessfile);
26138272Ssam 		syslog(LOG_ERR, "%s: %m\n", Accessfile);
26238272Ssam 		exit(3);
26338272Ssam 	}
26438272Ssam 	while (fgets(buf, sizeof(buf) - 1, fp)) {
26538272Ssam 		if (ferror(fp))
26638272Ssam 			break;
26738272Ssam 		n = sscanf(buf, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
26838272Ssam 			user, mode, laddr, raddr, mask);
26938272Ssam 		if (user[0] == '#' || n != 5)
27038272Ssam 			continue;
27138272Ssam 		if (strcmp(user, name) == 0) {
27238272Ssam 			/* eventually deal with "mode" */
27338272Ssam 			localaddr = laddr;
27438272Ssam 			dstaddr = raddr;
27538272Ssam 			netmask = mask;
27638272Ssam 			fclose(fp);
27738272Ssam 			return 0;
27838272Ssam 		}
27938272Ssam 		if (feof(fp))
28038272Ssam 			break;
28138272Ssam 	}
28238272Ssam 	fputs("SLIP access denied\n", stderr);
28338272Ssam 	syslog(LOG_ERR, "SLIP access denied for %s\n", name);
28438272Ssam 	exit(4);
28538272Ssam }
28638272Ssam 
287*38372Ssam in_getaddr(s, saddr, which)
28838272Ssam 	char *s;
28938272Ssam 	struct sockaddr *saddr;
290*38372Ssam 	int which;
29138272Ssam {
29238272Ssam 	register struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
29338272Ssam 	struct hostent *hp;
29438272Ssam 	struct netent *np;
29538272Ssam 	int val;
29638272Ssam 	extern struct in_addr inet_makeaddr();
29738272Ssam 
29838272Ssam 	bzero((caddr_t)saddr, sizeof *saddr);
299*38372Ssam 	if (which == ADDR) {
300*38372Ssam 		sin->sin_len = sizeof (*sin);
301*38372Ssam 		sin->sin_family = AF_INET;
302*38372Ssam 	} else
303*38372Ssam 		sin->sin_len = 8;
30438272Ssam 	val = inet_addr(s);
30538272Ssam 	if (val != -1) {
30638272Ssam 		sin->sin_addr.s_addr = val;
30738272Ssam 		return;
30838272Ssam 	}
30938272Ssam 	hp = gethostbyname(s);
31038272Ssam 	if (hp) {
31138272Ssam 		sin->sin_family = hp->h_addrtype;
31238272Ssam 		bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
31338272Ssam 		return;
31438272Ssam 	}
31538272Ssam 	np = getnetbyname(s);
31638272Ssam 	if (np) {
31738272Ssam 		sin->sin_family = np->n_addrtype;
31838272Ssam 		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
31938272Ssam 		return;
32038272Ssam 	}
32138272Ssam 	fprintf(stderr, "sliplogin: %s: bad value\n", s);
32238272Ssam 	syslog(LOG_ERR, "%s: bad value\n", s);
32338272Ssam 	exit(1);
32438272Ssam }
325