138272Ssam #ifndef lint 2*40016Ssam static char sccsid[] = "@(#)sliplogin.c 1.4 (Berkeley) 02/06/90"; 3*40016Ssam /* from static char *sccsid = "@(#)sliplogin.c 1.3 MS/ACF 89/04/18"; */ 438272Ssam #endif 538272Ssam 638272Ssam /* 738272Ssam * sliplogin.c 838373Skarels * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!] 938272Ssam * 1038272Ssam * This program initializes its own tty port to be an async TCP/IP interface. 1138272Ssam * It merely sets up the SLIP module all by its lonesome on the STREAMS stack, 1238272Ssam * initializes the network interface, and pauses forever waiting for hangup. 1338272Ssam * 1438272Ssam * It is a remote descendant of several similar programs with incestuous ties: 1538272Ssam * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL. 1638272Ssam * - slattach, probably by Rick Adams but touched by countless hordes. 1738272Ssam * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it. 1838272Ssam * - a simple slattach-like program used to test the STREAMS SLIP code. 1938272Ssam * 2038272Ssam * There are three basic forms of usage: 2138272Ssam * 2238272Ssam * "sliplogin" 2338272Ssam * Invoked simply as "sliplogin" and a realuid != 0, the program looks up 2438272Ssam * the uid in /etc/passwd, and then the username in the file /etc/hosts.slip. 2538272Ssam * If and entry is found, the line on fd0 is configured for SLIP operation 2638272Ssam * as specified in the file. 2738272Ssam * 2838272Ssam * "sliplogin IPhost1 </dev/ttyb" 2938272Ssam * Invoked by root with a username, the name is looked up in the 3038272Ssam * /etc/hosts.slip file and if found fd0 is configured as in case 1. 3138272Ssam * 3238272Ssam * "sliplogin 192.100.1.1 192.100.1.2 255.255.255.0 < /dev/ttyb" 3338272Ssam * Finally, if invoked with a remote addr, local addr, and optionally 3438272Ssam * a net mask, the line on fd0 is setup as specified if the user is root. 3538272Ssam * 3638272Ssam * Doug Kingston 8810?? - logging + first pass at adding I_STR ioctl's 3738272Ssam * Rayan Zachariassen 881011 - version for SunOS STREAMS SLIP 3838272Ssam */ 3938272Ssam 4038272Ssam #include <sys/types.h> 4138272Ssam #include <sys/socket.h> 4238272Ssam #include <sys/termios.h> 4338372Ssam #include <sys/ioctl.h> 4438272Ssam #include <sys/file.h> 4538272Ssam #include <sys/syslog.h> 4638272Ssam 4738272Ssam #include <netinet/in.h> 4838272Ssam #include <net/if.h> 4938373Skarels #include <net/if_slvar.h> /* XXX */ 5038272Ssam 5138272Ssam #include <stdio.h> 5238272Ssam #include <errno.h> 5338272Ssam #include <ctype.h> 5438272Ssam #include <netdb.h> 5538272Ssam 5638272Ssam #include <signal.h> 5738272Ssam #include <strings.h> 5838272Ssam #include <pwd.h> 5938272Ssam #include <ttyent.h> 6038272Ssam 6138372Ssam #define SLIPIFNAME "sl" 6238372Ssam 6338372Ssam #define ADDR 1 6438372Ssam #define MASK 2 6538372Ssam 66*40016Ssam #define DCD_CHECK_INTERVAL 0 /* if > 0, time between automatic DCD checks */ 6738272Ssam #define DCD_SETTLING_TIME 1 /* time between DCD change and status check */ 6838272Ssam 6938272Ssam int gotalarm = 0; 7038272Ssam int timeleft = DCD_CHECK_INTERVAL; 7138272Ssam 7238272Ssam #if defined(SIGDCD) && SIGDCD > 0 7338272Ssam void 7438272Ssam dcd_handler() 7538272Ssam { 7638272Ssam #if DCD_SETTLING_TIME > 0 7738272Ssam timeleft = alarm(DCD_SETTLING_TIME); 7838272Ssam #else 7938272Ssam gotalarm = 1; 8038272Ssam #endif /* DCD_SETTLING_TIME */ 8138272Ssam } 8238272Ssam #endif 8338272Ssam 84*40016Ssam #if DCD_CHECK_INTERVAL > 0 85*40016Ssam void 86*40016Ssam alarm_handler() 87*40016Ssam { 88*40016Ssam #ifdef SIGDCD 89*40016Ssam if (timeleft > DCD_SETTLING_TIME) 90*40016Ssam (void) alarm(timeleft-DCD_SETTLING_TIME); 91*40016Ssam else 92*40016Ssam #endif /* SIGDCD */ 93*40016Ssam (void) alarm(DCD_CHECK_INTERVAL); 94*40016Ssam gotalarm = 1; 95*40016Ssam timeleft = 0; 96*40016Ssam } 97*40016Ssam 9838272Ssam /* Use TIOCMGET to test if DCD is low on the port of the passed descriptor */ 9938272Ssam 10038272Ssam int 10138272Ssam lowdcd(fd) 10238272Ssam int fd; 10338272Ssam { 10438272Ssam int mbits; 10538272Ssam 10638272Ssam if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0) 10738272Ssam return 1; /* port is dead, we die */ 10838272Ssam return !(mbits & TIOCM_CAR); 10938272Ssam } 110*40016Ssam #endif /* DCD_CHECK_INTERVAL > 0 */ 11138272Ssam 11238272Ssam char *Accessfile = "/etc/hosts.slip"; 11338272Ssam 11438272Ssam extern char *malloc(), *ttyname(); 11538272Ssam extern struct passwd *getpwuid(); 11638272Ssam 11738272Ssam char *dstaddr, *localaddr, *netmask; 11838373Skarels int slip_mode, unit; 11938272Ssam 12038373Skarels struct slip_modes { 12138373Skarels char *sm_name; 12238373Skarels int sm_value; 12338373Skarels } modes[] = { 12438373Skarels "normal", 0, /* slip "standard" ala Rick Adams */ 12538373Skarels "compress", SC_COMPRESS, /* Van Jacobsen's tcp header comp. */ 12638373Skarels "noicmp", SC_NOICMP, /* Sam's(?) ICMP suppression */ 12738373Skarels } ; 12838373Skarels 12938373Skarels void 130*40016Ssam hup_handler(s) 131*40016Ssam int s; 13238373Skarels { 133*40016Ssam 134*40016Ssam syslog(LOG_INFO, 135*40016Ssam "%s%d: connection closed: process aborted, sig %d, remote %s\n", 136*40016Ssam SLIPIFNAME, unit, s, dstaddr); 137*40016Ssam if (close(0) < 0) 138*40016Ssam syslog(LOG_ERR, "(hup) close: %m"); 139*40016Ssam else 140*40016Ssam syslog(LOG_INFO, "(hup) close completed"); 14138373Skarels exit(1) ; 14238373Skarels } 14338373Skarels 14438272Ssam main(argc, argv) 14538272Ssam int argc; 14638272Ssam char *argv[]; 14738272Ssam { 14838373Skarels int fd, s, ldisc, odisc; 14938373Skarels struct termios tios, otios; 15038272Ssam struct ifreq ifr; 15138272Ssam 15238272Ssam s = getdtablesize(); 15338272Ssam for (fd = 3 ; fd < s ; fd++) 15438272Ssam close(fd); 15538272Ssam openlog("sliplogin", LOG_PID, LOG_DAEMON); 15638272Ssam if (getuid() == 0) { 15738272Ssam if (argc <= 1) { 15838272Ssam fprintf(stderr, "Usage: %s loginname\n", argv[0]); 15938272Ssam fprintf(stderr, " or: %s dstaddr localaddr [mask]\n", 16038272Ssam argv[0]); 16138272Ssam exit(1); 16238272Ssam } else if (argc == 2) { 16338272Ssam findid(argv[1]); 16438272Ssam fprintf(stderr, "local %s remote %s mask %s\n", 16538272Ssam localaddr, dstaddr, netmask); 16638272Ssam } if (argc > 2) { 16738272Ssam if (argc < 3 || argc > 4) { 16838272Ssam fprintf(stderr, 16938272Ssam "Usage: %s dstaddr localaddr [mask]\n", 17038272Ssam argv[0]); 17138272Ssam exit(1); 17238272Ssam } 17338272Ssam dstaddr = argv[1]; 17438272Ssam localaddr = argv[2]; 17538272Ssam if (argc == 4) 17638272Ssam netmask = argv[3]; 17738272Ssam else 17838272Ssam netmask = "default"; 17938272Ssam } 180*40016Ssam /* 181*40016Ssam * Disassociate from current controlling terminal, if any, 182*40016Ssam * and ensure that the slip line is our controlling terminal. 183*40016Ssam */ 184*40016Ssam #if !defined(BSD) || BSD < 198810 185*40016Ssam if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) { 186*40016Ssam (void) ioctl(fd, TIOCNOTTY, 0); 187*40016Ssam (void) close(fd); 188*40016Ssam /* open slip tty again to acquire as controlling tty? */ 189*40016Ssam fd = open(ttyname(0), O_RDWR, 0); 190*40016Ssam if (fd >= 0) 191*40016Ssam (void) close(fd); 192*40016Ssam } 193*40016Ssam (void) setpgrp(0, getpid()); 194*40016Ssam #else 195*40016Ssam (void) setsid(); 196*40016Ssam (void) ioctl(0, TIOCSCTTY, 0); /* not sure this will work */ 197*40016Ssam #endif 19838272Ssam } else 19938272Ssam findid((char *)0); 20038272Ssam fchmod(0, 0600); 20138272Ssam /* set up the line parameters */ 202*40016Ssam if (ioctl(0, TIOCGETA, (caddr_t)&tios) < 0) { 203*40016Ssam syslog(LOG_ERR, "ioctl (TIOCGETA): %m"); 20438272Ssam exit(1); 20538272Ssam } 206*40016Ssam otios = tios; 207*40016Ssam tios.c_cflag = CS8|CREAD|HUPCL; 20838272Ssam tios.c_iflag = IGNBRK; 20938372Ssam tios.c_oflag = tios.c_lflag = 0; 210*40016Ssam if (ioctl(0, TIOCSETA, (caddr_t)&tios) < 0) { 211*40016Ssam syslog(LOG_ERR, "ioctl (TIOCSETA) (1): %m"); 21238272Ssam exit(1); 21338272Ssam } 21438373Skarels /* find out what ldisc we started with */ 21538373Skarels if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) { 21638373Skarels syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m"); 21738373Skarels exit(1); 21838373Skarels } 21938372Ssam ldisc = SLIPDISC; 22038372Ssam if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) { 221*40016Ssam syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); 22238272Ssam exit(1); 22338272Ssam } 22438272Ssam /* find out what unit number we were assigned */ 22538372Ssam if (ioctl(0, TIOCGETD, (caddr_t)&unit) < 0) { 22638373Skarels syslog(LOG_ERR, "ioctl (TIOCGETD) (2): %m"); 22738272Ssam exit(1); 22838272Ssam } 229*40016Ssam syslog(LOG_INFO, "attaching %s%d: local %s remote %s mask %s\n", 23038372Ssam SLIPIFNAME, unit, localaddr, dstaddr, netmask); 23138372Ssam #ifdef notdef 23238272Ssam /* set the local and remote interface addresses */ 23338272Ssam s = socket(AF_INET, SOCK_DGRAM, 0); 23438272Ssam if (getuid() != 0 || argc == 4) { 23538272Ssam (void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit); 23638372Ssam in_getaddr(netmask, &ifr.ifr_addr, MASK); 23738272Ssam if (ioctl(s, SIOCSIFNETMASK, (caddr_t)&ifr) < 0) { 23838272Ssam syslog(LOG_ERR, "ioctl (SIOCSIFNETMASK): %m"); 23938272Ssam exit(1); 24038272Ssam } 24138272Ssam } 24238272Ssam (void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit); 24338372Ssam in_getaddr(dstaddr, &ifr.ifr_addr, ADDR); 24438272Ssam if (ioctl(s, SIOCSIFDSTADDR, (caddr_t)&ifr) < 0) { 24538272Ssam syslog(LOG_ERR, "ioctl (SIOCSIFDSTADDR): %m"); 24638272Ssam exit(1); 24738272Ssam } 24838272Ssam (void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit); 24938372Ssam in_getaddr(localaddr, &ifr.ifr_addr, ADDR); 25038272Ssam /* this has the side-effect of marking the interface up */ 25138272Ssam if (ioctl(s, SIOCSIFADDR, (caddr_t)&ifr) < 0) { 25238272Ssam syslog(LOG_ERR, "ioctl (SIOCSIFADDR): %m"); 25338272Ssam exit(1); 25438272Ssam } 25538372Ssam #else 25638372Ssam /* XXX -- give up for now and just invoke ifconfig XXX */ 25738372Ssam { char cmd[256]; 25838372Ssam sprintf(cmd, "/sbin/ifconfig %s%d inet %s %s netmask %s", 25938372Ssam SLIPIFNAME, unit, localaddr, dstaddr, netmask); 26038372Ssam system(cmd); 26138372Ssam } 262*40016Ssam #endif 26338373Skarels if (ioctl(0, SLIOCSFLAGS, (caddr_t)&slip_mode) < 0) { 26438373Skarels syslog(LOG_ERR, "ioctl (SLIOCSFLAGS): %m"); 26538373Skarels exit(1); 26638373Skarels } 26738272Ssam 26838272Ssam /* set up signal handlers */ 26938272Ssam #if defined(SIGDCD) && SIGDCD > 0 27038272Ssam (void) signal(SIGDCD, dcd_handler); 27138272Ssam #endif 27238272Ssam (void) sigblock(sigmask(SIGALRM)); 27338373Skarels (void) signal(SIGHUP, hup_handler); 27438373Skarels (void) signal(SIGTERM, hup_handler); 27538272Ssam 276*40016Ssam #if DCD_CHECK_INTERVAL > 0 27738272Ssam /* timeleft = 60 * 60 * 24 * 365 ; (void) alarm(timeleft); */ 278*40016Ssam (void) signal(SIGALRM, alarm_handler); 27938373Skarels (void) alarm(DCD_CHECK_INTERVAL); 280*40016Ssam #endif 28138272Ssam 28238272Ssam /* twiddle thumbs until we get a signal */ 28338272Ssam while (1) { 28438272Ssam sigpause(0); 285*40016Ssam #if DCD_CHECK_INTERVAL > 0 28638272Ssam (void) sigblock(sigmask(SIGALRM)); 28738272Ssam if (gotalarm && lowdcd(0)) 28838272Ssam break; 28938272Ssam gotalarm = 0; 290*40016Ssam #endif /* DCD_CHECK_INTERVAL > 0 */ 29138272Ssam } 29238272Ssam 293*40016Ssam #ifdef notdef 29438373Skarels if (lowdcd(0)) 29538373Skarels syslog(LOG_NOTICE, 29638373Skarels "connection closed: loss of carrier %s%d: remote %s\n", 29738373Skarels SLIPIFNAME, unit, dstaddr); 298*40016Ssam #endif 29938373Skarels 30038373Skarels if (ioctl(0, TIOCSETD, (caddr_t)&odisc) < 0) { 30138373Skarels syslog(LOG_ERR, "ioctl(TIOCSETD) (2): %m"); 30238373Skarels exit(1); 30338373Skarels } 304*40016Ssam if (ioctl(0, TIOCSETA, (caddr_t)&otios) < 0) { 305*40016Ssam syslog(LOG_ERR, "ioctl (TIOCSETA) (2): %m"); 30638373Skarels exit(1); 30738373Skarels } 308*40016Ssam if (close(0) < 0) { 309*40016Ssam syslog(LOG_ERR, "close: %m"); 310*40016Ssam exit(1); 311*40016Ssam } 31238272Ssam exit(0); 31338272Ssam } 31438272Ssam 31538272Ssam findid(name) 31638272Ssam char *name; 31738272Ssam { 31838272Ssam char buf[BUFSIZ]; 31938272Ssam static char mode[16]; 32038272Ssam static char laddr[16]; 32138272Ssam static char raddr[16]; 32238272Ssam static char mask[16]; 32338272Ssam char user[16]; 32438272Ssam FILE *fp; 32538272Ssam struct passwd *pw; 32638272Ssam int n; 32738272Ssam 32838272Ssam if (name == NULL && (pw = getpwuid(getuid())) == NULL) { 32938272Ssam fprintf(stderr, "Your UID (%d) is unknown\n", getuid()); 33038272Ssam syslog(LOG_ERR, "UID (%d) is unknown\n", getuid()); 33138272Ssam exit(1); 33238272Ssam } else if (name == NULL) 33338272Ssam name = pw->pw_name; 33438272Ssam if ((fp = fopen(Accessfile, "r")) == NULL) { 33538272Ssam perror(Accessfile); 33638272Ssam syslog(LOG_ERR, "%s: %m\n", Accessfile); 33738272Ssam exit(3); 33838272Ssam } 33938272Ssam while (fgets(buf, sizeof(buf) - 1, fp)) { 34038272Ssam if (ferror(fp)) 34138272Ssam break; 34238272Ssam n = sscanf(buf, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n", 34338272Ssam user, mode, laddr, raddr, mask); 34438272Ssam if (user[0] == '#' || n != 5) 34538272Ssam continue; 34638272Ssam if (strcmp(user, name) == 0) { 34738373Skarels char *p,*q; int val, i, domore; 34838373Skarels 34938373Skarels p = q = mode; val = 0; 35038373Skarels loop: 35138373Skarels while (isalnum(*p)) p++; 35238373Skarels if(ispunct(*p) || *p == '\0') { 35338373Skarels if(ispunct(*p)) domore = 1; else domore = 0; 35438373Skarels *p++ = '\0' ; 35538373Skarels for (i = 0; i < 35638373Skarels sizeof(modes)/sizeof(struct slip_modes) 35738373Skarels ; i++) { 35838373Skarels if (strcmp(modes[i].sm_name, q) == 0) { 35938373Skarels val |= modes[i].sm_value ; 36038373Skarels break; 36138373Skarels } ; 36238373Skarels } 36338373Skarels q = p; 36438373Skarels if(domore)goto loop; 36538373Skarels } 36638373Skarels 36738373Skarels slip_mode = val ; 36838272Ssam localaddr = laddr; 36938272Ssam dstaddr = raddr; 37038272Ssam netmask = mask; 37138272Ssam fclose(fp); 37238272Ssam return 0; 37338272Ssam } 37438272Ssam if (feof(fp)) 37538272Ssam break; 37638272Ssam } 37738272Ssam fputs("SLIP access denied\n", stderr); 37838272Ssam syslog(LOG_ERR, "SLIP access denied for %s\n", name); 37938272Ssam exit(4); 38038272Ssam } 38138272Ssam 38238372Ssam in_getaddr(s, saddr, which) 38338272Ssam char *s; 38438272Ssam struct sockaddr *saddr; 38538372Ssam int which; 38638272Ssam { 38738272Ssam register struct sockaddr_in *sin = (struct sockaddr_in *)saddr; 38838272Ssam struct hostent *hp; 38938272Ssam struct netent *np; 39038272Ssam int val; 39138272Ssam extern struct in_addr inet_makeaddr(); 39238272Ssam 39338272Ssam bzero((caddr_t)saddr, sizeof *saddr); 39438372Ssam if (which == ADDR) { 39538372Ssam sin->sin_len = sizeof (*sin); 39638372Ssam sin->sin_family = AF_INET; 39738372Ssam } else 39838372Ssam sin->sin_len = 8; 39938272Ssam val = inet_addr(s); 40038272Ssam if (val != -1) { 40138272Ssam sin->sin_addr.s_addr = val; 40238272Ssam return; 40338272Ssam } 40438272Ssam hp = gethostbyname(s); 40538272Ssam if (hp) { 40638272Ssam sin->sin_family = hp->h_addrtype; 40738272Ssam bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length); 40838272Ssam return; 40938272Ssam } 41038272Ssam np = getnetbyname(s); 41138272Ssam if (np) { 41238272Ssam sin->sin_family = np->n_addrtype; 41338272Ssam sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 41438272Ssam return; 41538272Ssam } 41638272Ssam fprintf(stderr, "sliplogin: %s: bad value\n", s); 41738272Ssam syslog(LOG_ERR, "%s: bad value\n", s); 41838272Ssam exit(1); 41938272Ssam } 420