138272Ssam #ifndef lint 238272Ssam static char *sccsid = "@(#)sliplogin.c 1.3 MS/ACF 89/04/18"; 338272Ssam #endif 438272Ssam 538272Ssam /* 638272Ssam * sliplogin.c 738272Ssam * 838272Ssam * This program initializes its own tty port to be an async TCP/IP interface. 938272Ssam * It merely sets up the SLIP module all by its lonesome on the STREAMS stack, 1038272Ssam * initializes the network interface, and pauses forever waiting for hangup. 1138272Ssam * 1238272Ssam * It is a remote descendant of several similar programs with incestuous ties: 1338272Ssam * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL. 1438272Ssam * - slattach, probably by Rick Adams but touched by countless hordes. 1538272Ssam * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it. 1638272Ssam * - a simple slattach-like program used to test the STREAMS SLIP code. 1738272Ssam * 1838272Ssam * There are three basic forms of usage: 1938272Ssam * 2038272Ssam * "sliplogin" 2138272Ssam * Invoked simply as "sliplogin" and a realuid != 0, the program looks up 2238272Ssam * the uid in /etc/passwd, and then the username in the file /etc/hosts.slip. 2338272Ssam * If and entry is found, the line on fd0 is configured for SLIP operation 2438272Ssam * as specified in the file. 2538272Ssam * 2638272Ssam * "sliplogin IPhost1 </dev/ttyb" 2738272Ssam * Invoked by root with a username, the name is looked up in the 2838272Ssam * /etc/hosts.slip file and if found fd0 is configured as in case 1. 2938272Ssam * 3038272Ssam * "sliplogin 192.100.1.1 192.100.1.2 255.255.255.0 < /dev/ttyb" 3138272Ssam * Finally, if invoked with a remote addr, local addr, and optionally 3238272Ssam * a net mask, the line on fd0 is setup as specified if the user is root. 3338272Ssam * 3438272Ssam * Doug Kingston 8810?? - logging + first pass at adding I_STR ioctl's 3538272Ssam * Rayan Zachariassen 881011 - version for SunOS STREAMS SLIP 3638272Ssam */ 3738272Ssam 3838272Ssam #include <sys/types.h> 3938272Ssam #include <sys/socket.h> 4038272Ssam #include <sys/termios.h> 41*38372Ssam #include <sys/ioctl.h> 4238272Ssam #include <sys/file.h> 4338272Ssam #include <sys/syslog.h> 4438272Ssam 4538272Ssam #include <netinet/in.h> 4638272Ssam #include <net/if.h> 4738272Ssam 4838272Ssam #include <stdio.h> 4938272Ssam #include <errno.h> 5038272Ssam #include <ctype.h> 5138272Ssam #include <netdb.h> 5238272Ssam 5338272Ssam #include <signal.h> 5438272Ssam #include <strings.h> 5538272Ssam #include <pwd.h> 5638272Ssam #include <ttyent.h> 5738272Ssam 58*38372Ssam #define SLIPIFNAME "sl" 59*38372Ssam 60*38372Ssam #define ADDR 1 61*38372Ssam #define MASK 2 62*38372Ssam 6338272Ssam #define DCD_CHECK_INTERVAL 0 /* if > 0, time between automatic DCD checks */ 6438272Ssam #define DCD_SETTLING_TIME 1 /* time between DCD change and status check */ 6538272Ssam 6638272Ssam int gotalarm = 0; 6738272Ssam int timeleft = DCD_CHECK_INTERVAL; 6838272Ssam 6938272Ssam void 7038272Ssam alarm_handler() 7138272Ssam { 7238272Ssam if (timeleft > DCD_SETTLING_TIME) 7338272Ssam (void) alarm(timeleft-DCD_SETTLING_TIME); 7438272Ssam else 7538272Ssam (void) alarm(DCD_CHECK_INTERVAL); 7638272Ssam gotalarm = 1; 7738272Ssam timeleft = 0; 7838272Ssam } 7938272Ssam 8038272Ssam #if defined(SIGDCD) && SIGDCD > 0 8138272Ssam void 8238272Ssam dcd_handler() 8338272Ssam { 8438272Ssam #if DCD_SETTLING_TIME > 0 8538272Ssam timeleft = alarm(DCD_SETTLING_TIME); 8638272Ssam #else 8738272Ssam gotalarm = 1; 8838272Ssam #endif /* DCD_SETTLING_TIME */ 8938272Ssam } 9038272Ssam #endif 9138272Ssam 9238272Ssam /* Use TIOCMGET to test if DCD is low on the port of the passed descriptor */ 9338272Ssam 9438272Ssam int 9538272Ssam lowdcd(fd) 9638272Ssam int fd; 9738272Ssam { 9838272Ssam int mbits; 9938272Ssam 10038272Ssam if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0) 10138272Ssam return 1; /* port is dead, we die */ 10238272Ssam return !(mbits & TIOCM_CAR); 10338272Ssam } 10438272Ssam 10538272Ssam char *Accessfile = "/etc/hosts.slip"; 10638272Ssam 10738272Ssam extern char *malloc(), *ttyname(); 10838272Ssam extern struct passwd *getpwuid(); 10938272Ssam 11038272Ssam char *dstaddr, *localaddr, *netmask; 11138272Ssam 11238272Ssam main(argc, argv) 11338272Ssam int argc; 11438272Ssam char *argv[]; 11538272Ssam { 116*38372Ssam int fd, s, unit, ldisc; 11738272Ssam struct termios tios; 11838272Ssam struct ifreq ifr; 11938272Ssam 12038272Ssam s = getdtablesize(); 12138272Ssam for (fd = 3 ; fd < s ; fd++) 12238272Ssam close(fd); 12338272Ssam openlog("sliplogin", LOG_PID, LOG_DAEMON); 12438272Ssam if (getuid() == 0) { 12538272Ssam if (argc <= 1) { 12638272Ssam fprintf(stderr, "Usage: %s loginname\n", argv[0]); 12738272Ssam fprintf(stderr, " or: %s dstaddr localaddr [mask]\n", 12838272Ssam argv[0]); 12938272Ssam exit(1); 13038272Ssam } else if (argc == 2) { 13138272Ssam findid(argv[1]); 13238272Ssam fprintf(stderr, "local %s remote %s mask %s\n", 13338272Ssam localaddr, dstaddr, netmask); 13438272Ssam } if (argc > 2) { 13538272Ssam if (argc < 3 || argc > 4) { 13638272Ssam fprintf(stderr, 13738272Ssam "Usage: %s dstaddr localaddr [mask]\n", 13838272Ssam argv[0]); 13938272Ssam exit(1); 14038272Ssam } 14138272Ssam dstaddr = argv[1]; 14238272Ssam localaddr = argv[2]; 14338272Ssam if (argc == 4) 14438272Ssam netmask = argv[3]; 14538272Ssam else 14638272Ssam netmask = "default"; 14738272Ssam } 14838272Ssam } else 14938272Ssam findid((char *)0); 150*38372Ssam /* disassociate from current controlling terminal */ 15138272Ssam if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) { 15238272Ssam (void) ioctl(fd, TIOCNOTTY, 0); 15338272Ssam (void) close(fd); 15438272Ssam } 155*38372Ssam /* ensure that the slip line is our new controlling terminal */ 156*38372Ssam (void) setpgrp(0, getpid()); 157*38372Ssam (void) ioctl(0, TIOCSCTTY, 0); 15838272Ssam fchmod(0, 0600); 15938272Ssam /* set up the line parameters */ 160*38372Ssam if (ioctl(0, TCGETA, (caddr_t)&tios) < 0) { 161*38372Ssam syslog(LOG_ERR, "ioctl (TCGETA): %m"); 16238272Ssam exit(1); 16338272Ssam } 16438272Ssam tios.c_cflag &= 0xf; /* only save the speed */ 16538272Ssam tios.c_cflag |= CS8|CREAD|HUPCL; 16638272Ssam tios.c_iflag = IGNBRK; 167*38372Ssam tios.c_oflag = tios.c_lflag = 0; 168*38372Ssam if (ioctl(0, TCSETA, (caddr_t)&tios) < 0) { 169*38372Ssam syslog(LOG_ERR, "ioctl (TCSETA): %m"); 17038272Ssam exit(1); 17138272Ssam } 172*38372Ssam ldisc = SLIPDISC; 173*38372Ssam if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) { 174*38372Ssam syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); 17538272Ssam exit(1); 17638272Ssam } 17738272Ssam /* find out what unit number we were assigned */ 178*38372Ssam if (ioctl(0, TIOCGETD, (caddr_t)&unit) < 0) { 179*38372Ssam syslog(LOG_ERR, "ioctl (TIOCGETD): %m"); 18038272Ssam exit(1); 18138272Ssam } 182*38372Ssam syslog(LOG_NOTICE, "attaching %s%d: local %s remote %s mask %s\n", 183*38372Ssam SLIPIFNAME, unit, localaddr, dstaddr, netmask); 184*38372Ssam #ifdef notdef 18538272Ssam /* set the local and remote interface addresses */ 18638272Ssam s = socket(AF_INET, SOCK_DGRAM, 0); 18738272Ssam if (getuid() != 0 || argc == 4) { 18838272Ssam (void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit); 189*38372Ssam in_getaddr(netmask, &ifr.ifr_addr, MASK); 19038272Ssam if (ioctl(s, SIOCSIFNETMASK, (caddr_t)&ifr) < 0) { 19138272Ssam syslog(LOG_ERR, "ioctl (SIOCSIFNETMASK): %m"); 19238272Ssam exit(1); 19338272Ssam } 19438272Ssam } 19538272Ssam (void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit); 196*38372Ssam in_getaddr(dstaddr, &ifr.ifr_addr, ADDR); 19738272Ssam if (ioctl(s, SIOCSIFDSTADDR, (caddr_t)&ifr) < 0) { 19838272Ssam syslog(LOG_ERR, "ioctl (SIOCSIFDSTADDR): %m"); 19938272Ssam exit(1); 20038272Ssam } 20138272Ssam (void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit); 202*38372Ssam in_getaddr(localaddr, &ifr.ifr_addr, ADDR); 20338272Ssam /* this has the side-effect of marking the interface up */ 20438272Ssam if (ioctl(s, SIOCSIFADDR, (caddr_t)&ifr) < 0) { 20538272Ssam syslog(LOG_ERR, "ioctl (SIOCSIFADDR): %m"); 20638272Ssam exit(1); 20738272Ssam } 208*38372Ssam #else 209*38372Ssam /* XXX -- give up for now and just invoke ifconfig XXX */ 210*38372Ssam { char cmd[256]; 211*38372Ssam sprintf(cmd, "/sbin/ifconfig %s%d inet %s %s netmask %s", 212*38372Ssam SLIPIFNAME, unit, localaddr, dstaddr, netmask); 213*38372Ssam system(cmd); 214*38372Ssam } 215*38372Ssam #endif 21638272Ssam 21738272Ssam /* set up signal handlers */ 21838272Ssam #if defined(SIGDCD) && SIGDCD > 0 21938272Ssam (void) signal(SIGDCD, dcd_handler); 22038272Ssam #endif 22138272Ssam (void) sigblock(sigmask(SIGALRM)); 22238272Ssam (void) signal(SIGALRM, alarm_handler); 22338272Ssam /* a SIGHUP will kill us */ 22438272Ssam 22538272Ssam /* timeleft = 60 * 60 * 24 * 365 ; (void) alarm(timeleft); */ 22638272Ssam 22738272Ssam /* twiddle thumbs until we get a signal */ 22838272Ssam while (1) { 22938272Ssam sigpause(0); 23038272Ssam (void) sigblock(sigmask(SIGALRM)); 23138272Ssam if (gotalarm && lowdcd(0)) 23238272Ssam break; 23338272Ssam gotalarm = 0; 23438272Ssam } 23538272Ssam 23638272Ssam /* closing the descriptor should pop the slip module */ 23738272Ssam exit(0); 23838272Ssam } 23938272Ssam 24038272Ssam findid(name) 24138272Ssam char *name; 24238272Ssam { 24338272Ssam char buf[BUFSIZ]; 24438272Ssam static char mode[16]; 24538272Ssam static char laddr[16]; 24638272Ssam static char raddr[16]; 24738272Ssam static char mask[16]; 24838272Ssam char user[16]; 24938272Ssam FILE *fp; 25038272Ssam struct passwd *pw; 25138272Ssam int n; 25238272Ssam 25338272Ssam if (name == NULL && (pw = getpwuid(getuid())) == NULL) { 25438272Ssam fprintf(stderr, "Your UID (%d) is unknown\n", getuid()); 25538272Ssam syslog(LOG_ERR, "UID (%d) is unknown\n", getuid()); 25638272Ssam exit(1); 25738272Ssam } else if (name == NULL) 25838272Ssam name = pw->pw_name; 25938272Ssam if ((fp = fopen(Accessfile, "r")) == NULL) { 26038272Ssam perror(Accessfile); 26138272Ssam syslog(LOG_ERR, "%s: %m\n", Accessfile); 26238272Ssam exit(3); 26338272Ssam } 26438272Ssam while (fgets(buf, sizeof(buf) - 1, fp)) { 26538272Ssam if (ferror(fp)) 26638272Ssam break; 26738272Ssam n = sscanf(buf, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n", 26838272Ssam user, mode, laddr, raddr, mask); 26938272Ssam if (user[0] == '#' || n != 5) 27038272Ssam continue; 27138272Ssam if (strcmp(user, name) == 0) { 27238272Ssam /* eventually deal with "mode" */ 27338272Ssam localaddr = laddr; 27438272Ssam dstaddr = raddr; 27538272Ssam netmask = mask; 27638272Ssam fclose(fp); 27738272Ssam return 0; 27838272Ssam } 27938272Ssam if (feof(fp)) 28038272Ssam break; 28138272Ssam } 28238272Ssam fputs("SLIP access denied\n", stderr); 28338272Ssam syslog(LOG_ERR, "SLIP access denied for %s\n", name); 28438272Ssam exit(4); 28538272Ssam } 28638272Ssam 287*38372Ssam in_getaddr(s, saddr, which) 28838272Ssam char *s; 28938272Ssam struct sockaddr *saddr; 290*38372Ssam int which; 29138272Ssam { 29238272Ssam register struct sockaddr_in *sin = (struct sockaddr_in *)saddr; 29338272Ssam struct hostent *hp; 29438272Ssam struct netent *np; 29538272Ssam int val; 29638272Ssam extern struct in_addr inet_makeaddr(); 29738272Ssam 29838272Ssam bzero((caddr_t)saddr, sizeof *saddr); 299*38372Ssam if (which == ADDR) { 300*38372Ssam sin->sin_len = sizeof (*sin); 301*38372Ssam sin->sin_family = AF_INET; 302*38372Ssam } else 303*38372Ssam sin->sin_len = 8; 30438272Ssam val = inet_addr(s); 30538272Ssam if (val != -1) { 30638272Ssam sin->sin_addr.s_addr = val; 30738272Ssam return; 30838272Ssam } 30938272Ssam hp = gethostbyname(s); 31038272Ssam if (hp) { 31138272Ssam sin->sin_family = hp->h_addrtype; 31238272Ssam bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length); 31338272Ssam return; 31438272Ssam } 31538272Ssam np = getnetbyname(s); 31638272Ssam if (np) { 31738272Ssam sin->sin_family = np->n_addrtype; 31838272Ssam sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 31938272Ssam return; 32038272Ssam } 32138272Ssam fprintf(stderr, "sliplogin: %s: bad value\n", s); 32238272Ssam syslog(LOG_ERR, "%s: bad value\n", s); 32338272Ssam exit(1); 32438272Ssam } 325