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