1 #ifndef lint
2 static char *sccsid = "@(#)sliplogin.c	1.3	MS/ACF	89/04/18";
3 #endif
4 
5 /*
6  * sliplogin.c
7  * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!]
8  *
9  * This program initializes its own tty port to be an async TCP/IP interface.
10  * It merely sets up the SLIP module all by its lonesome on the STREAMS stack,
11  * initializes the network interface, and pauses forever waiting for hangup.
12  *
13  * It is a remote descendant of several similar programs with incestuous ties:
14  * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL.
15  * - slattach, probably by Rick Adams but touched by countless hordes.
16  * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it.
17  * - a simple slattach-like program used to test the STREAMS SLIP code.
18  *
19  * There are three basic forms of usage:
20  *
21  * "sliplogin"
22  * Invoked simply as "sliplogin" and a realuid != 0, the program looks up
23  * the uid in /etc/passwd, and then the username in the file /etc/hosts.slip.
24  * If and entry is found, the line on fd0 is configured for SLIP operation
25  * as specified in the file.
26  *
27  * "sliplogin IPhost1 </dev/ttyb"
28  * Invoked by root with a username, the name is looked up in the
29  * /etc/hosts.slip file and if found fd0 is configured as in case 1.
30  *
31  * "sliplogin 192.100.1.1 192.100.1.2 255.255.255.0 < /dev/ttyb"
32  * Finally, if invoked with a remote addr, local addr, and optionally
33  * a net mask, the line on fd0 is setup as specified if the user is root.
34  *
35  * Doug Kingston 8810??		- logging + first pass at adding I_STR ioctl's
36  * Rayan Zachariassen 881011	- version for SunOS STREAMS SLIP
37  */
38 
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/termios.h>
42 #include <sys/ioctl.h>
43 #include <sys/file.h>
44 #include <sys/syslog.h>
45 
46 #include <netinet/in.h>
47 #include <net/if.h>
48 #include <net/if_slvar.h>	/* XXX */
49 
50 #include <stdio.h>
51 #include <errno.h>
52 #include <ctype.h>
53 #include <netdb.h>
54 
55 #include <signal.h>
56 #include <strings.h>
57 #include <pwd.h>
58 #include <ttyent.h>
59 
60 #define	SLIPIFNAME	"sl"
61 
62 #define ADDR	1
63 #define MASK	2
64 
65 #define	DCD_CHECK_INTERVAL 5	/* if > 0, time between automatic DCD checks */
66 #define	DCD_SETTLING_TIME 1	/* time between DCD change and status check */
67 
68 int gotalarm = 0;
69 int timeleft = DCD_CHECK_INTERVAL;
70 
71 void
72 alarm_handler()
73 {
74 	/*if (timeleft > DCD_SETTLING_TIME)
75 		(void) alarm(timeleft-DCD_SETTLING_TIME);
76 	else */
77 		(void) alarm(DCD_CHECK_INTERVAL);
78 	gotalarm = 1;
79 	timeleft = 0;
80 }
81 
82 #if	defined(SIGDCD) && SIGDCD > 0
83 void
84 dcd_handler()
85 {
86 #if	DCD_SETTLING_TIME > 0
87 	timeleft = alarm(DCD_SETTLING_TIME);
88 #else
89 	gotalarm = 1;
90 #endif	/* DCD_SETTLING_TIME */
91 }
92 #endif
93 
94 /* Use TIOCMGET to test if DCD is low on the port of the passed descriptor */
95 
96 int
97 lowdcd(fd)
98 	int fd;
99 {
100 	int mbits;
101 
102 	if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0)
103 		return 1;	/* port is dead, we die */
104 	return !(mbits & TIOCM_CAR);
105 }
106 
107 /* Use TIOCMGET to test if DTR is low on the port of the passed descriptor */
108 
109 int
110 lowdtr(fd)
111 	int fd;
112 {
113 	int mbits;
114 
115 	if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0)
116 		return 1;	/* port is dead, we die */
117 	return ((mbits & TIOCM_DTR) == TIOCM_DTR);
118 }
119 
120 char	*Accessfile = "/etc/hosts.slip";
121 
122 extern char *malloc(), *ttyname();
123 extern struct passwd *getpwuid();
124 
125 char	*dstaddr, *localaddr, *netmask;
126 int	slip_mode, unit;
127 
128 struct slip_modes {
129 	char	*sm_name;
130 	int	sm_value;
131 }	 modes[] = {
132 	"normal",	0,		/* slip "standard" ala Rick Adams */
133 	"compress",	SC_COMPRESS,	/* Van Jacobsen's tcp header comp. */
134 	"noicmp",	SC_NOICMP,	/* Sam's(?) ICMP suppression */
135 } ;
136 
137 /*
138  * If we are uncerimoniously dumped, bitch
139  */
140 void
141 hup_handler()
142 {
143 syslog(LOG_NOTICE, "connection closed: process aborted %s%d: remote %s\n",
144 		SLIPIFNAME, unit, dstaddr);
145 	exit(1) ;
146 }
147 
148 main(argc, argv)
149 	int argc;
150 	char *argv[];
151 {
152 	int	fd, s, ldisc, odisc;
153 	struct	termios tios, otios;
154 	struct	ifreq ifr;
155 
156 	s = getdtablesize();
157 	for (fd = 3 ; fd < s ; fd++)
158 		close(fd);
159 	openlog("sliplogin", LOG_PID, LOG_DAEMON);
160 	if (getuid() == 0) {
161 		if (argc <= 1) {
162 			fprintf(stderr, "Usage: %s loginname\n", argv[0]);
163 			fprintf(stderr, "   or: %s dstaddr localaddr [mask]\n",
164 					argv[0]);
165 			exit(1);
166 		} else if (argc == 2) {
167 			findid(argv[1]);
168 			fprintf(stderr, "local %s remote %s mask %s\n",
169 				localaddr, dstaddr, netmask);
170 		} if (argc > 2) {
171 			if (argc < 3 || argc > 4) {
172 				fprintf(stderr,
173 					"Usage: %s dstaddr localaddr [mask]\n",
174 					argv[0]);
175 				exit(1);
176 			}
177 			dstaddr = argv[1];
178 			localaddr = argv[2];
179 			if (argc == 4)
180 				netmask = argv[3];
181 			else
182 				netmask = "default";
183 		}
184 	} else
185 		findid((char *)0);
186 	/* ensure that the slip line is our controlling terminal */
187 	if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
188 		(void) ioctl(fd, TIOCNOTTY, 0);
189 		(void) close(fd);
190 		fd = open(ttyname(0), O_RDWR, 0);
191 		if (fd >= 0)
192 			(void) close(fd);
193 		(void) setpgrp(0, getpid());
194 	}
195 	fchmod(0, 0600);
196 	/* set up the line parameters */
197 	if (ioctl(0, TCGETA, (caddr_t)&tios) < 0) {
198 		syslog(LOG_ERR, "ioctl (TCGETA): %m");
199 		exit(1);
200 	}
201 	otios = tios ;
202 	tios.c_cflag &= 0xf;	/* only save the speed */
203 	tios.c_cflag |= CS8|CREAD|HUPCL;
204 	tios.c_iflag = IGNBRK;
205 	tios.c_oflag = tios.c_lflag = 0;
206 	if (ioctl(0, TCSETA, (caddr_t)&tios) < 0) {
207 		syslog(LOG_ERR, "ioctl (TCSETA) (1): %m");
208 		exit(1);
209 	}
210 	/* find out what ldisc we started with */
211 	if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) {
212 		syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m");
213 		exit(1);
214 	}
215 	ldisc = SLIPDISC;
216 	if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) {
217 		syslog(LOG_ERR, "ioctl(TIOCSETD) (1): %m");
218 		exit(1);
219 	}
220 	/* find out what unit number we were assigned */
221 	if (ioctl(0, TIOCGETD, (caddr_t)&unit) < 0) {
222 		syslog(LOG_ERR, "ioctl (TIOCGETD) (2): %m");
223 		exit(1);
224 	}
225 	syslog(LOG_NOTICE, "attaching %s%d: local %s remote %s mask %s\n",
226 		SLIPIFNAME, unit, localaddr, dstaddr, netmask);
227 #ifdef notdef
228 	/* set the local and remote interface addresses */
229 	s = socket(AF_INET, SOCK_DGRAM, 0);
230 	if (getuid() != 0 || argc == 4) {
231 		(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
232 		in_getaddr(netmask, &ifr.ifr_addr, MASK);
233 		if (ioctl(s, SIOCSIFNETMASK, (caddr_t)&ifr) < 0) {
234 			syslog(LOG_ERR, "ioctl (SIOCSIFNETMASK): %m");
235 			exit(1);
236 		}
237 	}
238 	(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
239 	in_getaddr(dstaddr, &ifr.ifr_addr, ADDR);
240 	if (ioctl(s, SIOCSIFDSTADDR, (caddr_t)&ifr) < 0) {
241 		syslog(LOG_ERR, "ioctl (SIOCSIFDSTADDR): %m");
242 		exit(1);
243 	}
244 	(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
245 	in_getaddr(localaddr, &ifr.ifr_addr, ADDR);
246 	/* this has the side-effect of marking the interface up */
247 	if (ioctl(s, SIOCSIFADDR, (caddr_t)&ifr) < 0) {
248 		syslog(LOG_ERR, "ioctl (SIOCSIFADDR): %m");
249 		exit(1);
250 	}
251 #else
252 	/* XXX -- give up for now and just invoke ifconfig XXX */
253 	{ char cmd[256];
254 	  sprintf(cmd, "/sbin/ifconfig %s%d inet %s %s netmask %s",
255 	      SLIPIFNAME, unit, localaddr, dstaddr, netmask);
256 	  system(cmd);
257 	}
258 	if (ioctl(0, SLIOCSFLAGS, (caddr_t)&slip_mode) < 0) {
259 		syslog(LOG_ERR, "ioctl (SLIOCSFLAGS): %m");
260 		exit(1);
261 	}
262 #endif
263 
264 	/* set up signal handlers */
265 #if	defined(SIGDCD) && SIGDCD > 0
266 	(void) signal(SIGDCD, dcd_handler);
267 #endif
268 	(void) sigblock(sigmask(SIGALRM));
269 	(void) signal(SIGALRM, alarm_handler);
270 	/* a SIGHUP will kill us */
271 	(void) signal(SIGHUP, hup_handler);
272 	(void) signal(SIGTERM, hup_handler);
273 
274 	/* timeleft = 60 * 60 * 24 * 365 ; (void) alarm(timeleft); */
275 	(void) alarm(DCD_CHECK_INTERVAL);
276 
277 	/* twiddle thumbs until we get a signal */
278 	while (1) {
279 		sigpause(0);
280 		(void) sigblock(sigmask(SIGALRM));
281 		if (gotalarm && lowdcd(0))
282 			break;
283 		if (gotalarm && lowdtr(0))
284 			break;
285 		gotalarm = 0;
286 	}
287 
288 	if (lowdcd(0))
289 		syslog(LOG_NOTICE,
290 			"connection closed: loss of carrier %s%d: remote %s\n",
291 			SLIPIFNAME, unit, dstaddr);
292 	else if (lowdtr(0))
293 		syslog(LOG_NOTICE,
294 			"connection closed by foreign host %s%d: remote %s\n",
295 			SLIPIFNAME, unit, dstaddr);
296 
297 	if (ioctl(0, TIOCSETD, (caddr_t)&odisc) < 0) {
298 		syslog(LOG_ERR, "ioctl(TIOCSETD) (2): %m");
299 		exit(1);
300 	}
301 	if (ioctl(0, TCSETA, (caddr_t)&otios) < 0) {
302 		syslog(LOG_ERR, "ioctl (TCSETA) (2): %m");
303 		exit(1);
304 	}
305 	exit(0);
306 }
307 
308 findid(name)
309 	char *name;
310 {
311 	char buf[BUFSIZ];
312 	static char mode[16];
313 	static char laddr[16];
314 	static char raddr[16];
315 	static char mask[16];
316 	char user[16];
317 	FILE *fp;
318 	struct passwd *pw;
319 	int n;
320 
321 	if (name == NULL && (pw = getpwuid(getuid())) == NULL) {
322 		fprintf(stderr, "Your UID (%d) is unknown\n", getuid());
323 		syslog(LOG_ERR, "UID (%d) is unknown\n", getuid());
324 		exit(1);
325 	} else if (name == NULL)
326 		name = pw->pw_name;
327 	if ((fp = fopen(Accessfile, "r")) == NULL) {
328 		perror(Accessfile);
329 		syslog(LOG_ERR, "%s: %m\n", Accessfile);
330 		exit(3);
331 	}
332 	while (fgets(buf, sizeof(buf) - 1, fp)) {
333 		if (ferror(fp))
334 			break;
335 		n = sscanf(buf, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
336 			user, mode, laddr, raddr, mask);
337 		if (user[0] == '#' || n != 5)
338 			continue;
339 		if (strcmp(user, name) == 0) {
340 			char *p,*q; int val, i, domore;
341 
342 			p = q = mode;	val = 0;
343 		loop:
344 			while (isalnum(*p)) p++;
345 			if(ispunct(*p) || *p == '\0') {
346 				if(ispunct(*p)) domore = 1; else domore = 0;
347 				*p++ = '\0' ;
348 				for (i = 0; i <
349 					sizeof(modes)/sizeof(struct slip_modes)
350 					 ; i++) {
351 					if (strcmp(modes[i].sm_name, q) == 0) {
352 						val |= modes[i].sm_value ;
353 						break;
354 					} ;
355 }
356 				q = p;
357 				if(domore)goto loop;
358 			}
359 
360 			slip_mode = val ;
361 			localaddr = laddr;
362 			dstaddr = raddr;
363 			netmask = mask;
364 			fclose(fp);
365 			return 0;
366 		}
367 		if (feof(fp))
368 			break;
369 	}
370 	fputs("SLIP access denied\n", stderr);
371 	syslog(LOG_ERR, "SLIP access denied for %s\n", name);
372 	exit(4);
373 }
374 
375 in_getaddr(s, saddr, which)
376 	char *s;
377 	struct sockaddr *saddr;
378 	int which;
379 {
380 	register struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
381 	struct hostent *hp;
382 	struct netent *np;
383 	int val;
384 	extern struct in_addr inet_makeaddr();
385 
386 	bzero((caddr_t)saddr, sizeof *saddr);
387 	if (which == ADDR) {
388 		sin->sin_len = sizeof (*sin);
389 		sin->sin_family = AF_INET;
390 	} else
391 		sin->sin_len = 8;
392 	val = inet_addr(s);
393 	if (val != -1) {
394 		sin->sin_addr.s_addr = val;
395 		return;
396 	}
397 	hp = gethostbyname(s);
398 	if (hp) {
399 		sin->sin_family = hp->h_addrtype;
400 		bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
401 		return;
402 	}
403 	np = getnetbyname(s);
404 	if (np) {
405 		sin->sin_family = np->n_addrtype;
406 		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
407 		return;
408 	}
409 	fprintf(stderr, "sliplogin: %s: bad value\n", s);
410 	syslog(LOG_ERR, "%s: bad value\n", s);
411 	exit(1);
412 }
413