#ifndef lint static char *sccsid = "@(#)sliplogin.c 1.3 MS/ACF 89/04/18"; #endif /* * sliplogin.c * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!] * * This program initializes its own tty port to be an async TCP/IP interface. * It merely sets up the SLIP module all by its lonesome on the STREAMS stack, * initializes the network interface, and pauses forever waiting for hangup. * * It is a remote descendant of several similar programs with incestuous ties: * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL. * - slattach, probably by Rick Adams but touched by countless hordes. * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it. * - a simple slattach-like program used to test the STREAMS SLIP code. * * There are three basic forms of usage: * * "sliplogin" * Invoked simply as "sliplogin" and a realuid != 0, the program looks up * the uid in /etc/passwd, and then the username in the file /etc/hosts.slip. * If and entry is found, the line on fd0 is configured for SLIP operation * as specified in the file. * * "sliplogin IPhost1 #include #include #include #include #include #include #include #include /* XXX */ #include #include #include #include #include #include #include #include #define SLIPIFNAME "sl" #define ADDR 1 #define MASK 2 #define DCD_CHECK_INTERVAL 5 /* if > 0, time between automatic DCD checks */ #define DCD_SETTLING_TIME 1 /* time between DCD change and status check */ int gotalarm = 0; int timeleft = DCD_CHECK_INTERVAL; void alarm_handler() { /*if (timeleft > DCD_SETTLING_TIME) (void) alarm(timeleft-DCD_SETTLING_TIME); else */ (void) alarm(DCD_CHECK_INTERVAL); gotalarm = 1; timeleft = 0; } #if defined(SIGDCD) && SIGDCD > 0 void dcd_handler() { #if DCD_SETTLING_TIME > 0 timeleft = alarm(DCD_SETTLING_TIME); #else gotalarm = 1; #endif /* DCD_SETTLING_TIME */ } #endif /* Use TIOCMGET to test if DCD is low on the port of the passed descriptor */ int lowdcd(fd) int fd; { int mbits; if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0) return 1; /* port is dead, we die */ return !(mbits & TIOCM_CAR); } /* Use TIOCMGET to test if DTR is low on the port of the passed descriptor */ int lowdtr(fd) int fd; { int mbits; if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0) return 1; /* port is dead, we die */ return ((mbits & TIOCM_DTR) == TIOCM_DTR); } char *Accessfile = "/etc/hosts.slip"; extern char *malloc(), *ttyname(); extern struct passwd *getpwuid(); char *dstaddr, *localaddr, *netmask; int slip_mode, unit; struct slip_modes { char *sm_name; int sm_value; } modes[] = { "normal", 0, /* slip "standard" ala Rick Adams */ "compress", SC_COMPRESS, /* Van Jacobsen's tcp header comp. */ "noicmp", SC_NOICMP, /* Sam's(?) ICMP suppression */ } ; /* * If we are uncerimoniously dumped, bitch */ void hup_handler() { syslog(LOG_NOTICE, "connection closed: process aborted %s%d: remote %s\n", SLIPIFNAME, unit, dstaddr); exit(1) ; } main(argc, argv) int argc; char *argv[]; { int fd, s, ldisc, odisc; struct termios tios, otios; struct ifreq ifr; s = getdtablesize(); for (fd = 3 ; fd < s ; fd++) close(fd); openlog("sliplogin", LOG_PID, LOG_DAEMON); if (getuid() == 0) { if (argc <= 1) { fprintf(stderr, "Usage: %s loginname\n", argv[0]); fprintf(stderr, " or: %s dstaddr localaddr [mask]\n", argv[0]); exit(1); } else if (argc == 2) { findid(argv[1]); fprintf(stderr, "local %s remote %s mask %s\n", localaddr, dstaddr, netmask); } if (argc > 2) { if (argc < 3 || argc > 4) { fprintf(stderr, "Usage: %s dstaddr localaddr [mask]\n", argv[0]); exit(1); } dstaddr = argv[1]; localaddr = argv[2]; if (argc == 4) netmask = argv[3]; else netmask = "default"; } } else findid((char *)0); /* ensure that the slip line is our controlling terminal */ if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) { (void) ioctl(fd, TIOCNOTTY, 0); (void) close(fd); fd = open(ttyname(0), O_RDWR, 0); if (fd >= 0) (void) close(fd); (void) setpgrp(0, getpid()); } fchmod(0, 0600); /* set up the line parameters */ if (ioctl(0, TCGETA, (caddr_t)&tios) < 0) { syslog(LOG_ERR, "ioctl (TCGETA): %m"); exit(1); } otios = tios ; tios.c_cflag &= 0xf; /* only save the speed */ tios.c_cflag |= CS8|CREAD|HUPCL; tios.c_iflag = IGNBRK; tios.c_oflag = tios.c_lflag = 0; if (ioctl(0, TCSETA, (caddr_t)&tios) < 0) { syslog(LOG_ERR, "ioctl (TCSETA) (1): %m"); exit(1); } /* find out what ldisc we started with */ if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) { syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m"); exit(1); } ldisc = SLIPDISC; if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) { syslog(LOG_ERR, "ioctl(TIOCSETD) (1): %m"); exit(1); } /* find out what unit number we were assigned */ if (ioctl(0, TIOCGETD, (caddr_t)&unit) < 0) { syslog(LOG_ERR, "ioctl (TIOCGETD) (2): %m"); exit(1); } syslog(LOG_NOTICE, "attaching %s%d: local %s remote %s mask %s\n", SLIPIFNAME, unit, localaddr, dstaddr, netmask); #ifdef notdef /* set the local and remote interface addresses */ s = socket(AF_INET, SOCK_DGRAM, 0); if (getuid() != 0 || argc == 4) { (void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit); in_getaddr(netmask, &ifr.ifr_addr, MASK); if (ioctl(s, SIOCSIFNETMASK, (caddr_t)&ifr) < 0) { syslog(LOG_ERR, "ioctl (SIOCSIFNETMASK): %m"); exit(1); } } (void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit); in_getaddr(dstaddr, &ifr.ifr_addr, ADDR); if (ioctl(s, SIOCSIFDSTADDR, (caddr_t)&ifr) < 0) { syslog(LOG_ERR, "ioctl (SIOCSIFDSTADDR): %m"); exit(1); } (void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit); in_getaddr(localaddr, &ifr.ifr_addr, ADDR); /* this has the side-effect of marking the interface up */ if (ioctl(s, SIOCSIFADDR, (caddr_t)&ifr) < 0) { syslog(LOG_ERR, "ioctl (SIOCSIFADDR): %m"); exit(1); } #else /* XXX -- give up for now and just invoke ifconfig XXX */ { char cmd[256]; sprintf(cmd, "/sbin/ifconfig %s%d inet %s %s netmask %s", SLIPIFNAME, unit, localaddr, dstaddr, netmask); system(cmd); } if (ioctl(0, SLIOCSFLAGS, (caddr_t)&slip_mode) < 0) { syslog(LOG_ERR, "ioctl (SLIOCSFLAGS): %m"); exit(1); } #endif /* set up signal handlers */ #if defined(SIGDCD) && SIGDCD > 0 (void) signal(SIGDCD, dcd_handler); #endif (void) sigblock(sigmask(SIGALRM)); (void) signal(SIGALRM, alarm_handler); /* a SIGHUP will kill us */ (void) signal(SIGHUP, hup_handler); (void) signal(SIGTERM, hup_handler); /* timeleft = 60 * 60 * 24 * 365 ; (void) alarm(timeleft); */ (void) alarm(DCD_CHECK_INTERVAL); /* twiddle thumbs until we get a signal */ while (1) { sigpause(0); (void) sigblock(sigmask(SIGALRM)); if (gotalarm && lowdcd(0)) break; if (gotalarm && lowdtr(0)) break; gotalarm = 0; } if (lowdcd(0)) syslog(LOG_NOTICE, "connection closed: loss of carrier %s%d: remote %s\n", SLIPIFNAME, unit, dstaddr); else if (lowdtr(0)) syslog(LOG_NOTICE, "connection closed by foreign host %s%d: remote %s\n", SLIPIFNAME, unit, dstaddr); if (ioctl(0, TIOCSETD, (caddr_t)&odisc) < 0) { syslog(LOG_ERR, "ioctl(TIOCSETD) (2): %m"); exit(1); } if (ioctl(0, TCSETA, (caddr_t)&otios) < 0) { syslog(LOG_ERR, "ioctl (TCSETA) (2): %m"); exit(1); } exit(0); } findid(name) char *name; { char buf[BUFSIZ]; static char mode[16]; static char laddr[16]; static char raddr[16]; static char mask[16]; char user[16]; FILE *fp; struct passwd *pw; int n; if (name == NULL && (pw = getpwuid(getuid())) == NULL) { fprintf(stderr, "Your UID (%d) is unknown\n", getuid()); syslog(LOG_ERR, "UID (%d) is unknown\n", getuid()); exit(1); } else if (name == NULL) name = pw->pw_name; if ((fp = fopen(Accessfile, "r")) == NULL) { perror(Accessfile); syslog(LOG_ERR, "%s: %m\n", Accessfile); exit(3); } while (fgets(buf, sizeof(buf) - 1, fp)) { if (ferror(fp)) break; n = sscanf(buf, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n", user, mode, laddr, raddr, mask); if (user[0] == '#' || n != 5) continue; if (strcmp(user, name) == 0) { char *p,*q; int val, i, domore; p = q = mode; val = 0; loop: while (isalnum(*p)) p++; if(ispunct(*p) || *p == '\0') { if(ispunct(*p)) domore = 1; else domore = 0; *p++ = '\0' ; for (i = 0; i < sizeof(modes)/sizeof(struct slip_modes) ; i++) { if (strcmp(modes[i].sm_name, q) == 0) { val |= modes[i].sm_value ; break; } ; } q = p; if(domore)goto loop; } slip_mode = val ; localaddr = laddr; dstaddr = raddr; netmask = mask; fclose(fp); return 0; } if (feof(fp)) break; } fputs("SLIP access denied\n", stderr); syslog(LOG_ERR, "SLIP access denied for %s\n", name); exit(4); } in_getaddr(s, saddr, which) char *s; struct sockaddr *saddr; int which; { register struct sockaddr_in *sin = (struct sockaddr_in *)saddr; struct hostent *hp; struct netent *np; int val; extern struct in_addr inet_makeaddr(); bzero((caddr_t)saddr, sizeof *saddr); if (which == ADDR) { sin->sin_len = sizeof (*sin); sin->sin_family = AF_INET; } else sin->sin_len = 8; val = inet_addr(s); if (val != -1) { sin->sin_addr.s_addr = val; return; } hp = gethostbyname(s); if (hp) { sin->sin_family = hp->h_addrtype; bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length); return; } np = getnetbyname(s); if (np) { sin->sin_family = np->n_addrtype; sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); return; } fprintf(stderr, "sliplogin: %s: bad value\n", s); syslog(LOG_ERR, "%s: bad value\n", s); exit(1); }