1b88df7feSbostic /*-
29122c3bfSbostic * Copyright (c) 1990, 1993
39122c3bfSbostic * The Regents of the University of California. All rights reserved.
4b88df7feSbostic *
5b88df7feSbostic * %sccs.include.redist.c%
6b88df7feSbostic */
7b88df7feSbostic
8a14e21ddSsam #ifndef lint
99122c3bfSbostic static char copyright[] =
109122c3bfSbostic "@(#) Copyright (c) 1990, 1993\n\
119122c3bfSbostic The Regents of the University of California. All rights reserved.\n";
12b88df7feSbostic #endif /* not lint */
13b88df7feSbostic
14b88df7feSbostic #ifndef lint
15*3d29b849Scgd static char sccsid[] = "@(#)sliplogin.c 8.2 (Berkeley) 02/01/94";
16b88df7feSbostic #endif /* not lint */
17b88df7feSbostic
18a14e21ddSsam /*
19a14e21ddSsam * sliplogin.c
20a18a0028Skarels * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!]
21a14e21ddSsam *
22a14e21ddSsam * This program initializes its own tty port to be an async TCP/IP interface.
23aa9b0ccbStrent * It sets the line discipline to slip, invokes a shell script to initialize
24aa9b0ccbStrent * the network interface, then pauses forever waiting for hangup.
25a14e21ddSsam *
26a14e21ddSsam * It is a remote descendant of several similar programs with incestuous ties:
27a14e21ddSsam * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL.
28a14e21ddSsam * - slattach, probably by Rick Adams but touched by countless hordes.
29a14e21ddSsam * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it.
30a14e21ddSsam *
31aa9b0ccbStrent * There are two forms of usage:
32a14e21ddSsam *
33a14e21ddSsam * "sliplogin"
34c4a0303eSkarels * Invoked simply as "sliplogin", the program looks up the username
35c4a0303eSkarels * in the file /etc/slip.hosts.
36c4a0303eSkarels * If an entry is found, the line on fd0 is configured for SLIP operation
37a14e21ddSsam * as specified in the file.
38a14e21ddSsam *
39c4a0303eSkarels * "sliplogin IPhostlogin </dev/ttyb"
40a14e21ddSsam * Invoked by root with a username, the name is looked up in the
41c4a0303eSkarels * /etc/slip.hosts file and if found fd0 is configured as in case 1.
42a14e21ddSsam */
43a14e21ddSsam
44aa9b0ccbStrent #include <sys/param.h>
45a14e21ddSsam #include <sys/socket.h>
467ada4fb7Sbostic #include <sys/signal.h>
47a14e21ddSsam #include <sys/file.h>
48a14e21ddSsam #include <sys/syslog.h>
49a14e21ddSsam #include <netdb.h>
507ada4fb7Sbostic
51c4a0303eSkarels #if BSD >= 199006
52c4a0303eSkarels #define POSIX
53aa9b0ccbStrent #endif
54c4a0303eSkarels #ifdef POSIX
55aa9b0ccbStrent #include <sys/termios.h>
56c4a0303eSkarels #include <sys/ioctl.h>
57a14e21ddSsam #include <ttyent.h>
58c4a0303eSkarels #else
59c4a0303eSkarels #include <sgtty.h>
60aa9b0ccbStrent #endif
61*3d29b849Scgd #include <net/slip.h>
62ca1574aaSsam
637ada4fb7Sbostic #include <stdio.h>
647ada4fb7Sbostic #include <errno.h>
657ada4fb7Sbostic #include <ctype.h>
667ada4fb7Sbostic #include <string.h>
677ada4fb7Sbostic #include "pathnames.h"
685347ed73Ssam
69aa9b0ccbStrent int unit;
70aa9b0ccbStrent int speed;
71c4a0303eSkarels int uid;
72aa9b0ccbStrent char loginargs[BUFSIZ];
73c4a0303eSkarels char loginfile[MAXPATHLEN];
74aa9b0ccbStrent char loginname[BUFSIZ];
75a18a0028Skarels
76a18a0028Skarels void
findid(name)77aa9b0ccbStrent findid(name)
78aa9b0ccbStrent char *name;
79aa9b0ccbStrent {
80aa9b0ccbStrent FILE *fp;
81aa9b0ccbStrent static char slopt[5][16];
82aa9b0ccbStrent static char laddr[16];
83aa9b0ccbStrent static char raddr[16];
84aa9b0ccbStrent static char mask[16];
85aa9b0ccbStrent char user[16];
86aa9b0ccbStrent int i, j, n;
87aa9b0ccbStrent
88aa9b0ccbStrent (void)strcpy(loginname, name);
897ada4fb7Sbostic if ((fp = fopen(_PATH_ACCESS, "r")) == NULL) {
907ada4fb7Sbostic (void)fprintf(stderr, "sliplogin: %s: %s\n",
917ada4fb7Sbostic _PATH_ACCESS, strerror(errno));
927ada4fb7Sbostic syslog(LOG_ERR, "%s: %m\n", _PATH_ACCESS);
937ada4fb7Sbostic exit(1);
94aa9b0ccbStrent }
95aa9b0ccbStrent while (fgets(loginargs, sizeof(loginargs) - 1, fp)) {
96aa9b0ccbStrent if (ferror(fp))
97aa9b0ccbStrent break;
98aa9b0ccbStrent n = sscanf(loginargs, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
99aa9b0ccbStrent user, laddr, raddr, mask, slopt[0], slopt[1],
100aa9b0ccbStrent slopt[2], slopt[3], slopt[4]);
101aa9b0ccbStrent if (user[0] == '#' || isspace(user[0]))
102aa9b0ccbStrent continue;
103aa9b0ccbStrent if (strcmp(user, name) != 0)
104aa9b0ccbStrent continue;
105aa9b0ccbStrent
106aa9b0ccbStrent /*
107aa9b0ccbStrent * we've found the guy we're looking for -- see if
108aa9b0ccbStrent * there's a login file we can use. First check for
109aa9b0ccbStrent * one specific to this host. If none found, try for
110aa9b0ccbStrent * a generic one.
111aa9b0ccbStrent */
1127ada4fb7Sbostic (void)sprintf(loginfile, "%s.%s", _PATH_LOGIN, name);
113c4a0303eSkarels if (access(loginfile, R_OK|X_OK) != 0) {
1147ada4fb7Sbostic (void)strcpy(loginfile, _PATH_LOGIN);
115aa9b0ccbStrent if (access(loginfile, R_OK|X_OK)) {
116aa9b0ccbStrent fputs("access denied - no login file\n",
117aa9b0ccbStrent stderr);
118aa9b0ccbStrent syslog(LOG_ERR,
119aa9b0ccbStrent "access denied for %s - no %s\n",
1207ada4fb7Sbostic name, _PATH_LOGIN);
121aa9b0ccbStrent exit(5);
122aa9b0ccbStrent }
123c4a0303eSkarels }
124aa9b0ccbStrent
125aa9b0ccbStrent (void) fclose(fp);
126aa9b0ccbStrent return;
127aa9b0ccbStrent }
128aa9b0ccbStrent (void)fprintf(stderr, "SLIP access denied for %s\n", name);
129aa9b0ccbStrent syslog(LOG_ERR, "SLIP access denied for %s\n", name);
130aa9b0ccbStrent exit(4);
131aa9b0ccbStrent /* NOTREACHED */
132aa9b0ccbStrent }
133aa9b0ccbStrent
134aa9b0ccbStrent char *
sigstr(s)135aa9b0ccbStrent sigstr(s)
136aa9b0ccbStrent int s;
137aa9b0ccbStrent {
138aa9b0ccbStrent static char buf[32];
139aa9b0ccbStrent
140aa9b0ccbStrent switch (s) {
141aa9b0ccbStrent case SIGHUP: return("HUP");
142aa9b0ccbStrent case SIGINT: return("INT");
143aa9b0ccbStrent case SIGQUIT: return("QUIT");
144aa9b0ccbStrent case SIGILL: return("ILL");
145aa9b0ccbStrent case SIGTRAP: return("TRAP");
146aa9b0ccbStrent case SIGIOT: return("IOT");
147aa9b0ccbStrent case SIGEMT: return("EMT");
148aa9b0ccbStrent case SIGFPE: return("FPE");
149aa9b0ccbStrent case SIGKILL: return("KILL");
150aa9b0ccbStrent case SIGBUS: return("BUS");
151aa9b0ccbStrent case SIGSEGV: return("SEGV");
152aa9b0ccbStrent case SIGSYS: return("SYS");
153aa9b0ccbStrent case SIGPIPE: return("PIPE");
154aa9b0ccbStrent case SIGALRM: return("ALRM");
155aa9b0ccbStrent case SIGTERM: return("TERM");
156aa9b0ccbStrent case SIGURG: return("URG");
157aa9b0ccbStrent case SIGSTOP: return("STOP");
158aa9b0ccbStrent case SIGTSTP: return("TSTP");
159aa9b0ccbStrent case SIGCONT: return("CONT");
160aa9b0ccbStrent case SIGCHLD: return("CHLD");
161aa9b0ccbStrent case SIGTTIN: return("TTIN");
162aa9b0ccbStrent case SIGTTOU: return("TTOU");
163aa9b0ccbStrent case SIGIO: return("IO");
164aa9b0ccbStrent case SIGXCPU: return("XCPU");
165aa9b0ccbStrent case SIGXFSZ: return("XFSZ");
166aa9b0ccbStrent case SIGVTALRM: return("VTALRM");
167aa9b0ccbStrent case SIGPROF: return("PROF");
168aa9b0ccbStrent case SIGWINCH: return("WINCH");
169aa9b0ccbStrent #ifdef SIGLOST
170aa9b0ccbStrent case SIGLOST: return("LOST");
171aa9b0ccbStrent #endif
172aa9b0ccbStrent case SIGUSR1: return("USR1");
173aa9b0ccbStrent case SIGUSR2: return("USR2");
174aa9b0ccbStrent }
175aa9b0ccbStrent (void)sprintf(buf, "sig %d", s);
176aa9b0ccbStrent return(buf);
177aa9b0ccbStrent }
178aa9b0ccbStrent
17927d38c72Sbostic void
hup_handler(s)1805347ed73Ssam hup_handler(s)
1815347ed73Ssam int s;
182a18a0028Skarels {
183c4a0303eSkarels char logoutfile[MAXPATHLEN];
184c4a0303eSkarels
185c4a0303eSkarels (void)sprintf(logoutfile, "%s.%s", _PATH_LOGOUT, loginname);
186c4a0303eSkarels if (access(logoutfile, R_OK|X_OK) != 0)
187c4a0303eSkarels (void)strcpy(logoutfile, _PATH_LOGOUT);
188aa9b0ccbStrent if (access(logoutfile, R_OK|X_OK) == 0) {
189c4a0303eSkarels char logincmd[2*MAXPATHLEN+32];
1905347ed73Ssam
191aa9b0ccbStrent (void) sprintf(logincmd, "%s %d %d %s", logoutfile, unit, speed,
192aa9b0ccbStrent loginargs);
193aa9b0ccbStrent (void) system(logincmd);
194aa9b0ccbStrent }
195aa9b0ccbStrent (void) close(0);
196aa9b0ccbStrent syslog(LOG_INFO, "closed %s slip unit %d (%s)\n", loginname, unit,
197aa9b0ccbStrent sigstr(s));
198a18a0028Skarels exit(1);
199aa9b0ccbStrent /* NOTREACHED */
200a18a0028Skarels }
201a14e21ddSsam
main(argc,argv)202a14e21ddSsam main(argc, argv)
203a14e21ddSsam int argc;
204a14e21ddSsam char *argv[];
205a14e21ddSsam {
206a18a0028Skarels int fd, s, ldisc, odisc;
207aa9b0ccbStrent char *name;
208c4a0303eSkarels #ifdef POSIX
209a18a0028Skarels struct termios tios, otios;
210aa9b0ccbStrent #else
211aa9b0ccbStrent struct sgttyb tty, otty;
212aa9b0ccbStrent #endif
213aa9b0ccbStrent char logincmd[2*BUFSIZ+32];
214aa9b0ccbStrent extern uid_t getuid();
215a14e21ddSsam
216aa9b0ccbStrent if ((name = strrchr(argv[0], '/')) == NULL)
217aa9b0ccbStrent name = argv[0];
218a14e21ddSsam s = getdtablesize();
219a14e21ddSsam for (fd = 3 ; fd < s ; fd++)
220aa9b0ccbStrent (void) close(fd);
221aa9b0ccbStrent openlog(name, LOG_PID, LOG_DAEMON);
222c4a0303eSkarels uid = getuid();
223aa9b0ccbStrent if (argc > 1) {
224a14e21ddSsam findid(argv[1]);
225aa9b0ccbStrent
2265347ed73Ssam /*
2275347ed73Ssam * Disassociate from current controlling terminal, if any,
2285347ed73Ssam * and ensure that the slip line is our controlling terminal.
2295347ed73Ssam */
230c4a0303eSkarels #ifdef POSIX
231c4a0303eSkarels if (fork() > 0)
232c4a0303eSkarels exit(0);
233c4a0303eSkarels if (setsid() != 0)
234c4a0303eSkarels perror("setsid");
235aa9b0ccbStrent #else
236a14e21ddSsam if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
237aa9b0ccbStrent extern char *ttyname();
238aa9b0ccbStrent
239aa9b0ccbStrent (void) ioctl(fd, TIOCNOTTY, (caddr_t)0);
240a14e21ddSsam (void) close(fd);
2415347ed73Ssam /* open slip tty again to acquire as controlling tty? */
242a18a0028Skarels fd = open(ttyname(0), O_RDWR, 0);
243a18a0028Skarels if (fd >= 0)
244a18a0028Skarels (void) close(fd);
245a18a0028Skarels }
2465347ed73Ssam (void) setpgrp(0, getpid());
2475347ed73Ssam #endif
248c4a0303eSkarels if (argc > 2) {
249c4a0303eSkarels if ((fd = open(argv[2], O_RDWR)) == -1) {
250c4a0303eSkarels perror(argv[2]);
251c4a0303eSkarels exit(2);
252c4a0303eSkarels }
253c4a0303eSkarels (void) dup2(fd, 0);
254c4a0303eSkarels if (fd > 2)
255c4a0303eSkarels close(fd);
256c4a0303eSkarels }
257c4a0303eSkarels #ifdef TIOCSCTTY
258c4a0303eSkarels if (ioctl(0, TIOCSCTTY, (caddr_t)0) != 0)
259c4a0303eSkarels perror("ioctl (TIOCSCTTY)");
260c4a0303eSkarels #endif
261aa9b0ccbStrent } else {
262c4a0303eSkarels extern char *getlogin();
263aa9b0ccbStrent
264c4a0303eSkarels if ((name = getlogin()) == NULL) {
265aa9b0ccbStrent (void) fprintf(stderr, "access denied - no username\n");
266c4a0303eSkarels syslog(LOG_ERR, "access denied - getlogin returned 0\n");
267aa9b0ccbStrent exit(1);
268aa9b0ccbStrent }
269aa9b0ccbStrent findid(name);
270aa9b0ccbStrent }
271aa9b0ccbStrent (void) fchmod(0, 0600);
272aa9b0ccbStrent (void) fprintf(stderr, "starting slip login for %s\n", loginname);
273c4a0303eSkarels #ifdef POSIX
274a14e21ddSsam /* set up the line parameters */
275c4a0303eSkarels if (tcgetattr(0, &tios) < 0) {
276c4a0303eSkarels syslog(LOG_ERR, "tcgetattr: %m");
277a14e21ddSsam exit(1);
278a14e21ddSsam }
279a18a0028Skarels otios = tios;
280c4a0303eSkarels cfmakeraw(&tios);
281c4a0303eSkarels tios.c_iflag &= ~IMAXBEL;
282c4a0303eSkarels if (tcsetattr(0, TCSAFLUSH, &tios) < 0) {
283c4a0303eSkarels syslog(LOG_ERR, "tcsetattr: %m");
284a18a0028Skarels exit(1);
285a18a0028Skarels }
286c4a0303eSkarels speed = cfgetispeed(&tios);
287aa9b0ccbStrent #else
288aa9b0ccbStrent /* set up the line parameters */
289aa9b0ccbStrent if (ioctl(0, TIOCGETP, (caddr_t)&tty) < 0) {
290aa9b0ccbStrent syslog(LOG_ERR, "ioctl (TIOCGETP): %m");
291aa9b0ccbStrent exit(1);
292aa9b0ccbStrent }
293aa9b0ccbStrent otty = tty;
294aa9b0ccbStrent speed = tty.sg_ispeed;
295aa9b0ccbStrent tty.sg_flags = RAW | ANYP;
296aa9b0ccbStrent if (ioctl(0, TIOCSETP, (caddr_t)&tty) < 0) {
297aa9b0ccbStrent syslog(LOG_ERR, "ioctl (TIOCSETP): %m");
298aa9b0ccbStrent exit(1);
299aa9b0ccbStrent }
300aa9b0ccbStrent #endif
301a18a0028Skarels /* find out what ldisc we started with */
302a18a0028Skarels if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) {
303a18a0028Skarels syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m");
304a14e21ddSsam exit(1);
305a14e21ddSsam }
306ca1574aaSsam ldisc = SLIPDISC;
307ca1574aaSsam if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) {
3085347ed73Ssam syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
309a14e21ddSsam exit(1);
310a14e21ddSsam }
311a14e21ddSsam /* find out what unit number we were assigned */
312c4a0303eSkarels if (ioctl(0, SLIOCGUNIT, (caddr_t)&unit) < 0) {
313f0479b09Skarels syslog(LOG_ERR, "ioctl (SLIOCGUNIT): %m");
314a14e21ddSsam exit(1);
315a14e21ddSsam }
316aa9b0ccbStrent (void) signal(SIGHUP, hup_handler);
317aa9b0ccbStrent (void) signal(SIGTERM, hup_handler);
318aa9b0ccbStrent
319aa9b0ccbStrent syslog(LOG_INFO, "attaching slip unit %d for %s\n", unit, loginname);
320aa9b0ccbStrent (void)sprintf(logincmd, "%s %d %d %s", loginfile, unit, speed,
321aa9b0ccbStrent loginargs);
322aa9b0ccbStrent /*
323aa9b0ccbStrent * aim stdout and errout at /dev/null so logincmd output won't
324aa9b0ccbStrent * babble into the slip tty line.
325aa9b0ccbStrent */
326aa9b0ccbStrent (void) close(1);
32727d38c72Sbostic if ((fd = open(_PATH_DEVNULL, O_WRONLY)) != 1) {
328aa9b0ccbStrent if (fd < 0) {
329aa9b0ccbStrent syslog(LOG_ERR, "open /dev/null: %m");
330a14e21ddSsam exit(1);
331a14e21ddSsam }
332aa9b0ccbStrent (void) dup2(fd, 1);
333aa9b0ccbStrent (void) close(fd);
334a14e21ddSsam }
335aa9b0ccbStrent (void) dup2(1, 2);
336c4a0303eSkarels
337c4a0303eSkarels /*
338c4a0303eSkarels * Run login and logout scripts as root (real and effective);
339c4a0303eSkarels * current route(8) is setuid root, and checks the real uid
340c4a0303eSkarels * to see whether changes are allowed (or just "route get").
341c4a0303eSkarels */
342c4a0303eSkarels (void) setuid(0);
343aa9b0ccbStrent if (s = system(logincmd)) {
344aa9b0ccbStrent syslog(LOG_ERR, "%s login failed: exit status %d from %s",
345aa9b0ccbStrent loginname, s, loginfile);
346aa9b0ccbStrent (void) ioctl(0, TIOCSETD, (caddr_t)&odisc);
347aa9b0ccbStrent exit(6);
348a14e21ddSsam }
349a14e21ddSsam
350a14e21ddSsam /* twiddle thumbs until we get a signal */
351aa9b0ccbStrent while (1)
352a14e21ddSsam sigpause(0);
353a14e21ddSsam
354aa9b0ccbStrent /* NOTREACHED */
355a14e21ddSsam }
356