+ }
+
+/********************************************************************
+ *
+ * Update the wtmp file with the appropriate user name and tty device.
+ */
+
+void logwtmp (const char *line, const char *name, const char *host)
+ {
+ int wtmp;
+ struct utmp ut, *utp;
+ pid_t mypid = getpid();
+/*
+ * Update the signon database for users.
+ * Christoph Lameter: Copied from poeigl-1.36 Jan 3, 1996
+ */
+ utmpname(_PATH_UTMP);
+ setutent();
+ while ((utp = getutent()) && (utp->ut_pid != mypid))
+ /* nothing */;
+
+ /* Is this call really necessary? There is another one after the 'put' */
+ endutent();
+
+ if (utp)
+ {
+ memcpy(&ut, utp, sizeof(ut));
+ }
+ else
+ {
+ /* some gettys/telnetds don't initialize utmp... */
+ memset(&ut, 0, sizeof(ut));
+ }
+
+ if (ut.ut_id[0] == 0)
+ {
+ strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
+ }
+
+ strncpy(ut.ut_user, name, sizeof(ut.ut_user));
+ strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+
+ time(&ut.ut_time);
+
+ ut.ut_type = USER_PROCESS;
+ ut.ut_pid = mypid;
+
+ /* Insert the host name if one is supplied */
+ if (*host)
+ {
+ strncpy (ut.ut_host, host, sizeof(ut.ut_host));
+ }
+
+ /* Insert the IP address of the remote system if IP is enabled */
+ if (ipcp_protent.enabled_flag && ipcp_hisoptions[0].neg_addr)
+ {
+ memcpy (&ut.ut_addr, (char *) &ipcp_hisoptions[0].hisaddr,
+ sizeof(ut.ut_addr));
+ }
+
+ /* CL: Makes sure that the logout works */
+ if (*host == 0 && *name==0)
+ {
+ ut.ut_host[0]=0;
+ }
+
+ pututline(&ut);
+ endutent();
+/*
+ * Update the wtmp file.
+ */
+ wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY);
+ if (wtmp >= 0)
+ {
+ flock(wtmp, LOCK_EX);
+
+ /* we really should check for error on the write for a full disk! */
+ write (wtmp, (char *)&ut, sizeof(ut));
+ close (wtmp);
+
+ flock(wtmp, LOCK_UN);
+ }
+ }
+
+/********************************************************************
+ * Code for locking/unlocking the serial device.
+ * This code is derived from chat.c.
+ */
+
+/*
+ * lock - create a lock file for the named device
+ */
+
+int lock (char *dev)
+ {
+#ifdef LOCKLIB
+ int result;
+ lock_file = malloc(strlen(dev) + 1);
+ if (lock_file == NULL)
+ {
+ novm("lock file name");
+ }
+ strcpy (lock_file, dev);
+ result = mklock (dev, (void *) 0);
+
+ if (result > 0)
+ {
+ syslog (LOG_NOTICE, "Device %s is locked by pid %d", dev, result);
+ free (lock_file);
+ lock_file = NULL;
+ result = -1;
+ }
+ else
+ {
+ if (result < 0)
+ {
+ syslog (LOG_ERR, "Can't create lock file %s", lock_file);
+ free (lock_file);
+ lock_file = NULL;
+ result = -1;
+ }
+ }
+ return (result);
+#else
+ char hdb_lock_buffer[12];
+ int fd, n;
+ int pid = getpid();
+ char *p;
+
+ p = strrchr(dev, '/');
+ if (p != NULL)
+ {
+ dev = ++p;
+ }
+
+ lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1);
+ if (lock_file == NULL)
+ {
+ novm("lock file name");
+ }
+
+ strcpy (lock_file, LOCK_PREFIX);
+ strcat (lock_file, dev);
+/*
+ * Attempt to create the lock file at this point.
+ */
+ while (1)
+ {
+ fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644);
+ if (fd >= 0)
+ {
+ pid = getpid();
+#ifndef PID_BINARY
+ sprintf (hdb_lock_buffer, "%010d\n", pid);
+ write (fd, hdb_lock_buffer, 11);
+#else
+ write(fd, &pid, sizeof (pid));
+#endif
+ close(fd);
+ return 0;
+ }
+/*
+ * If the file exists then check to see if the pid is stale
+ */
+ if (errno == EEXIST)
+ {
+ fd = open(lock_file, O_RDONLY, 0);
+ if (fd < 0)
+ {
+ if (errno == ENOENT) /* This is just a timing problem. */
+ {
+ continue;
+ }
+ break;
+ }
+
+ /* Read the lock file to find out who has the device locked */
+ n = read (fd, hdb_lock_buffer, 11);
+ close (fd);
+ if (n < 0)
+ {
+ syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
+ break;
+ }
+
+ /* See the process still exists. */
+ if (n > 0)
+ {
+#ifndef PID_BINARY
+ hdb_lock_buffer[n] = '\0';
+ sscanf (hdb_lock_buffer, " %d", &pid);
+#else
+ pid = ((int *) hdb_lock_buffer)[0];
+#endif
+ if (pid == 0 || pid == getpid()
+ || (kill(pid, 0) == -1 && errno == ESRCH))
+ {
+ n = 0;
+ }
+ }
+
+ /* If the process does not exist then try to remove the lock */
+ if (n == 0 && unlink (lock_file) == 0)
+ {
+ syslog (LOG_NOTICE, "Removed stale lock on %s (pid %d)",
+ dev, pid);
+ continue;
+ }
+
+ syslog (LOG_NOTICE, "Device %s is locked by pid %d", dev, pid);
+ break;
+ }
+
+ syslog(LOG_ERR, "Can't create lock file %s: %m(%d)", lock_file, errno);
+ break;
+ }
+
+ free(lock_file);
+ lock_file = NULL;
+ return -1;
+#endif
+}
+
+
+/********************************************************************
+ *
+ * unlock - remove our lockfile
+ */
+
+void unlock(void)
+ {
+ if (lock_file)
+ {
+#ifdef LOCKLIB
+ (void) rmlock (lock_file, (void *) 0);
+#else
+ unlink(lock_file);
+#endif
+ free(lock_file);
+ lock_file = NULL;
+ }
+ }
+
+/********************************************************************
+ *
+ * sifvjcomp - config tcp header compression
+ */
+
+int sifvjcomp (int u, int vjcomp, int cidcomp, int maxcid)
+ {
+ u_int x = get_flags();
+
+ if (vjcomp)
+ {
+ if (ioctl (ppp_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_ERR, "ioctl(PPPIOCSFLAGS): %m(%d)", errno);
+ }
+ vjcomp = 0;
+ }
+ }
+
+ x = vjcomp ? x | SC_COMP_TCP : x &~ SC_COMP_TCP;
+ x = cidcomp ? x & ~SC_NO_TCP_CCID : x | SC_NO_TCP_CCID;
+ set_flags (x);
+
+ return 1;
+ }
+
+/********************************************************************
+ *
+ * sifup - Config the interface up and enable IP packets to pass.
+ */
+
+int sifup (int u)
+ {
+ struct ifreq ifr;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m(%d)", errno);
+ }
+ return 0;
+ }
+
+ ifr.ifr_flags |= (IFF_UP | IFF_POINTOPOINT);
+ if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m(%d)", errno);
+ }
+ return 0;
+ }
+ if_is_up = 1;
+ return 1;
+ }
+
+/********************************************************************
+ *
+ * sifdown - Config the interface down and disable IP.
+ */
+
+int sifdown (int u)
+ {
+ struct ifreq ifr;
+
+ if_is_up = 0;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m(%d)", errno);
+ }
+ return 0;
+ }
+
+ ifr.ifr_flags &= ~IFF_UP;
+ ifr.ifr_flags |= IFF_POINTOPOINT;
+ if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m(%d)", errno);
+ }
+ return 0;
+ }
+ return 1;
+ }
+
+/********************************************************************
+ *
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+
+int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr,
+ u_int32_t net_mask)
+ {
+ struct ifreq ifr;
+ struct rtentry rt;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ memset (&rt, '\0', sizeof (rt));
+
+ SET_SA_FAMILY (ifr.ifr_addr, AF_INET);
+ SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET);
+ SET_SA_FAMILY (ifr.ifr_netmask, AF_INET);
+
+ strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+/*
+ * Set our IP address
+ */
+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = our_adr;
+ if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &ifr) < 0)
+ {
+ if (errno != EEXIST)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_ERR, "ioctl(SIOCAIFADDR): %m(%d)", errno);
+ }
+ }
+ else
+ {
+ syslog (LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
+ }
+ return (0);
+ }
+/*
+ * Set the gateway address
+ */
+ ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = his_adr;
+ if (ioctl(sock_fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m(%d)", errno);
+ }
+ return (0);
+ }
+/*
+ * Set the netmask.
+ * For recent kernels, force the netmask to 255.255.255.255.
+ */
+ if (strcmp(utsname.release, "2.1.16") >= 0)
+ net_mask = ~0L;
+ if (net_mask != 0)
+ {
+ ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr = net_mask;
+ if (ioctl(sock_fd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_ERR, "ioctl(SIOCSIFNETMASK): %m(%d)", errno);
+ }
+ return (0);
+ }
+ }
+/*
+ * Add the device route
+ */
+ if (strcmp(utsname.release, "2.1.16") < 0) {
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ rt.rt_dev = ifname;
+
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = 0L;
+ ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = his_adr;
+ rt.rt_flags = RTF_UP | RTF_HOST;
+
+ if (strcmp(utsname.release, "2.1.0") > 0) {
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_genmask)->sin_addr.s_addr = -1L;
+ }
+
+ if (ioctl(sock_fd, SIOCADDRT, &rt) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_ERR, "ioctl(SIOCADDRT) device route: %m(%d)", errno);
+ }
+ return (0);
+ }
+ }
+ return 1;
+ }
+
+/********************************************************************
+ *
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+
+int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr)
+ {
+ struct rtentry rt;
+
+ if (strcmp(utsname.release, "2.1.16") < 0) {
+/*
+ * Delete the route through the device
+ */
+ memset (&rt, '\0', sizeof (rt));
+
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ rt.rt_dev = ifname;
+
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = 0;
+ ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = his_adr;
+ rt.rt_flags = RTF_UP | RTF_HOST;
+
+ if (strcmp(utsname.release, "2.1.0") > 0) {
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_genmask)->sin_addr.s_addr = -1L;
+ }
+
+ if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH)
+ {
+ if (still_ppp() && ! ok_error (errno))
+ {
+ syslog (LOG_ERR, "ioctl(SIOCDELRT) device route: %m(%d)", errno);
+ }
+ return (0);
+ }
+ }
+ return 1;
+ }
+
+/********************************************************************
+ *
+ * open_loopback - open the device we use for getting packets
+ * in demand mode. Under Linux, we use our existing fd
+ * to the ppp driver.
+ */
+void
+open_ppp_loopback(void)
+ {
+ int flags, i;
+ struct termios tios;
+
+ master_fd = -1;
+ for (i = 0; i < 64; ++i) {
+ sprintf(loop_name, "/dev/pty%c%x", 'p' + i / 16, i % 16);
+ master_fd = open(loop_name, O_RDWR | O_NOCTTY, 0);
+ if (master_fd >= 0)
+ break;
+ }
+ if (master_fd < 0) {
+ syslog(LOG_ERR, "No free pty for loopback");
+ die(1);
+ }
+ SYSDEBUG((LOG_DEBUG, "using %s for loopback", loop_name));
+ loop_name[5] = 't';
+ slave_fd = open(loop_name, O_RDWR | O_NOCTTY, 0);
+ if (slave_fd < 0) {
+ syslog(LOG_ERR, "Couldn't open %s for loopback: %m", loop_name);
+ die(1);
+ }
+
+ set_ppp_fd(slave_fd);
+
+ if (tcgetattr(ppp_fd, &tios) == 0)
+ {
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
+ tios.c_cflag |= CS8 | CREAD;
+ tios.c_iflag = IGNPAR | CLOCAL;
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ if (tcsetattr(ppp_fd, TCSAFLUSH, &tios) < 0)
+ {
+ syslog(LOG_WARNING, "couldn't set attributes on loopback: %m(%d)", errno);
+ }
+ }
+
+ flags = fcntl(master_fd, F_GETFL);
+ if (flags == -1 ||
+ fcntl(master_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ {
+ syslog(LOG_WARNING, "couldn't set master loopback to nonblock: %m(%d)", errno);
+ }
+
+ flags = fcntl(ppp_fd, F_GETFL);
+ if (flags == -1 ||
+ fcntl(ppp_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ {
+ syslog(LOG_WARNING, "couldn't set slave loopback to nonblock: %m(%d)", errno);
+ }
+
+ if (ioctl(ppp_fd, TIOCSETD, &ppp_disc) < 0)
+ {
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m(%d)", errno);
+ die(1);
+ }
+/*
+ * Find out which interface we were given.
+ */
+ if (ioctl(ppp_fd, PPPIOCGUNIT, &ifunit) < 0)
+ {
+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m(%d)", errno);
+ die(1);
+ }
+/*
+ * Enable debug in the driver if requested.
+ */
+ set_kdebugflag (kdebugflag);
+ }
+
+/********************************************************************
+ *
+ * restore_loop - reattach the ppp unit to the loopback.
+ *
+ * The kernel ppp driver automatically reattaches the ppp unit to
+ * the loopback if the serial port is set to a line discipline other
+ * than ppp, or if it detects a modem hangup. The former will happen
+ * in disestablish_ppp if the latter hasn't already happened, so we
+ * shouldn't need to do anything.
+ *
+ * Just to be sure, set the real serial port to the normal discipline.
+ */
+
+void
+restore_loop(void)
+ {
+ if (ppp_fd != slave_fd)
+ {
+ (void) ioctl(ppp_fd, TIOCSETD, &tty_disc);
+ set_ppp_fd(slave_fd);
+ }
+ }
+
+/********************************************************************
+ *
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+
+int
+sifnpmode(u, proto, mode)
+ int u;
+ int proto;
+ enum NPmode mode;
+{
+ struct npioctl npi;
+
+ npi.protocol = proto;
+ npi.mode = mode;
+ if (ioctl(ppp_fd, PPPIOCSNPMODE, (caddr_t) &npi) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE, %d, %d): %m(%d)",
+ proto, mode, errno);
+ syslog(LOG_ERR, "ppp_fd=%d slave_fd=%d\n", ppp_fd, slave_fd);
+ }
+ return 0;
+ }
+ return 1;
+ }
+
+\f
+/********************************************************************
+ *
+ * sipxfaddr - Config the interface IPX networknumber
+ */
+
+int sipxfaddr (int unit, unsigned long int network, unsigned char * node )
+ {
+ int result = 1;
+
+#ifdef IPX_CHANGE
+ int skfd;
+ struct sockaddr_ipx ipx_addr;
+ struct ifreq ifr;
+ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
+
+ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+ if (skfd < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_DEBUG, "socket(AF_IPX): %m(%d)", errno);
+ }
+ result = 0;
+ }
+ else
+ {
+ memset (&ifr, '\0', sizeof (ifr));
+ strcpy (ifr.ifr_name, ifname);
+
+ memcpy (sipx->sipx_node, node, IPX_NODE_LEN);
+ sipx->sipx_family = AF_IPX;
+ sipx->sipx_port = 0;
+ sipx->sipx_network = htonl (network);
+ sipx->sipx_type = IPX_FRAME_ETHERII;
+ sipx->sipx_action = IPX_CRTITF;
+/*
+ * Set the IPX device
+ */
+ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0)
+ {
+ result = 0;
+ if (errno != EEXIST)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_DEBUG,
+ "ioctl(SIOCAIFADDR, CRTITF): %m(%d)", errno);
+ }
+ }
+ else
+ {
+ syslog (LOG_WARNING,
+ "ioctl(SIOCAIFADDR, CRTITF): Address already exists");
+ }
+ }
+ close (skfd);
+ }
+#endif
+ return result;
+ }
+
+/********************************************************************
+ *
+ * cipxfaddr - Clear the information for the IPX network. The IPX routes
+ * are removed and the device is no longer able to pass IPX
+ * frames.
+ */
+
+int cipxfaddr (int unit)
+ {
+ int result = 1;
+
+#ifdef IPX_CHANGE
+ int skfd;
+ struct sockaddr_ipx ipx_addr;
+ struct ifreq ifr;
+ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
+
+ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+ if (skfd < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_DEBUG, "socket(AF_IPX): %m(%d)", errno);
+ }
+ result = 0;
+ }
+ else
+ {
+ memset (&ifr, '\0', sizeof (ifr));
+ strcpy (ifr.ifr_name, ifname);
+
+ sipx->sipx_type = IPX_FRAME_ETHERII;
+ sipx->sipx_action = IPX_DLTITF;
+ sipx->sipx_family = AF_IPX;
+/*
+ * Set the IPX device
+ */
+ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_INFO,
+ "ioctl(SIOCAIFADDR, IPX_DLTITF): %m(%d)", errno);
+ }
+ result = 0;
+ }
+ close (skfd);
+ }
+#endif
+ return result;
+ }
+
+/*
+ * daemon - Detach us from controlling terminal session.
+ */
+int
+daemon(nochdir, noclose)
+ int nochdir, noclose;
+{
+ int pid;
+
+ if ((pid = fork()) < 0)
+ return -1;
+ if (pid != 0)
+ exit(0); /* parent dies */
+ setsid();
+ if (!nochdir)
+ chdir("/");
+ if (!noclose) {
+ fclose(stdin); /* don't need stdin, stdout, stderr */
+ fclose(stdout);
+ fclose(stderr);
+ }
+ return 0;