138272Ssam #ifndef lint 238272Ssam static char *sccsid = "@(#)sliplogin.c 1.3 MS/ACF 89/04/18"; 338272Ssam #endif 438272Ssam 538272Ssam /* 638272Ssam * sliplogin.c 7*38373Skarels * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!] 838272Ssam * 938272Ssam * This program initializes its own tty port to be an async TCP/IP interface. 1038272Ssam * It merely sets up the SLIP module all by its lonesome on the STREAMS stack, 1138272Ssam * initializes the network interface, and pauses forever waiting for hangup. 1238272Ssam * 1338272Ssam * It is a remote descendant of several similar programs with incestuous ties: 1438272Ssam * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL. 1538272Ssam * - slattach, probably by Rick Adams but touched by countless hordes. 1638272Ssam * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it. 1738272Ssam * - a simple slattach-like program used to test the STREAMS SLIP code. 1838272Ssam * 1938272Ssam * There are three basic forms of usage: 2038272Ssam * 2138272Ssam * "sliplogin" 2238272Ssam * Invoked simply as "sliplogin" and a realuid != 0, the program looks up 2338272Ssam * the uid in /etc/passwd, and then the username in the file /etc/hosts.slip. 2438272Ssam * If and entry is found, the line on fd0 is configured for SLIP operation 2538272Ssam * as specified in the file. 2638272Ssam * 2738272Ssam * "sliplogin IPhost1 </dev/ttyb" 2838272Ssam * Invoked by root with a username, the name is looked up in the 2938272Ssam * /etc/hosts.slip file and if found fd0 is configured as in case 1. 3038272Ssam * 3138272Ssam * "sliplogin 192.100.1.1 192.100.1.2 255.255.255.0 < /dev/ttyb" 3238272Ssam * Finally, if invoked with a remote addr, local addr, and optionally 3338272Ssam * a net mask, the line on fd0 is setup as specified if the user is root. 3438272Ssam * 3538272Ssam * Doug Kingston 8810?? - logging + first pass at adding I_STR ioctl's 3638272Ssam * Rayan Zachariassen 881011 - version for SunOS STREAMS SLIP 3738272Ssam */ 3838272Ssam 3938272Ssam #include <sys/types.h> 4038272Ssam #include <sys/socket.h> 4138272Ssam #include <sys/termios.h> 4238372Ssam #include <sys/ioctl.h> 4338272Ssam #include <sys/file.h> 4438272Ssam #include <sys/syslog.h> 4538272Ssam 4638272Ssam #include <netinet/in.h> 4738272Ssam #include <net/if.h> 48*38373Skarels #include <net/if_slvar.h> /* XXX */ 4938272Ssam 5038272Ssam #include <stdio.h> 5138272Ssam #include <errno.h> 5238272Ssam #include <ctype.h> 5338272Ssam #include <netdb.h> 5438272Ssam 5538272Ssam #include <signal.h> 5638272Ssam #include <strings.h> 5738272Ssam #include <pwd.h> 5838272Ssam #include <ttyent.h> 5938272Ssam 6038372Ssam #define SLIPIFNAME "sl" 6138372Ssam 6238372Ssam #define ADDR 1 6338372Ssam #define MASK 2 6438372Ssam 65*38373Skarels #define DCD_CHECK_INTERVAL 5 /* if > 0, time between automatic DCD checks */ 6638272Ssam #define DCD_SETTLING_TIME 1 /* time between DCD change and status check */ 6738272Ssam 6838272Ssam int gotalarm = 0; 6938272Ssam int timeleft = DCD_CHECK_INTERVAL; 7038272Ssam 7138272Ssam void 7238272Ssam alarm_handler() 7338272Ssam { 74*38373Skarels /*if (timeleft > DCD_SETTLING_TIME) 7538272Ssam (void) alarm(timeleft-DCD_SETTLING_TIME); 76*38373Skarels else */ 7738272Ssam (void) alarm(DCD_CHECK_INTERVAL); 7838272Ssam gotalarm = 1; 7938272Ssam timeleft = 0; 8038272Ssam } 8138272Ssam 8238272Ssam #if defined(SIGDCD) && SIGDCD > 0 8338272Ssam void 8438272Ssam dcd_handler() 8538272Ssam { 8638272Ssam #if DCD_SETTLING_TIME > 0 8738272Ssam timeleft = alarm(DCD_SETTLING_TIME); 8838272Ssam #else 8938272Ssam gotalarm = 1; 9038272Ssam #endif /* DCD_SETTLING_TIME */ 9138272Ssam } 9238272Ssam #endif 9338272Ssam 9438272Ssam /* Use TIOCMGET to test if DCD is low on the port of the passed descriptor */ 9538272Ssam 9638272Ssam int 9738272Ssam lowdcd(fd) 9838272Ssam int fd; 9938272Ssam { 10038272Ssam int mbits; 10138272Ssam 10238272Ssam if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0) 10338272Ssam return 1; /* port is dead, we die */ 10438272Ssam return !(mbits & TIOCM_CAR); 10538272Ssam } 10638272Ssam 107*38373Skarels /* Use TIOCMGET to test if DTR is low on the port of the passed descriptor */ 108*38373Skarels 109*38373Skarels int 110*38373Skarels lowdtr(fd) 111*38373Skarels int fd; 112*38373Skarels { 113*38373Skarels int mbits; 114*38373Skarels 115*38373Skarels if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0) 116*38373Skarels return 1; /* port is dead, we die */ 117*38373Skarels return ((mbits & TIOCM_DTR) == TIOCM_DTR); 118*38373Skarels } 119*38373Skarels 12038272Ssam char *Accessfile = "/etc/hosts.slip"; 12138272Ssam 12238272Ssam extern char *malloc(), *ttyname(); 12338272Ssam extern struct passwd *getpwuid(); 12438272Ssam 12538272Ssam char *dstaddr, *localaddr, *netmask; 126*38373Skarels int slip_mode, unit; 12738272Ssam 128*38373Skarels struct slip_modes { 129*38373Skarels char *sm_name; 130*38373Skarels int sm_value; 131*38373Skarels } modes[] = { 132*38373Skarels "normal", 0, /* slip "standard" ala Rick Adams */ 133*38373Skarels "compress", SC_COMPRESS, /* Van Jacobsen's tcp header comp. */ 134*38373Skarels "noicmp", SC_NOICMP, /* Sam's(?) ICMP suppression */ 135*38373Skarels } ; 136*38373Skarels 137*38373Skarels /* 138*38373Skarels * If we are uncerimoniously dumped, bitch 139*38373Skarels */ 140*38373Skarels void 141*38373Skarels hup_handler() 142*38373Skarels { 143*38373Skarels syslog(LOG_NOTICE, "connection closed: process aborted %s%d: remote %s\n", 144*38373Skarels SLIPIFNAME, unit, dstaddr); 145*38373Skarels exit(1) ; 146*38373Skarels } 147*38373Skarels 14838272Ssam main(argc, argv) 14938272Ssam int argc; 15038272Ssam char *argv[]; 15138272Ssam { 152*38373Skarels int fd, s, ldisc, odisc; 153*38373Skarels struct termios tios, otios; 15438272Ssam struct ifreq ifr; 15538272Ssam 15638272Ssam s = getdtablesize(); 15738272Ssam for (fd = 3 ; fd < s ; fd++) 15838272Ssam close(fd); 15938272Ssam openlog("sliplogin", LOG_PID, LOG_DAEMON); 16038272Ssam if (getuid() == 0) { 16138272Ssam if (argc <= 1) { 16238272Ssam fprintf(stderr, "Usage: %s loginname\n", argv[0]); 16338272Ssam fprintf(stderr, " or: %s dstaddr localaddr [mask]\n", 16438272Ssam argv[0]); 16538272Ssam exit(1); 16638272Ssam } else if (argc == 2) { 16738272Ssam findid(argv[1]); 16838272Ssam fprintf(stderr, "local %s remote %s mask %s\n", 16938272Ssam localaddr, dstaddr, netmask); 17038272Ssam } if (argc > 2) { 17138272Ssam if (argc < 3 || argc > 4) { 17238272Ssam fprintf(stderr, 17338272Ssam "Usage: %s dstaddr localaddr [mask]\n", 17438272Ssam argv[0]); 17538272Ssam exit(1); 17638272Ssam } 17738272Ssam dstaddr = argv[1]; 17838272Ssam localaddr = argv[2]; 17938272Ssam if (argc == 4) 18038272Ssam netmask = argv[3]; 18138272Ssam else 18238272Ssam netmask = "default"; 18338272Ssam } 18438272Ssam } else 18538272Ssam findid((char *)0); 186*38373Skarels /* ensure that the slip line is our controlling terminal */ 18738272Ssam if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) { 18838272Ssam (void) ioctl(fd, TIOCNOTTY, 0); 18938272Ssam (void) close(fd); 190*38373Skarels fd = open(ttyname(0), O_RDWR, 0); 191*38373Skarels if (fd >= 0) 192*38373Skarels (void) close(fd); 193*38373Skarels (void) setpgrp(0, getpid()); 19438272Ssam } 19538272Ssam fchmod(0, 0600); 19638272Ssam /* set up the line parameters */ 19738372Ssam if (ioctl(0, TCGETA, (caddr_t)&tios) < 0) { 19838372Ssam syslog(LOG_ERR, "ioctl (TCGETA): %m"); 19938272Ssam exit(1); 20038272Ssam } 201*38373Skarels otios = tios ; 20238272Ssam tios.c_cflag &= 0xf; /* only save the speed */ 20338272Ssam tios.c_cflag |= CS8|CREAD|HUPCL; 20438272Ssam tios.c_iflag = IGNBRK; 20538372Ssam tios.c_oflag = tios.c_lflag = 0; 20638372Ssam if (ioctl(0, TCSETA, (caddr_t)&tios) < 0) { 207*38373Skarels syslog(LOG_ERR, "ioctl (TCSETA) (1): %m"); 20838272Ssam exit(1); 20938272Ssam } 210*38373Skarels /* find out what ldisc we started with */ 211*38373Skarels if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) { 212*38373Skarels syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m"); 213*38373Skarels exit(1); 214*38373Skarels } 21538372Ssam ldisc = SLIPDISC; 21638372Ssam if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) { 217*38373Skarels syslog(LOG_ERR, "ioctl(TIOCSETD) (1): %m"); 21838272Ssam exit(1); 21938272Ssam } 22038272Ssam /* find out what unit number we were assigned */ 22138372Ssam if (ioctl(0, TIOCGETD, (caddr_t)&unit) < 0) { 222*38373Skarels syslog(LOG_ERR, "ioctl (TIOCGETD) (2): %m"); 22338272Ssam exit(1); 22438272Ssam } 22538372Ssam syslog(LOG_NOTICE, "attaching %s%d: local %s remote %s mask %s\n", 22638372Ssam SLIPIFNAME, unit, localaddr, dstaddr, netmask); 22738372Ssam #ifdef notdef 22838272Ssam /* set the local and remote interface addresses */ 22938272Ssam s = socket(AF_INET, SOCK_DGRAM, 0); 23038272Ssam if (getuid() != 0 || argc == 4) { 23138272Ssam (void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit); 23238372Ssam in_getaddr(netmask, &ifr.ifr_addr, MASK); 23338272Ssam if (ioctl(s, SIOCSIFNETMASK, (caddr_t)&ifr) < 0) { 23438272Ssam syslog(LOG_ERR, "ioctl (SIOCSIFNETMASK): %m"); 23538272Ssam exit(1); 23638272Ssam } 23738272Ssam } 23838272Ssam (void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit); 23938372Ssam in_getaddr(dstaddr, &ifr.ifr_addr, ADDR); 24038272Ssam if (ioctl(s, SIOCSIFDSTADDR, (caddr_t)&ifr) < 0) { 24138272Ssam syslog(LOG_ERR, "ioctl (SIOCSIFDSTADDR): %m"); 24238272Ssam exit(1); 24338272Ssam } 24438272Ssam (void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit); 24538372Ssam in_getaddr(localaddr, &ifr.ifr_addr, ADDR); 24638272Ssam /* this has the side-effect of marking the interface up */ 24738272Ssam if (ioctl(s, SIOCSIFADDR, (caddr_t)&ifr) < 0) { 24838272Ssam syslog(LOG_ERR, "ioctl (SIOCSIFADDR): %m"); 24938272Ssam exit(1); 25038272Ssam } 25138372Ssam #else 25238372Ssam /* XXX -- give up for now and just invoke ifconfig XXX */ 25338372Ssam { char cmd[256]; 25438372Ssam sprintf(cmd, "/sbin/ifconfig %s%d inet %s %s netmask %s", 25538372Ssam SLIPIFNAME, unit, localaddr, dstaddr, netmask); 25638372Ssam system(cmd); 25738372Ssam } 258*38373Skarels if (ioctl(0, SLIOCSFLAGS, (caddr_t)&slip_mode) < 0) { 259*38373Skarels syslog(LOG_ERR, "ioctl (SLIOCSFLAGS): %m"); 260*38373Skarels exit(1); 261*38373Skarels } 26238372Ssam #endif 26338272Ssam 26438272Ssam /* set up signal handlers */ 26538272Ssam #if defined(SIGDCD) && SIGDCD > 0 26638272Ssam (void) signal(SIGDCD, dcd_handler); 26738272Ssam #endif 26838272Ssam (void) sigblock(sigmask(SIGALRM)); 26938272Ssam (void) signal(SIGALRM, alarm_handler); 27038272Ssam /* a SIGHUP will kill us */ 271*38373Skarels (void) signal(SIGHUP, hup_handler); 272*38373Skarels (void) signal(SIGTERM, hup_handler); 27338272Ssam 27438272Ssam /* timeleft = 60 * 60 * 24 * 365 ; (void) alarm(timeleft); */ 275*38373Skarels (void) alarm(DCD_CHECK_INTERVAL); 27638272Ssam 27738272Ssam /* twiddle thumbs until we get a signal */ 27838272Ssam while (1) { 27938272Ssam sigpause(0); 28038272Ssam (void) sigblock(sigmask(SIGALRM)); 28138272Ssam if (gotalarm && lowdcd(0)) 28238272Ssam break; 283*38373Skarels if (gotalarm && lowdtr(0)) 284*38373Skarels break; 28538272Ssam gotalarm = 0; 28638272Ssam } 28738272Ssam 288*38373Skarels if (lowdcd(0)) 289*38373Skarels syslog(LOG_NOTICE, 290*38373Skarels "connection closed: loss of carrier %s%d: remote %s\n", 291*38373Skarels SLIPIFNAME, unit, dstaddr); 292*38373Skarels else if (lowdtr(0)) 293*38373Skarels syslog(LOG_NOTICE, 294*38373Skarels "connection closed by foreign host %s%d: remote %s\n", 295*38373Skarels SLIPIFNAME, unit, dstaddr); 296*38373Skarels 297*38373Skarels if (ioctl(0, TIOCSETD, (caddr_t)&odisc) < 0) { 298*38373Skarels syslog(LOG_ERR, "ioctl(TIOCSETD) (2): %m"); 299*38373Skarels exit(1); 300*38373Skarels } 301*38373Skarels if (ioctl(0, TCSETA, (caddr_t)&otios) < 0) { 302*38373Skarels syslog(LOG_ERR, "ioctl (TCSETA) (2): %m"); 303*38373Skarels exit(1); 304*38373Skarels } 30538272Ssam exit(0); 30638272Ssam } 30738272Ssam 30838272Ssam findid(name) 30938272Ssam char *name; 31038272Ssam { 31138272Ssam char buf[BUFSIZ]; 31238272Ssam static char mode[16]; 31338272Ssam static char laddr[16]; 31438272Ssam static char raddr[16]; 31538272Ssam static char mask[16]; 31638272Ssam char user[16]; 31738272Ssam FILE *fp; 31838272Ssam struct passwd *pw; 31938272Ssam int n; 32038272Ssam 32138272Ssam if (name == NULL && (pw = getpwuid(getuid())) == NULL) { 32238272Ssam fprintf(stderr, "Your UID (%d) is unknown\n", getuid()); 32338272Ssam syslog(LOG_ERR, "UID (%d) is unknown\n", getuid()); 32438272Ssam exit(1); 32538272Ssam } else if (name == NULL) 32638272Ssam name = pw->pw_name; 32738272Ssam if ((fp = fopen(Accessfile, "r")) == NULL) { 32838272Ssam perror(Accessfile); 32938272Ssam syslog(LOG_ERR, "%s: %m\n", Accessfile); 33038272Ssam exit(3); 33138272Ssam } 33238272Ssam while (fgets(buf, sizeof(buf) - 1, fp)) { 33338272Ssam if (ferror(fp)) 33438272Ssam break; 33538272Ssam n = sscanf(buf, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n", 33638272Ssam user, mode, laddr, raddr, mask); 33738272Ssam if (user[0] == '#' || n != 5) 33838272Ssam continue; 33938272Ssam if (strcmp(user, name) == 0) { 340*38373Skarels char *p,*q; int val, i, domore; 341*38373Skarels 342*38373Skarels p = q = mode; val = 0; 343*38373Skarels loop: 344*38373Skarels while (isalnum(*p)) p++; 345*38373Skarels if(ispunct(*p) || *p == '\0') { 346*38373Skarels if(ispunct(*p)) domore = 1; else domore = 0; 347*38373Skarels *p++ = '\0' ; 348*38373Skarels for (i = 0; i < 349*38373Skarels sizeof(modes)/sizeof(struct slip_modes) 350*38373Skarels ; i++) { 351*38373Skarels if (strcmp(modes[i].sm_name, q) == 0) { 352*38373Skarels val |= modes[i].sm_value ; 353*38373Skarels break; 354*38373Skarels } ; 355*38373Skarels } 356*38373Skarels q = p; 357*38373Skarels if(domore)goto loop; 358*38373Skarels } 359*38373Skarels 360*38373Skarels slip_mode = val ; 36138272Ssam localaddr = laddr; 36238272Ssam dstaddr = raddr; 36338272Ssam netmask = mask; 36438272Ssam fclose(fp); 36538272Ssam return 0; 36638272Ssam } 36738272Ssam if (feof(fp)) 36838272Ssam break; 36938272Ssam } 37038272Ssam fputs("SLIP access denied\n", stderr); 37138272Ssam syslog(LOG_ERR, "SLIP access denied for %s\n", name); 37238272Ssam exit(4); 37338272Ssam } 37438272Ssam 37538372Ssam in_getaddr(s, saddr, which) 37638272Ssam char *s; 37738272Ssam struct sockaddr *saddr; 37838372Ssam int which; 37938272Ssam { 38038272Ssam register struct sockaddr_in *sin = (struct sockaddr_in *)saddr; 38138272Ssam struct hostent *hp; 38238272Ssam struct netent *np; 38338272Ssam int val; 38438272Ssam extern struct in_addr inet_makeaddr(); 38538272Ssam 38638272Ssam bzero((caddr_t)saddr, sizeof *saddr); 38738372Ssam if (which == ADDR) { 38838372Ssam sin->sin_len = sizeof (*sin); 38938372Ssam sin->sin_family = AF_INET; 39038372Ssam } else 39138372Ssam sin->sin_len = 8; 39238272Ssam val = inet_addr(s); 39338272Ssam if (val != -1) { 39438272Ssam sin->sin_addr.s_addr = val; 39538272Ssam return; 39638272Ssam } 39738272Ssam hp = gethostbyname(s); 39838272Ssam if (hp) { 39938272Ssam sin->sin_family = hp->h_addrtype; 40038272Ssam bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length); 40138272Ssam return; 40238272Ssam } 40338272Ssam np = getnetbyname(s); 40438272Ssam if (np) { 40538272Ssam sin->sin_family = np->n_addrtype; 40638272Ssam sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 40738272Ssam return; 40838272Ssam } 40938272Ssam fprintf(stderr, "sliplogin: %s: bad value\n", s); 41038272Ssam syslog(LOG_ERR, "%s: bad value\n", s); 41138272Ssam exit(1); 41238272Ssam } 413