]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/sliplogin/sliplogin.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / usr.sbin / sliplogin / sliplogin.c
1 /*-
2  * Copyright (c) 1990, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 static char copyright[] =
36 "@(#) Copyright (c) 1990, 1993\n\
37         The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 static char sccsid[] = "@(#)sliplogin.c 8.2 (Berkeley) 2/1/94";
42 #endif /* not lint */
43
44 /*
45  * sliplogin.c
46  * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!]
47  *
48  * This program initializes its own tty port to be an async TCP/IP interface.
49  * It sets the line discipline to slip, invokes a shell script to initialize
50  * the network interface, then pauses forever waiting for hangup.
51  *
52  * It is a remote descendant of several similar programs with incestuous ties:
53  * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL.
54  * - slattach, probably by Rick Adams but touched by countless hordes.
55  * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it.
56  *
57  * There are two forms of usage:
58  *
59  * "sliplogin"
60  * Invoked simply as "sliplogin", the program looks up the username
61  * in the file /etc/slip.hosts.
62  * If an entry is found, the line on fd0 is configured for SLIP operation
63  * as specified in the file.
64  *
65  * "sliplogin IPhostlogin </dev/ttyb"
66  * Invoked by root with a username, the name is looked up in the
67  * /etc/slip.hosts file and if found fd0 is configured as in case 1.
68  */
69
70 #include <sys/param.h>
71 #include <sys/socket.h>
72 #include <sys/file.h>
73 #include <sys/stat.h>
74 #include <syslog.h>
75 #include <netdb.h>
76
77 #include <termios.h>
78 #include <sys/ioctl.h>
79 #include <net/slip.h>
80 #include <net/if.h>
81
82 #include <stdio.h>
83 #include <errno.h>
84 #include <ctype.h>
85 #include <string.h>
86 #include <unistd.h>
87 #include <stdlib.h>
88 #include <signal.h>
89 #include "pathnames.h"
90
91 extern char **environ;
92
93 static char *restricted_environ[] = {
94         "PATH=" _PATH_STDPATH,
95         NULL
96 };
97
98 int     unit;
99 int     slip_mode;
100 speed_t speed;
101 int     uid;
102 int     keepal;
103 int     outfill;
104 int     slunit;
105 char    loginargs[BUFSIZ];
106 char    loginfile[MAXPATHLEN];
107 char    loginname[BUFSIZ];
108 static char raddr[32];                  /* remote address */
109 char ifname[IFNAMSIZ];                  /* interface name */
110 static  char pidfilename[MAXPATHLEN];   /* name of pid file */
111 static  char iffilename[MAXPATHLEN];    /* name of if file */
112 static  pid_t   pid;                    /* our pid */
113
114 char *
115 make_ipaddr(void)
116 {
117 static char address[20] ="";
118 struct hostent *he;
119 unsigned long ipaddr;
120 int i;
121
122 address[0] = '\0';
123 if ((he = gethostbyname(raddr)) != NULL) {
124         ipaddr = ntohl(*(long *)he->h_addr_list[0]);
125         sprintf(address, "%lu.%lu.%lu.%lu",
126                 ipaddr >> 24,
127                 (ipaddr & 0x00ff0000) >> 16,
128                 (ipaddr & 0x0000ff00) >> 8,
129                 (ipaddr & 0x000000ff));
130         }
131
132 return address;
133 }
134
135 struct slip_modes {
136         char    *sm_name;
137         int     sm_or_flag;
138         int     sm_and_flag;
139 }        modes[] = {
140         "normal",       0        , 0        ,
141         "compress",     IFF_LINK0, IFF_LINK2,
142         "noicmp",       IFF_LINK1, 0        ,
143         "autocomp",     IFF_LINK2, IFF_LINK0,
144 };
145
146 void
147 findid(name)
148         char *name;
149 {
150         FILE *fp;
151         static char slopt[5][16];
152         static char laddr[16];
153         static char mask[16];
154         char   slparmsfile[MAXPATHLEN];
155         char user[16];
156         char buf[128];
157         int i, j, n;
158
159         environ = restricted_environ; /* minimal protection for system() */
160
161         (void)strncpy(loginname, name, sizeof(loginname)-1);
162         loginname[sizeof(loginname)-1] = '\0';
163
164         if ((fp = fopen(_PATH_ACCESS, "r")) == NULL) {
165         accfile_err:
166                 syslog(LOG_ERR, "%s: %m\n", _PATH_ACCESS);
167                 exit(1);
168         }
169         while (fgets(loginargs, sizeof(loginargs) - 1, fp)) {
170                 if (ferror(fp))
171                         goto accfile_err;
172                 if (loginargs[0] == '#' || isspace(loginargs[0]))
173                         continue;
174                 n = sscanf(loginargs, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
175                         user, laddr, raddr, mask, slopt[0], slopt[1],
176                         slopt[2], slopt[3], slopt[4]);
177                 if (n < 4) {
178                         syslog(LOG_ERR, "%s: wrong format\n", _PATH_ACCESS);
179                         exit(1);
180                 }
181                 if (strcmp(user, name) != 0)
182                         continue;
183
184                 (void) fclose(fp);
185
186                 slip_mode = 0;
187                 for (i = 0; i < n - 4; i++) {
188                         for (j = 0; j < sizeof(modes)/sizeof(struct slip_modes);
189                                 j++) {
190                                 if (strcmp(modes[j].sm_name, slopt[i]) == 0) {
191                                         slip_mode |= (modes[j].sm_or_flag);
192                                         slip_mode &= ~(modes[j].sm_and_flag);
193                                         break;
194                                 }
195                         }
196                 }
197
198                 /*
199                  * we've found the guy we're looking for -- see if
200                  * there's a login file we can use.  First check for
201                  * one specific to this host.  If none found, try for
202                  * a generic one.
203                  */
204                 (void)snprintf(loginfile, sizeof(loginfile), "%s.%s", _PATH_LOGIN, name);
205                 if (access(loginfile, R_OK|X_OK) != 0) {
206                         (void)strncpy(loginfile, _PATH_LOGIN, sizeof(loginfile)-1);
207                         loginfile[sizeof(loginfile)-1] = '\0';
208                         if (access(loginfile, R_OK|X_OK)) {
209                                 syslog(LOG_ERR,
210                                        "access denied for %s - no %s\n",
211                                        name, _PATH_LOGIN);
212                                 exit(5);
213                         }
214                 }
215                 (void)snprintf(slparmsfile, sizeof(slparmsfile), "%s.%s", _PATH_SLPARMS, name);
216                 if (access(slparmsfile, R_OK|X_OK) != 0) {
217                         (void)strncpy(slparmsfile, _PATH_SLPARMS, sizeof(slparmsfile)-1);
218                         slparmsfile[sizeof(slparmsfile)-1] = '\0';
219                         if (access(slparmsfile, R_OK|X_OK))
220                                 *slparmsfile = '\0';
221                 }
222                 keepal = outfill = 0;
223                 slunit = -1;
224                 if (*slparmsfile) {
225                         if ((fp = fopen(slparmsfile, "r")) == NULL) {
226                         slfile_err:
227                                 syslog(LOG_ERR, "%s: %m\n", slparmsfile);
228                                 exit(1);
229                         }
230                         n = 0;
231                         while (fgets(buf, sizeof(buf) - 1, fp) != NULL) {
232                                 if (ferror(fp))
233                                         goto slfile_err;
234                                 if (buf[0] == '#' || isspace(buf[0]))
235                                         continue;
236                                 n = sscanf(buf, "%d %d %d", &keepal, &outfill, &slunit);
237                                 if (n < 1) {
238                                 slwrong_fmt:
239                                         syslog(LOG_ERR, "%s: wrong format\n", slparmsfile);
240                                         exit(1);
241                                 }
242                                 (void) fclose(fp);
243                                 break;
244                         }
245                         if (n == 0)
246                                 goto slwrong_fmt;
247                 }
248
249                 return;
250         }
251         syslog(LOG_ERR, "SLIP access denied for %s\n", name);
252         exit(4);
253         /* NOTREACHED */
254 }
255
256 char *
257 sigstr(s)
258         int s;
259 {
260         static char buf[32];
261
262         switch (s) {
263         case SIGHUP:    return("HUP");
264         case SIGINT:    return("INT");
265         case SIGQUIT:   return("QUIT");
266         case SIGILL:    return("ILL");
267         case SIGTRAP:   return("TRAP");
268         case SIGIOT:    return("IOT");
269         case SIGEMT:    return("EMT");
270         case SIGFPE:    return("FPE");
271         case SIGKILL:   return("KILL");
272         case SIGBUS:    return("BUS");
273         case SIGSEGV:   return("SEGV");
274         case SIGSYS:    return("SYS");
275         case SIGPIPE:   return("PIPE");
276         case SIGALRM:   return("ALRM");
277         case SIGTERM:   return("TERM");
278         case SIGURG:    return("URG");
279         case SIGSTOP:   return("STOP");
280         case SIGTSTP:   return("TSTP");
281         case SIGCONT:   return("CONT");
282         case SIGCHLD:   return("CHLD");
283         case SIGTTIN:   return("TTIN");
284         case SIGTTOU:   return("TTOU");
285         case SIGIO:     return("IO");
286         case SIGXCPU:   return("XCPU");
287         case SIGXFSZ:   return("XFSZ");
288         case SIGVTALRM: return("VTALRM");
289         case SIGPROF:   return("PROF");
290         case SIGWINCH:  return("WINCH");
291 #ifdef SIGLOST
292         case SIGLOST:   return("LOST");
293 #endif
294         case SIGUSR1:   return("USR1");
295         case SIGUSR2:   return("USR2");
296         }
297         (void)snprintf(buf, sizeof(buf), "sig %d", s);
298         return(buf);
299 }
300
301 void
302 hup_handler(s)
303         int s;
304 {
305         char logoutfile[MAXPATHLEN];
306
307         (void) close(0);
308         seteuid(0);
309         (void)snprintf(logoutfile, sizeof(logoutfile), "%s.%s", _PATH_LOGOUT, loginname);
310         if (access(logoutfile, R_OK|X_OK) != 0) {
311                 (void)strncpy(logoutfile, _PATH_LOGOUT, sizeof(logoutfile)-1);
312                 logoutfile[sizeof(logoutfile)-1] = '\0';
313         }
314         if (access(logoutfile, R_OK|X_OK) == 0) {
315                 char logincmd[2*MAXPATHLEN+32];
316
317                 (void) snprintf(logincmd, sizeof(logincmd), "%s %d %ld %s", logoutfile, unit, speed, loginargs);
318                 (void) system(logincmd);
319         }
320         syslog(LOG_INFO, "closed %s slip unit %d (%s)\n", loginname, unit,
321                sigstr(s));
322         if (unlink(pidfilename) < 0 && errno != ENOENT)
323                 syslog(LOG_WARNING, "unable to delete pid file: %m");
324         if (unlink(iffilename) < 0 && errno != ENOENT)
325                 syslog(LOG_WARNING, "unable to delete if file: %m");
326         exit(1);
327         /* NOTREACHED */
328 }
329
330
331 /* Modify the slip line mode and add any compression or no-icmp flags. */
332 void line_flags(unit)
333         int unit;
334 {
335         struct ifreq ifr;
336         int s;
337
338         /* open a socket as the handle to the interface */
339         s = socket(AF_INET, SOCK_DGRAM, 0);
340         if (s < 0) {
341                 syslog(LOG_ERR, "socket: %m");
342                 exit(1);
343         }
344         sprintf(ifr.ifr_name, "sl%d", unit);
345
346         /* get the flags for the interface */
347         if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
348                 syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
349                 exit(1);
350         }
351
352         /* Assert any compression or no-icmp flags. */
353 #define SLMASK (~(IFF_LINK0 | IFF_LINK1 | IFF_LINK2))
354         ifr.ifr_flags &= SLMASK;
355         ifr.ifr_flags |= slip_mode;
356         if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
357                 syslog(LOG_ERR, "ioctl (SIOCSIFFLAGS): %m");
358                 exit(1);
359         }
360         close(s);
361 }
362
363
364 main(argc, argv)
365         int argc;
366         char *argv[];
367 {
368         int fd, s, ldisc;
369         char *name;
370         struct termios tios, otios;
371         char logincmd[2*BUFSIZ+32];
372         extern uid_t getuid();
373
374         FILE *pidfile;                          /* pid file */
375         FILE *iffile;                           /* interfaces file */
376         char *p;
377         int n;
378         char devnam[MAXPATHLEN] = "/dev/tty";   /* Device name */
379
380         if ((name = strrchr(argv[0], '/')) == NULL)
381                 name = argv[0];
382         s = getdtablesize();
383         for (fd = 3 ; fd < s ; fd++)
384                 (void) close(fd);
385         openlog(name, LOG_PID|LOG_PERROR, LOG_DAEMON);
386         uid = getuid();
387         if (argc > 1) {
388                 findid(argv[1]);
389
390                 /*
391                  * Disassociate from current controlling terminal, if any,
392                  * and ensure that the slip line is our controlling terminal.
393                  */
394                 if (daemon(1, 1)) {
395                         syslog(LOG_ERR, "daemon(1, 1): %m");
396                         exit(1);
397                 }
398                 if (argc > 2) {
399                         if ((fd = open(argv[2], O_RDWR)) == -1) {
400                                 syslog(LOG_ERR, "open %s: %m", argv[2]);
401                                 exit(2);
402                         }
403                         (void) dup2(fd, 0);
404                         if (fd > 2)
405                                 close(fd);
406                 }
407                 if (ioctl(0, TIOCSCTTY, 0) == -1) {
408                         syslog(LOG_ERR, "ioctl (TIOCSCTTY): %m");
409                         exit(1);
410                 }
411                 if (tcsetpgrp(0, getpid()) < 0) {
412                         syslog(LOG_ERR, "tcsetpgrp failed: %m");
413                         exit(1);
414                 }
415         } else {
416                 if ((name = getlogin()) == NULL) {
417                         syslog(LOG_ERR, "access denied - login name not found\n");
418                         exit(1);
419                 }
420                 findid(name);
421         }
422         (void) fchmod(0, 0600);
423         (void) fprintf(stderr, "starting slip login for %s\n", loginname);
424         (void) fprintf(stderr, "your address is %s\n\n", make_ipaddr());
425
426         (void) fflush(stderr);
427         sleep(1);
428
429         /* set up the line parameters */
430         if (tcgetattr(0, &tios) < 0) {
431                 syslog(LOG_ERR, "tcgetattr: %m");
432                 exit(1);
433         }
434         otios = tios;
435         cfmakeraw(&tios);
436         if (tcsetattr(0, TCSAFLUSH, &tios) < 0) {
437                 syslog(LOG_ERR, "tcsetattr: %m");
438                 exit(1);
439         }
440         speed = cfgetispeed(&tios);
441
442         ldisc = SLIPDISC;
443         if (ioctl(0, TIOCSETD, &ldisc) < 0) {
444                 syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
445                 exit(1);
446         }
447         if (slunit >= 0 && ioctl(0, SLIOCSUNIT, &slunit) < 0) {
448                 syslog(LOG_ERR, "ioctl (SLIOCSUNIT): %m");
449                 exit(1);
450         }
451         /* find out what unit number we were assigned */
452         if (ioctl(0, SLIOCGUNIT, &unit) < 0) {
453                 syslog(LOG_ERR, "ioctl (SLIOCGUNIT): %m");
454                 exit(1);
455         }
456         (void) signal(SIGHUP, hup_handler);
457         (void) signal(SIGTERM, hup_handler);
458
459         if (keepal > 0) {
460                 (void) signal(SIGURG, hup_handler);
461                 if (ioctl(0, SLIOCSKEEPAL, &keepal) < 0) {
462                         syslog(LOG_ERR, "ioctl(SLIOCSKEEPAL): %m");
463                         exit(1);
464                 }
465         }
466         if (outfill > 0 && ioctl(0, SLIOCSOUTFILL, &outfill) < 0) {
467                 syslog(LOG_ERR, "ioctl(SLIOCSOUTFILL): %m");
468                 exit(1);
469         }
470
471         /* write pid to file */
472         pid = getpid();
473         (void) sprintf(ifname, "sl%d", unit);
474         (void) sprintf(pidfilename, "%s%s.pid", _PATH_VARRUN, ifname);
475         if ((pidfile = fopen(pidfilename, "w")) != NULL) {
476                 fprintf(pidfile, "%d\n", pid);
477                 (void) fclose(pidfile);
478         } else {
479                 syslog(LOG_ERR, "Failed to create pid file %s: %m",
480                                 pidfilename);
481                 pidfilename[0] = 0;
482         }
483
484         /* write interface unit number to file */
485         p = ttyname(0);
486         if (p)
487                 strcpy(devnam, p);
488         for (n = strlen(devnam); n > 0; n--) 
489                 if (devnam[n] == '/') {
490                         n++;
491                         break;
492                 }
493         (void) sprintf(iffilename, "%s%s.if", _PATH_VARRUN, &devnam[n]);
494         if ((iffile = fopen(iffilename, "w")) != NULL) {
495                 fprintf(iffile, "sl%d\n", unit); 
496                 (void) fclose(iffile);
497         } else {
498                 syslog(LOG_ERR, "Failed to create if file %s: %m", iffilename);
499                 iffilename[0] = 0;  
500         }
501
502
503         syslog(LOG_INFO, "attaching slip unit %d for %s\n", unit, loginname);
504         (void)snprintf(logincmd, sizeof(logincmd), "%s %d %ld %s", loginfile, unit, speed,
505                       loginargs);
506         /*
507          * aim stdout and errout at /dev/null so logincmd output won't
508          * babble into the slip tty line.
509          */
510         (void) close(1);
511         if ((fd = open(_PATH_DEVNULL, O_WRONLY)) != 1) {
512                 if (fd < 0) {
513                         syslog(LOG_ERR, "open /dev/null: %m");
514                         exit(1);
515                 }
516                 (void) dup2(fd, 1);
517                 (void) close(fd);
518         }
519         (void) dup2(1, 2);
520
521         /*
522          * Run login and logout scripts as root (real and effective);
523          * current route(8) is setuid root, and checks the real uid
524          * to see whether changes are allowed (or just "route get").
525          */
526         (void) setuid(0);
527         if (s = system(logincmd)) {
528                 syslog(LOG_ERR, "%s login failed: exit status %d from %s",
529                        loginname, s, loginfile);
530                 exit(6);
531         }
532
533         /* Handle any compression or no-icmp flags. */
534         line_flags(unit);
535
536         /* reset uid to users' to allow the user to give a signal. */
537         seteuid(uid);
538         /* twiddle thumbs until we get a signal */
539         while (1)
540                 sigpause(0);
541
542         /* NOTREACHED */
543 }