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