]> git.ozlabs.org Git - ppp.git/commitdiff
Add pty, notty and record options.
authorPaul Mackerras <paulus@samba.org>
Mon, 22 Mar 1999 05:55:40 +0000 (05:55 +0000)
committerPaul Mackerras <paulus@samba.org>
Mon, 22 Mar 1999 05:55:40 +0000 (05:55 +0000)
Fix stats - problem was differing stats structures between
linux and other platforms.
Fix for removing proxy arp entry on linux.
IPX patches.

12 files changed:
pppd/ipxcp.c
pppd/main.c
pppd/options.c
pppd/pppd.8
pppd/pppd.h
pppd/sys-NeXT.c
pppd/sys-bsd.c
pppd/sys-linux.c
pppd/sys-osf.c
pppd/sys-sunos4.c
pppd/sys-svr4.c
pppd/sys-ultrix.c

index 840daf5ae3ae95d79c1894a9da1f2ecfd2069c57..91cad490b72de1b82e7b5334e78511773564744a 100644 (file)
@@ -19,7 +19,7 @@
 
 #ifdef IPX_CHANGE
 #ifndef lint
-static char rcsid[] = "$Id: ipxcp.c,v 1.13 1999/03/19 01:22:09 paulus Exp $";
+static char rcsid[] = "$Id: ipxcp.c,v 1.14 1999/03/22 05:55:31 paulus Exp $";
 #endif
 
 /*
@@ -199,7 +199,7 @@ short int internal;
 {
     short int  external;
 
-    if (internal & IPX_NONE)
+    if (internal & BIT(IPX_NONE) )
         external = IPX_NONE;
     else
         external = RIP_SAP;
@@ -666,9 +666,8 @@ ipxcp_ackci(f, p, len)
        ACKCINETWORK  (IPX_NETWORK_NUMBER,  go->neg_nn,     go->our_network);
        ACKCINODE     (IPX_NODE_NUMBER,     go->neg_node,   go->our_node);
        ACKCINAME     (IPX_ROUTER_NAME,     go->neg_name,   go->name);
-       ACKCIPROTO    (IPX_ROUTER_PROTOCOL, go->neg_router, go->router);
-       ACKCIPROTO    (IPX_ROUTER_PROTOCOL, go->neg_router, go->router);
-       ACKCIPROTO    (IPX_ROUTER_PROTOCOL, go->neg_router, go->router);
+       if (len > 0)
+               ACKCIPROTO    (IPX_ROUTER_PROTOCOL, go->neg_router, go->router);
 /*
  * This is the end of the record.
  */
index 7ad8d3f1d29fd52c683ccdbcd0369bb27ae5976f..4a4e14b010cbbf23559380017c7bdf48561bebd8 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: main.c,v 1.63 1999/03/19 04:23:40 paulus Exp $";
+static char rcsid[] = "$Id: main.c,v 1.64 1999/03/22 05:55:31 paulus Exp $";
 #endif
 
 #include <stdio.h>
@@ -76,12 +76,12 @@ int ifunit;                 /* Interface unit number */
 char *progname;                        /* Name of this program */
 char hostname[MAXNAMELEN];     /* Our hostname */
 static char pidfilename[MAXPATHLEN];   /* name of pid file */
-static char default_devnam[MAXPATHLEN];        /* name of default device */
+static char ppp_devnam[MAXPATHLEN]; /* name of PPP tty (maybe ttypx) */
 static pid_t pid;              /* Our pid */
 static uid_t uid;              /* Our real user-id */
 static int conn_running;       /* we have a [dis]connector running */
 
-int ttyfd = -1;                        /* Serial port file descriptor */
+int ttyfd;                     /* Serial port file descriptor */
 mode_t tty_mode = -1;          /* Original access permissions to tty */
 int baud_rate;                 /* Actual bits/second for serial device */
 int hungup;                    /* terminal has been hung up */
@@ -92,6 +92,9 @@ int log_to_fd;                        /* send log messages to this fd too */
 
 static int fd_ppp;             /* fd for talking PPP */
 static int fd_loop;            /* fd for getting demand-dial packets */
+static int pty_master;         /* fd for master side of pty */
+static int pty_slave;          /* fd for slave side of pty */
+static int real_ttyfd;         /* fd for actual serial port (not pty) */
 
 int phase;                     /* where the link is at */
 int kill_link;
@@ -117,15 +120,17 @@ int ngroups;                      /* How many groups valid in groups */
 
 static struct timeval start_time;      /* Time when link was started. */
 
-struct ppp_stats link_stats;
+struct pppd_stats link_stats;
 int link_stats_valid;
 
+static int charshunt_pid;      /* Process ID for charshunt */
+static FILE *recordf;          /* File for recording chars sent/rcvd */
+
 /* Prototypes for procedures local to this file. */
 
 static void create_pidfile __P((void));
 static void cleanup __P((void));
 static void close_tty __P((void));
-static void hangup_modem __P((int));
 static void get_input __P((void));
 static void calltimeout __P((void));
 static struct timeval *timeleft __P((struct timeval *));
@@ -137,13 +142,17 @@ static void toggle_debug __P((int));
 static void open_ccp __P((int));
 static void bad_signal __P((int));
 static void holdoff_end __P((void *));
-static int device_script __P((char *, int));
-static void reap_kids __P((void));
+static int device_script __P((char *, int, int));
+static void reap_kids __P((int waitfor));
 static void pr_log __P((void *, char *, ...));
 static void logit __P((int, char *, va_list));
 static void vslp_printer __P((void *, char *, ...));
 static void format_packet __P((u_char *, int, void (*) (void *, char *, ...),
                               void *));
+static void record_child __P((int, char *, void (*) (void *), void *));
+static void charshunt __P((int));
+static int record_write(FILE *, int code, u_char *buf, int nb,
+                       struct timeval *);
 
 extern char    *ttyname __P((int));
 extern char    *getlogin __P((void));
@@ -198,10 +207,7 @@ main(argc, argv)
     struct timeval now;
 
     phase = PHASE_INITIALIZE;
-    p = ttyname(0);
-    if (p)
-       strlcpy(devnam, p, sizeof(devnam));
-    strlcpy(default_devnam, devnam, sizeof(default_devnam));
+    log_to_fd = -1;
 
     script_env = NULL;
 
@@ -272,19 +278,59 @@ main(argc, argv)
        exit(1);
     }
 
+    if (ptycommand != NULL || notty) {
+       if (!default_device) {
+           option_error("%s option precludes specifying device name",
+                        notty? "notty": "pty");
+           exit(1);
+       }
+       if (ptycommand != NULL && (notty || record_file != NULL)) {
+           option_error("pty option is incompatible with %s option",
+                        notty? "notty": "record");
+           exit(1);
+       }
+       default_device = notty;
+       lockflag = 0;
+       modem = 0;
+    } else {
+       /*
+        * If the user has specified the default device name explicitly,
+        * pretend they hadn't.
+        */
+       p = isatty(0)? ttyname(0): NULL;
+       if (p == NULL) {
+           if (default_device) {
+               option_error("no device specified and stdin is not a tty");
+               exit(1);
+           }
+       } else {
+           if (default_device)
+               strlcpy(devnam, p, sizeof(devnam));
+           else if (strcmp(devnam, p) == 0)
+               default_device = 1;
+       }
+    }
+    if (default_device)
+       nodetach = 1;
+    else
+       log_to_fd = 1;          /* default to stdout */
+
     script_setenv("DEVICE", devnam);
     slprintf(numbuf, sizeof(numbuf), "%d", baud_rate);
     script_setenv("SPEED", numbuf);
 
     /*
-     * If the user has specified the default device name explicitly,
-     * pretend they hadn't.
+     * Open the record file (as the user) if required.
      */
-    if (!default_device && strcmp(devnam, default_devnam) == 0)
-       default_device = 1;
-    if (default_device)
-       nodetach = 1;
-    log_to_fd = !default_device? 1: -1;        /* default to stdout */
+    if (record_file != NULL) {
+       if (uid != 0)
+           seteuid(uid);
+       recordf = fopen(record_file, "a");
+       if (uid != 0)
+           seteuid(0);
+       if (recordf == NULL)
+           option_error("Couldn't create record file %s: %m", record_file);
+    }
 
     /*
      * Initialize system-dependent stuff and magic number package.
@@ -412,6 +458,8 @@ main(argc, argv)
     for (;;) {
 
        need_holdoff = 1;
+       ttyfd = -1;
+       real_ttyfd = -1;
 
        if (demand) {
            /*
@@ -441,7 +489,7 @@ main(argc, argv)
                }
                if (get_loop_output())
                    break;
-               reap_kids();
+               reap_kids(0);
            }
            remove_fd(fd_loop);
            if (kill_link && !persist)
@@ -454,6 +502,28 @@ main(argc, argv)
            info("Starting link");
        }
 
+       /*
+        * Get a pty master/slave pair if the pty, notty, or record
+        * options were specified.
+        */
+       strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
+       pty_master = -1;
+       pty_slave = -1;
+       if (ptycommand != NULL || notty || record_file != NULL) {
+           if (!get_pty(&pty_master, &pty_slave, ppp_devnam, uid)) {
+               error("Couldn't allocate pseudo-tty");
+               goto fail;
+           }
+           set_up_tty(pty_slave, 1);
+           if (ptycommand != NULL) {
+               if (device_script(ptycommand, pty_master, 1) < 0)
+                   goto fail;
+               ttyfd = pty_slave;
+               close(pty_master);
+               pty_master = -1;
+           }
+       }
+
        /*
         * Lock the device if we've been asked to.
         */
@@ -472,68 +542,106 @@ main(argc, argv)
         */
        hungup = 0;
        kill_link = 0;
-       for (;;) {
-           /* If the user specified the device name, become the
-              user before opening it. */
-           if (!devnam_info.priv)
-               seteuid(uid);
-           ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
-           if (!devnam_info.priv)
-               seteuid(0);
-           if (ttyfd >= 0)
-               break;
-           if (errno != EINTR)
-               error("Failed to open %s: %m", devnam);
-           if (!persist || errno != EINTR)
-               goto fail;
-       }
-       if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1
-           || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
-           warn("Couldn't reset non-blocking mode on device: %m");
-
-       /*
-        * Do the equivalent of `mesg n' to stop broadcast messages.
-        */
-       if (fstat(ttyfd, &statbuf) < 0
-           || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) {
-           warn("Couldn't restrict write permissions to %s: %m", devnam);
-       } else
-           tty_mode = statbuf.st_mode;
-
-       /* run connection script */
-       if (connector && connector[0]) {
-           MAINDEBUG(("Connecting with <%s>", connector));
-
-           if (!default_device && modem) {
-               hangup_modem(ttyfd);    /* in case modem is off hook */
-               sleep(1);
+       if (devnam[0] != 0) {
+           for (;;) {
+               /* If the user specified the device name, become the
+                  user before opening it. */
+               if (!devnam_info.priv)
+                   seteuid(uid);
+               ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
+               if (!devnam_info.priv)
+                   seteuid(0);
+               if (ttyfd >= 0)
+                   break;
+               if (errno != EINTR)
+                   error("Failed to open %s: %m", devnam);
+               if (!persist || errno != EINTR)
+                   goto fail;
            }
+           if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1
+               || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
+               warn("Couldn't reset non-blocking mode on device: %m");
+
+           /*
+            * Do the equivalent of `mesg n' to stop broadcast messages.
+            */
+           if (fstat(ttyfd, &statbuf) < 0
+               || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) {
+               warn("Couldn't restrict write permissions to %s: %m", devnam);
+           } else
+               tty_mode = statbuf.st_mode;
 
            /*
             * Set line speed, flow control, etc.
-            * On most systems we set CLOCAL for now so that we can talk
+            * If we have a non-null connection script,
+            * on most systems we set CLOCAL for now so that we can talk
             * to the modem before carrier comes up.  But this has the
             * side effect that we might miss it if CD drops before we
             * get to clear CLOCAL below.  On systems where we can talk
             * successfully to the modem with CLOCAL clear and CD down,
             * we could clear CLOCAL at this point.
             */
-           set_up_tty(ttyfd, 1);
+           set_up_tty(ttyfd, (connector != NULL && connector[0] != 0));
+           real_ttyfd = ttyfd;
+       }
+
+       /*
+        * If the notty and/or record option was specified,
+        * start up the character shunt now.
+        */
+       if (notty || record_file != NULL) {
+           int cpid;
 
-           if (device_script(connector, ttyfd) < 0) {
+           cpid = fork();
+           if (cpid == -1) {
+               error("Can't fork process for character shunt: %m");
+               goto fail;
+           }
+           if (cpid == 0) {
+               close(pty_slave);
+               setuid(uid);
+               if (getuid() != uid)
+                   fatal("setuid failed");
+               setgid(getgid());
+               charshunt(ttyfd);
+               exit(0);
+           }
+           charshunt_pid = cpid;
+           close(pty_master);
+           pty_master = -1;
+           if (ttyfd >= 0)
+               close(ttyfd);
+           ttyfd = pty_slave;
+           record_child(cpid, "pppd (charshunt)", NULL, NULL);
+       }
+
+       /* run connection script */
+       if (connector && connector[0]) {
+           MAINDEBUG(("Connecting with <%s>", connector));
+
+           if (real_ttyfd != -1) {
+               if (!default_device && modem) {
+                   setdtr(real_ttyfd, 0);      /* in case modem is off hook */
+                   sleep(1);
+                   setdtr(real_ttyfd, 1);
+               }
+           }
+
+           if (device_script(connector, ttyfd, 0) < 0) {
                error("Connect script failed");
                goto fail;
            }
 
            info("Serial connection established.");
-           sleep(1);           /* give it time to set up its terminal */
-       }
 
-       /* set line speed, flow control, etc.; clear CLOCAL if modem option */
-       set_up_tty(ttyfd, 0);
+           /* set line speed, flow control, etc.;
+              clear CLOCAL if modem option */
+           if (real_ttyfd != -1)
+               set_up_tty(real_ttyfd, 0);
+       }
 
        /* reopen tty if necessary to wait for carrier */
-       if (connector == NULL && modem) {
+       if (connector == NULL && modem && devnam[0] != 0) {
            for (;;) {
                if ((i = open(devnam, O_RDWR)) >= 0)
                    break;
@@ -547,12 +655,14 @@ main(argc, argv)
 
        /* run welcome script, if any */
        if (welcomer && welcomer[0]) {
-           if (device_script(welcomer, ttyfd) < 0)
+           if (device_script(welcomer, ttyfd, 0) < 0)
                warn("Welcome script failed");
        }
 
        /* set up the serial device as a ppp interface */
        fd_ppp = establish_ppp(ttyfd);
+       if (fd_ppp < 0)
+           goto fail;
 
        if (!demand) {
            
@@ -567,9 +677,22 @@ main(argc, argv)
         * Start opening the connection and wait for
         * incoming events (reply, timeout, etc.).
         */
-       notice("Connect: %s <--> %s", ifname, devnam);
+       notice("Connect: %s <--> %s", ifname, ppp_devnam);
        gettimeofday(&start_time, NULL);
        lcp_lowerup(0);
+
+       /*
+        * If we are initiating this connection, wait for a short
+        * time for something from the peer.  This can avoid bouncing
+        * our packets off his tty before he has it set up.
+        */
+       if (connector != NULL || ptycommand != NULL) {
+           struct timeval t;
+           t.tv_sec = 1;
+           t.tv_usec = 0;
+           wait_input(&t);
+       }
+
        lcp_open(0);            /* Start protocol */
        open_ccp_flag = 0;
        add_fd(fd_ppp);
@@ -598,7 +721,7 @@ main(argc, argv)
                }
                open_ccp_flag = 0;
            }
-           reap_kids();        /* Don't leave dead kids lying around */
+           reap_kids(0);       /* Don't leave dead kids lying around */
        }
 
        /*
@@ -607,11 +730,11 @@ main(argc, argv)
        if (gettimeofday(&now, NULL) >= 0) {
            int t = now.tv_sec - start_time.tv_sec;
            t = (t + 5) / 6;    /* now in 1/10ths of minutes */
-           info("Connect time %d.%d minutes", t/10, t%10);
+           info("Connect time %d.%d minutes.", t/10, t%10);
        }
        if (link_stats_valid) {
-           info("Send %d bytes, received %d bytes",
-                link_stats.p.ppp_obytes, link_stats.p.ppp_ibytes);
+           info("Sent %d bytes, received %d bytes.",
+                link_stats.bytes_out, link_stats.bytes_in);
        }
 
        /*
@@ -631,7 +754,7 @@ main(argc, argv)
         */
        if (disconnector && !hungup) {
            set_up_tty(ttyfd, 1);
-           if (device_script(disconnector, ttyfd) < 0) {
+           if (device_script(disconnector, ttyfd, 0) < 0) {
                warn("disconnect script failed");
            } else {
                info("Serial link disconnected.");
@@ -641,6 +764,10 @@ main(argc, argv)
            lcp_lowerdown(0);
 
     fail:
+       if (pty_master >= 0)
+           close(pty_master);
+       if (pty_slave >= 0 && pty_slave != ttyfd)
+           close(pty_slave);
        if (ttyfd >= 0)
            close_tty();
        if (locked) {
@@ -681,7 +808,7 @@ main(argc, argv)
                    kill_link = 0;
                    phase = PHASE_DORMANT; /* allow signal to end holdoff */
                }
-               reap_kids();
+               reap_kids(0);
            } while (phase == PHASE_HOLDOFF);
            if (!persist)
                break;
@@ -690,7 +817,7 @@ main(argc, argv)
 
     /* Wait for scripts to finish */
     while (n_children > 0)
-       reap_kids();
+       reap_kids(1);
 
     die(0);
     return 0;
@@ -868,7 +995,7 @@ close_tty()
 
     /* drop dtr to hang up */
     if (!default_device && modem) {
-       hangup_modem(ttyfd);
+       setdtr(ttyfd, 0);
        /*
         * This sleep is in case the serial port has CLOCAL set by default,
         * and consequently will reassert DTR when we close the device.
@@ -889,16 +1016,6 @@ close_tty()
     ttyfd = -1;
 }
 
-/*
- * hangup_modem - hang up the modem by clearing DTR.
- */
-static void
-hangup_modem(ttyfd)
-    int ttyfd;
-{
-    setdtr(ttyfd, 0);
-}
-
 
 struct callout {
     struct timeval     c_time;         /* time at which to call routine */
@@ -1057,6 +1174,8 @@ hup(sig)
     if (conn_running)
        /* Send the signal to the [dis]connector process(es) also */
        kill_my_pg(sig);
+    if (charshunt_pid)
+       kill(charshunt_pid, sig);
     if (waiting)
        siglongjmp(sigjmp, 1);
 }
@@ -1078,6 +1197,8 @@ term(sig)
     if (conn_running)
        /* Send the signal to the [dis]connector process(es) also */
        kill_my_pg(sig);
+    if (charshunt_pid)
+       kill(charshunt_pid, sig);
     if (waiting)
        siglongjmp(sigjmp, 1);
 }
@@ -1146,6 +1267,8 @@ bad_signal(sig)
     error("Fatal signal %d", sig);
     if (conn_running)
        kill_my_pg(SIGTERM);
+    if (charshunt_pid)
+       kill(charshunt_pid, SIGTERM);
     die(1);
 }
 
@@ -1155,20 +1278,22 @@ bad_signal(sig)
  * serial device.
  */
 static int
-device_script(program, inout)
+device_script(program, inout, dont_wait)
     char *program;
     int inout;
+    int dont_wait;
 {
     int pid;
-    int status;
+    int status = 0;
     int errfd;
 
-    conn_running = 1;
+    ++conn_running;
     pid = fork();
 
     if (pid < 0) {
-       conn_running = 0;
-       fatal("Failed to create child process: %m");
+       --conn_running;
+       error("Failed to create child process: %m");
+       return -1;
     }
 
     if (pid == 0) {
@@ -1201,6 +1326,8 @@ device_script(program, inout)
            error("setuid failed");
            exit(1);
        }
+       if (ttyfd > 2 && ttyfd != inout)
+           close(ttyfd);
        setgid(getgid());
        execl("/bin/sh", "sh", "-c", program, (char *)0);
        error("could not exec /bin/sh: %m");
@@ -1208,12 +1335,16 @@ device_script(program, inout)
        /* NOTREACHED */
     }
 
-    while (waitpid(pid, &status, 0) < 0) {
-       if (errno == EINTR)
-           continue;
-       fatal("error waiting for (dis)connection process: %m");
+    if (dont_wait) {
+       record_child(pid, program, NULL, NULL);
+    } else {
+       while (waitpid(pid, &status, 0) < 0) {
+           if (errno == EINTR)
+               continue;
+           fatal("error waiting for (dis)connection process: %m");
+       }
+       --conn_running;
     }
-    conn_running = 0;
 
     return (status == 0 ? 0 : -1);
 }
@@ -1252,7 +1383,6 @@ run_program(prog, args, must_exist, done, arg)
     void *arg;
 {
     int pid;
-    struct subprocess *chp;
     struct stat sbuf;
 
     /*
@@ -1270,8 +1400,10 @@ run_program(prog, args, must_exist, done, arg)
     }
 
     pid = fork();
-    if (pid == -1)
-       fatal("Failed to create child process for %s: %m", prog);
+    if (pid == -1) {
+       error("Failed to create child process for %s: %m", prog);
+       return -1;
+    }
     if (pid == 0) {
        int new_fd;
 
@@ -1311,13 +1443,42 @@ run_program(prog, args, must_exist, done, arg)
 
        /* run the program */
        execve(prog, args, script_env);
-       if (must_exist || errno != ENOENT)
-           warn("Can't execute %s: %m", prog);
+       if (must_exist || errno != ENOENT) {
+           /* have to reopen the log, there's nowhere else
+              for the message to go. */
+#ifdef ULTRIX
+           openlog("pppd", LOG_PID);
+#else
+           openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
+           setlogmask(LOG_UPTO(LOG_INFO));
+#endif
+           syslog(LOG_ERR, "Can't execute %s: %m", prog);
+           closelog();
+       }
        _exit(-1);
     }
 
     if (debug)
        dbglog("Script %s started; pid = %d", prog, pid);
+    record_child(pid, prog, done, arg);
+
+    return pid;
+}
+
+
+/*
+ * record_child - add a child process to the list for reap_kids
+ * to use.
+ */
+static void
+record_child(pid, prog, done, arg)
+    int pid;
+    char *prog;
+    void (*done) __P((void *));
+    void *arg;
+{
+    struct subprocess *chp;
+
     ++n_children;
 
     chp = (struct subprocess *) malloc(sizeof(struct subprocess));
@@ -1331,8 +1492,6 @@ run_program(prog, args, must_exist, done, arg)
        chp->next = children;
        children = chp;
     }
-
-    return pid;
 }
 
 
@@ -1341,29 +1500,30 @@ run_program(prog, args, must_exist, done, arg)
  * and log a message for abnormal terminations.
  */
 static void
-reap_kids()
+reap_kids(waitfor)
+    int waitfor;
 {
     int pid, status;
     struct subprocess *chp, **prevp;
 
     if (n_children == 0)
        return;
-    while ((pid = waitpid(-1, &status, WNOHANG)) != -1 && pid != 0) {
+    while ((pid = waitpid(-1, &status, (waitfor? 0: WNOHANG))) != -1
+          && pid != 0) {
        --n_children;
        for (prevp = &children; (chp = *prevp) != NULL; prevp = &chp->next)
            if (chp->pid == pid)
                break;
-       if (debug)
-           dbglog("process %d (%s) finished, status = 0x%x",
-                  pid, (chp? chp->prog: "??"), status);
        if (WIFSIGNALED(status)) {
            warn("Child process %s (pid %d) terminated with signal %d",
                 (chp? chp->prog: "??"), pid, WTERMSIG(status));
-       }
+       } else if (debug)
+           dbglog("process %d (%s) finished, status = 0x%x",
+                  pid, (chp? chp->prog: "??"), status);
        if (chp && chp->done)
            (*chp->done)(chp->arg);
     }
-    if (pid == -1 && errno != ECHILD)
+    if (pid == -1 && errno != ECHILD && errno != EINTR)
        error("Error waiting for child process: %m");
 }
 
@@ -2079,3 +2239,237 @@ dbglog __V((char *fmt, ...))
     logit(LOG_DEBUG, fmt, pvar);
     va_end(pvar);
 }
+
+/*
+ * charshunt - the character shunt, which passes characters between
+ * the pty master side and the serial port (or stdin/stdout).
+ * This runs as the user (not as root).
+ */
+static void
+charshunt(ttyfd)
+    int ttyfd;
+{
+    int ifd, ofd, nfds;
+    int n;
+    fd_set ready, writey;
+    u_char *ibufp, *obufp;
+    int nibuf, nobuf;
+    int flags;
+    int pty_readable, stdin_readable;
+    struct timeval lasttime;
+
+    /*
+     * Reset signal handlers.
+     */
+    signal(SIGHUP, SIG_DFL);           /* Hangup */
+    signal(SIGINT, SIG_DFL);           /* Interrupt */
+    signal(SIGTERM, SIG_DFL);          /* Terminate */
+    signal(SIGCHLD, SIG_DFL);
+    signal(SIGUSR1, SIG_DFL);
+    signal(SIGUSR2, SIG_DFL);
+    signal(SIGABRT, SIG_DFL);
+    signal(SIGALRM, SIG_DFL);
+    signal(SIGFPE, SIG_DFL);
+    signal(SIGILL, SIG_DFL);
+    signal(SIGPIPE, SIG_DFL);
+    signal(SIGQUIT, SIG_DFL);
+    signal(SIGSEGV, SIG_DFL);
+#ifdef SIGBUS
+    signal(SIGBUS, SIG_DFL);
+#endif
+#ifdef SIGEMT
+    signal(SIGEMT, SIG_DFL);
+#endif
+#ifdef SIGPOLL
+    signal(SIGPOLL, SIG_DFL);
+#endif
+#ifdef SIGPROF
+    signal(SIGPROF, SIG_DFL);
+#endif
+#ifdef SIGSYS
+    signal(SIGSYS, SIG_DFL);
+#endif
+#ifdef SIGTRAP
+    signal(SIGTRAP, SIG_DFL);
+#endif
+#ifdef SIGVTALRM
+    signal(SIGVTALRM, SIG_DFL);
+#endif
+#ifdef SIGXCPU
+    signal(SIGXCPU, SIG_DFL);
+#endif
+#ifdef SIGXFSZ
+    signal(SIGXFSZ, SIG_DFL);
+#endif
+
+    /* work out which fds we're using. */
+    if (notty) {
+       ifd = 0;
+       ofd = 1;
+    } else {
+       ifd = ofd = ttyfd;
+    }
+    nfds = (ofd > pty_master? ifd: pty_master) + 1;
+
+    /* set all the fds to non-blocking mode */
+    flags = fcntl(pty_master, F_GETFL);
+    if (flags == -1
+       || fcntl(pty_master, F_SETFL, flags | O_NONBLOCK) == -1)
+       warn("couldn't set pty master to nonblock: %m");
+    flags = fcntl(ifd, F_GETFL);
+    if (flags == -1
+       || fcntl(ifd, F_SETFL, flags | O_NONBLOCK) == -1)
+       warn("couldn't set %s to nonblock: %m", (notty? "stdin": "tty"));
+    if (notty) {
+       flags = fcntl(ofd, F_GETFL);
+       if (flags == -1
+           || fcntl(ofd, F_SETFL, flags | O_NONBLOCK) == -1)
+           warn("couldn't set stdout to nonblock: %m");
+    }
+
+    nibuf = nobuf = 0;
+    ibufp = obufp = NULL;
+    pty_readable = stdin_readable = 1;
+    gettimeofday(&lasttime, NULL);
+    while (nibuf != 0 || nobuf != 0 || pty_readable || stdin_readable) {
+       FD_ZERO(&ready);
+       FD_ZERO(&writey);
+       if (nibuf != 0)
+           FD_SET(pty_master, &writey);
+       else if (stdin_readable)
+           FD_SET(ifd, &ready);
+       if (nobuf != 0)
+           FD_SET(ofd, &writey);
+       else if (pty_readable)
+           FD_SET(pty_master, &ready);
+       if (select(nfds, &ready, &writey, NULL, NULL) < 0) {
+           if (errno != EINTR)
+               fatal("select");
+           continue;
+       }
+       if (FD_ISSET(ifd, &ready)) {
+           ibufp = inpacket_buf;
+           nibuf = read(ifd, ibufp, sizeof(inpacket_buf));
+           if (nibuf < 0 && errno == EIO)
+               nibuf = 0;
+           if (nibuf < 0) {
+               if (!(errno == EINTR || errno == EAGAIN)) {
+                   error("Error reading standard input: %m");
+                   break;
+               }
+               nibuf = 0;
+           } else if (nibuf == 0) {
+               /* end of file from stdin */
+               stdin_readable = 0;
+               /* do a 0-length write, hopefully this will generate
+                  an EOF (hangup) on the slave side. */
+               write(pty_master, inpacket_buf, 0);
+               if (recordf)
+                   if (!record_write(recordf, 4, NULL, 0, &lasttime))
+                       recordf = NULL;
+           } else {
+               FD_SET(pty_master, &writey);
+               if (recordf)
+                   if (!record_write(recordf, 2, ibufp, nibuf, &lasttime))
+                       recordf = NULL;
+           }
+       }
+       if (FD_ISSET(pty_master, &ready)) {
+           obufp = outpacket_buf;
+           nobuf = read(pty_master, obufp, sizeof(outpacket_buf));
+           if (nobuf < 0 && errno == EIO)
+               nobuf = 0;
+           if (nobuf < 0) {
+               if (!(errno == EINTR || errno == EAGAIN)) {
+                   error("Error reading pseudo-tty master: %m");
+                   break;
+               }
+               nobuf = 0;
+           } else if (nobuf == 0) {
+               /* end of file from the pty - slave side has closed */
+               pty_readable = 0;
+               stdin_readable = 0;     /* pty is not writable now */
+               nibuf = 0;
+               close(ofd);
+               if (recordf)
+                   if (!record_write(recordf, 3, NULL, 0, &lasttime))
+                       recordf = NULL;
+           } else {
+               FD_SET(ofd, &writey);
+               if (recordf)
+                   if (!record_write(recordf, 1, obufp, nobuf, &lasttime))
+                       recordf = NULL;
+           }
+       }
+       if (FD_ISSET(ofd, &writey)) {
+           n = write(ofd, obufp, nobuf);
+           if (n < 0) {
+               if (errno != EIO) {
+                   error("Error writing standard output: %m");
+                   break;
+               }
+               pty_readable = 0;
+               nobuf = 0;
+           } else {
+               obufp += n;
+               nobuf -= n;
+           }
+       }
+       if (FD_ISSET(pty_master, &writey)) {
+           n = write(pty_master, ibufp, nibuf);
+           if (n < 0) {
+               if (errno != EIO) {
+                   error("Error writing pseudo-tty master: %m");
+                   break;
+               }
+               stdin_readable = 0;
+               nibuf = 0;
+           } else {
+               ibufp += n;
+               nibuf -= n;
+           }
+       }
+    }
+    exit(0);
+}
+
+static int
+record_write(f, code, buf, nb, tp)
+    FILE *f;
+    int code;
+    u_char *buf;
+    int nb;
+    struct timeval *tp;
+{
+    struct timeval now;
+    int diff;
+
+    gettimeofday(&now, NULL);
+    diff = (now.tv_sec - tp->tv_sec) * 10
+       + (now.tv_usec - tp->tv_usec) / 100000;
+    if (diff > 0) {
+       if (diff > 255) {
+           putc(5, f);
+           putc(diff >> 24, f);
+           putc(diff >> 16, f);
+           putc(diff >> 8, f);
+           putc(diff, f);
+       } else {
+           putc(6, f);
+           putc(diff, f);
+       }
+       *tp = now;
+    }
+    putc(code, f);
+    if (buf != NULL) {
+       putc(nb >> 8, f);
+       putc(nb, f);
+       fwrite(buf, nb, 1, f);
+    }
+    fflush(f);
+    if (ferror(f)) {
+       error("Error writing record file: %m");
+       return 0;
+    }
+    return 1;
+}
index 53456cc8d13ead6754a11e37b39c12724777d465..7d5c71af36117b6e6ceae7290e79e8a54de2337f 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: options.c,v 1.53 1999/03/19 04:23:44 paulus Exp $";
+static char rcsid[] = "$Id: options.c,v 1.54 1999/03/22 05:55:33 paulus Exp $";
 #endif
 
 #include <ctype.h>
@@ -65,7 +65,7 @@ int   dflag = 0;              /* Tell libpcap we want debugging */
 int    debug = 0;              /* Debug flag */
 int    kdebugflag = 0;         /* Tell kernel to print debug messages */
 int    default_device = 1;     /* Using /dev/tty or equivalent */
-char   devnam[MAXPATHLEN] = "/dev/tty";        /* Device name */
+char   devnam[MAXPATHLEN];     /* Device name */
 int    crtscts = 0;            /* Use hardware flow control */
 bool   modem = 1;              /* Use modem control lines */
 int    inspeed = 0;            /* Input/Output speed requested */
@@ -76,6 +76,7 @@ bool  updetach = 0;           /* Detach once link is up */
 char   *connector = NULL;      /* Script to establish physical link */
 char   *disconnector = NULL;   /* Script to disestablish physical link */
 char   *welcomer = NULL;       /* Script to run after phys link estab. */
+char   *ptycommand = NULL;     /* Command to run on other side of pty */
 int    maxconnect = 0;         /* Maximum connect time */
 char   user[MAXNAMELEN];       /* Username for PAP */
 char   passwd[MAXSECRETLEN];   /* Password for PAP */
@@ -85,6 +86,8 @@ bool  demand = 0;             /* do dial-on-demand */
 char   *ipparam = NULL;        /* Extra parameter for ip up/down scripts */
 int    idle_time_limit = 0;    /* Disconnect if idle for this many seconds */
 int    holdoff = 30;           /* # seconds to pause before reconnecting */
+bool   notty = 0;              /* Stdin/out is not a tty */
+char   *record_file = NULL;    /* File to record chars sent/received */
 
 extern option_t auth_options[];
 
@@ -92,6 +95,7 @@ struct option_info connector_info;
 struct option_info disconnector_info;
 struct option_info welcomer_info;
 struct option_info devnam_info;
+struct option_info ptycommand_info;
 
 #ifdef PPP_FILTER
 struct bpf_program pass_filter;/* Filter program for packets to pass */
@@ -159,6 +163,13 @@ option_t general_options[] = {
     { "welcome", o_string, &welcomer,
       "Script to welcome client",
       OPT_A2INFO | OPT_PRIVFIX, &welcomer_info },
+    { "pty", o_string, &ptycommand,
+      "Script to run on pseudo-tty master side",
+      OPT_A2INFO | OPT_PRIVFIX, &ptycommand_info },
+    { "notty", o_bool, &notty,
+      "Input/output is not a tty", 1 },
+    { "record", o_string, &record_file,
+      "Record characters sent/received to file" },
     { "maxconnect", o_int, &maxconnect,
       "Set connection time limit", OPT_LLIMIT|OPT_NOINCR|OPT_ZEROINF },
     { "crtscts", o_int, &crtscts,
@@ -440,7 +451,7 @@ options_for_tty()
     dev = devnam;
     if (strncmp(dev, "/dev/", 5) == 0)
        dev += 5;
-    if (strcmp(dev, "tty") == 0)
+    if (dev[0] == 0 || strcmp(dev, "tty") == 0)
        return 1;               /* don't look for /etc/ppp/options.tty */
     pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1;
     path = malloc(pl);
index 04d60c3b56a151848589ea467ae6561e27a6ad31..59d74c0bcc980e5b2e00be1668828c4dfc487623 100644 (file)
@@ -1,5 +1,5 @@
 .\" manual page [] for pppd 2.3
-.\" $Id: pppd.8,v 1.35 1999/03/19 01:24:57 paulus Exp $
+.\" $Id: pppd.8,v 1.36 1999/03/22 05:55:34 paulus Exp $
 .\" SH section heading
 .\" SS subsection heading
 .\" LP paragraph
@@ -560,6 +560,19 @@ Disable the \fIproxyarp\fR option.  The system administrator who
 wishes to prevent users from creating proxy ARP entries with pppd can
 do so by placing this option in the /etc/ppp/options file.
 .TP
+.B notty
+Normally, pppd requires a terminal device.  With this option, pppd
+will allocate itself a pseudo-tty master/slave pair and use the slave
+as its terminal device.  Pppd will create a child process to act as a
+`character shunt' to transfer characters between the pseudo-tty master
+and its standard input and output.  Thus pppd will transmit characters
+on its standard output and receive characters on its standard input
+even if they are not terminal devices.  This option increases the
+latency and CPU overhead of transferring data over the ppp interface
+as all of the characters sent and received must flow through the
+character shunt process.  An explicit device name may not be given if
+this option is used.
+.TP
 .B novj
 Disable Van Jacobson style TCP/IP header compression in both the
 transmit and the receive direction.
@@ -628,6 +641,14 @@ with the IP address of the peer and the Ethernet address of this
 system.  This will have the effect of making the peer appear to other
 systems to be on the local ethernet.
 .TP
+.B pty \fIscript
+Specifies that the command \fIscript\fR is to be used to communicate
+rather than a specific terminal device.  Pppd will allocate itself a
+pseudo-tty master/slave pair and use the slave as its terminal
+device.  The \fIscript\fR will be run in a child process with the
+pseudo-tty master as its standard input and output.  An explicit
+device name may not be given if this option is used.
+.TP
 .B receive-all
 With this option, pppd will accept all control characters from the
 peer, including those marked in the receive asyncmap.  Without this
index 60ef281681957cf7810cc188c438027b0de4a67d..dcd469b4c98bc652c7e7e8ecb1763c9e9892a137 100644 (file)
@@ -16,7 +16,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- * $Id: pppd.h,v 1.33 1999/03/19 04:23:45 paulus Exp $
+ * $Id: pppd.h,v 1.34 1999/03/22 05:55:35 paulus Exp $
  */
 
 /*
@@ -110,6 +110,17 @@ struct permitted_ip {
     u_int32_t  mask;           /* base and mask are in network byte order */
 };
 
+/*
+ * Unfortunately, the linux kernel driver uses a different structure
+ * for statistics from the rest of the ports.
+ * This structure serves as a common representation for the bits
+ * pppd needs.
+ */
+struct pppd_stats {
+    unsigned int       bytes_in;
+    unsigned int       bytes_out;
+};
+
 /*
  * Global variables.
  */
@@ -131,7 +142,7 @@ extern char **script_env;   /* Environment variables for scripts */
 extern int     detached;       /* Have detached from controlling tty */
 extern GIDSET_TYPE groups[NGROUPS_MAX];        /* groups the user is in */
 extern int     ngroups;        /* How many groups valid in groups */
-extern struct ppp_stats link_stats; /* byte/packet counts etc. for link */
+extern struct pppd_stats link_stats; /* byte/packet counts etc. for link */
 extern int     link_stats_valid; /* set if link_stats is valid */
 
 /*
@@ -152,6 +163,7 @@ extern bool updetach;       /* Detach from controlling tty when link up */
 extern char    *connector;     /* Script to establish physical link */
 extern char    *disconnector;  /* Script to disestablish physical link */
 extern char    *welcomer;      /* Script to welcome client after connection */
+extern char    *ptycommand;    /* Command to run on other side of pty */
 extern int     maxconnect;     /* Maximum connect time (seconds) */
 extern char    user[MAXNAMELEN];/* Our name for authenticating ourselves */
 extern char    passwd[MAXSECRETLEN];   /* Password for PAP */
@@ -166,6 +178,8 @@ extern char *ipparam;       /* Extra parameter for ip up/down scripts */
 extern bool    cryptpap;       /* Others' PAP passwords are encrypted */
 extern int     idle_time_limit;/* Shut down link if idle for this long */
 extern int     holdoff;        /* Dead time before restarting */
+extern bool    notty;          /* Stdin/out is not a tty */
+extern char    *record_file;   /* File to record chars sent/received */
 
 #ifdef PPP_FILTER
 extern struct  bpf_program pass_filter;   /* Filter for pkts to pass */
@@ -313,6 +327,7 @@ void sys_cleanup __P((void));       /* Restore system state before exiting */
 int  sys_check_options __P((void)); /* Check options specified */
 void sys_close __P((void));    /* Clean up in a child before execing */
 int  ppp_available __P((void));        /* Test whether ppp kernel support exists */
+int  get_pty __P((int *, int *, char *, int)); /* Get pty master/slave */
 int  open_ppp_loopback __P((void)); /* Open loopback for demand-dialling */
 int  establish_ppp __P((int)); /* Turn serial port into a ppp interface */
 void restore_loop __P((void)); /* Transfer ppp unit back to loopback */
@@ -341,7 +356,7 @@ void ccp_flags_set __P((int, int, int));
 int  ccp_fatal_error __P((int)); /* Test for fatal decomp error in kernel */
 int  get_idle_time __P((int, struct ppp_idle *));
                                /* Find out how long link has been idle */
-int  get_ppp_stats __P((int, struct ppp_stats *));
+int  get_ppp_stats __P((int, struct pppd_stats *));
                                /* Return link statistics */
 int  sifvjcomp __P((int, int, int, int));
                                /* Configure VJ TCP header compression */
@@ -410,6 +425,7 @@ extern struct option_info devnam_info;
 extern struct option_info connector_info;
 extern struct option_info disconnector_info;
 extern struct option_info welcomer_info;
+extern struct option_info ptycommand_info;
 
 /*
  * Inline versions of get/put char/short/long.
index 7db81d4a43038954cccde98426018319232680b6..d498c4bfe7909e068cd3f87a19014e58b88a7db3 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: sys-NeXT.c,v 1.16 1999/03/19 04:23:46 paulus Exp $";
+static char rcsid[] = "$Id: sys-NeXT.c,v 1.17 1999/03/22 05:55:36 paulus Exp $";
 #endif
 
 #include <stdio.h>
@@ -1455,7 +1455,7 @@ get_idle_time(u, ip)
 int
 get_ppp_stats(u, stats)
     int u;
-    struct ppp_stats *stats;
+    struct pppd_stats *stats;
 {
     struct ifpppstatsreq req;
 
@@ -1465,7 +1465,8 @@ get_ppp_stats(u, stats)
        error("Couldn't get PPP statistics: %m");
        return 0;
     }
-    *stats = req.stats;
+    stats->bytes_in = req.stats.p.ppp_ibytes;
+    stats->bytes_out = req.stats.p.ppp_obytes;
     return 1;
 }
 
index d59f073ca8e64c34dc8ffe5a3535d3eafb30507f..27c568921187984fa3d53b460b2d24503858b917 100644 (file)
@@ -21,7 +21,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: sys-bsd.c,v 1.40 1999/03/19 04:23:47 paulus Exp $";
+static char rcsid[] = "$Id: sys-bsd.c,v 1.41 1999/03/22 05:55:36 paulus Exp $";
 /*     $NetBSD: sys-bsd.c,v 1.1.1.3 1997/09/26 18:53:04 christos Exp $ */
 #endif
 
@@ -798,7 +798,7 @@ get_idle_time(u, ip)
 int
 get_ppp_stats(u, stats)
     int u;
-    struct ppp_stats *stats;
+    struct pppd_stats *stats;
 {
     struct ifpppstatsreq req;
 
@@ -808,7 +808,8 @@ get_ppp_stats(u, stats)
        error("Couldn't get PPP statistics: %m");
        return 0;
     }
-    *stats = req.stats;
+    stats->bytes_in = req.stats.p.ppp_ibytes;
+    stats->bytes_out = req.stats.p.ppp_obytes;
     return 1;
 }
 
index a7fd168b0e8e06ec1b05e831cde69cb769e8d5bf..ba25a93ec843a653635adda286955dc3a603da99 100644 (file)
@@ -120,6 +120,7 @@ static unsigned char inbuf[512]; /* buffer for chars read from loopback */
 static int     if_is_up;       /* Interface has been marked up */
 static u_int32_t default_route_gateway;        /* Gateway for default route added */
 static u_int32_t proxy_arp_addr;       /* Addr for proxy arp entry added */
+static char proxy_arp_dev[16];         /* Device for proxy arp entry */
 
 static char *lock_file;
 
@@ -144,7 +145,7 @@ static int open_route_table (void);
 static int read_route_table (struct rtentry *rt);
 static int defaultroute_exists (struct rtentry *rt);
 static int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr,
-                          char *name);
+                          char *name, int namelen);
 static void decode_version (char *buf, int *version, int *mod, int *patch);
 static int set_kdebugflag(int level);
 static int ppp_registered(void);
@@ -971,7 +972,7 @@ get_idle_time(u, ip)
 int
 get_ppp_stats(u, stats)
     int u;
-    struct ppp_stats *stats;
+    struct pppd_stats *stats;
 {
     struct ifpppstatsreq req;
 
@@ -983,9 +984,10 @@ get_ppp_stats(u, stats)
        error("Couldn't get PPP statistics: %m");
        return 0;
     }
-    *stats = req.stats;
+    stats->bytes_in = req.stats.p.ppp_ibytes;
+    stats->bytes_out = req.stats.p.ppp_obytes;
     return 1;
-} 
+}
 
 /********************************************************************
  *
@@ -1319,11 +1321,13 @@ int sifproxyarp (int unit, u_int32_t his_adr)
  * Get the hardware address of an interface on the same subnet
  * as our local address.
  */
-       if (!get_ether_addr(his_adr, &arpreq.arp_ha, arpreq.arp_dev)) {
+       if (!get_ether_addr(his_adr, &arpreq.arp_ha, proxy_arp_dev,
+                           sizeof(proxy_arp_dev))) {
            error("Cannot determine ethernet address for proxy ARP");
            return 0;
        }
-       
+       strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
+
        if (ioctl(sock_fd, SIOCSARP, (caddr_t)&arpreq) < 0) {
            if ( ! ok_error ( errno ))
                error("ioctl(SIOCSARP): %m(%d)", errno);
@@ -1351,6 +1355,7 @@ int cifproxyarp (int unit, u_int32_t his_adr)
        SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
        ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = his_adr;
        arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+       strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
 
        if (ioctl(sock_fd, SIOCDARP, (caddr_t)&arpreq) < 0) {
            if ( ! ok_error ( errno ))
@@ -1369,7 +1374,7 @@ int cifproxyarp (int unit, u_int32_t his_adr)
 
 static int get_ether_addr (u_int32_t ipaddr,
                           struct sockaddr *hwaddr,
-                          char *name)
+                          char *name, int namelen)
 {
     struct ifreq *ifr, *ifend;
     u_int32_t ina, mask;
@@ -1426,7 +1431,7 @@ static int get_ether_addr (u_int32_t ipaddr,
     if (ifr >= ifend)
         return 0;
 
-    memcpy (name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
+    strlcpy(name, ifreq.ifr_name, namelen);
     info("found interface %s for proxy arp", name);
 /*
  * Now get the hardware address.
@@ -2114,44 +2119,71 @@ int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr)
     return 1;
 }
 
-/********************************************************************
- *
- * open_loopback - open the device we use for getting packets
- * in demand mode.  Under Linux, we use a pty master/slave pair.
+/*
+ * get_pty - get a pty master/slave pair and chown the slave side
+ * to the uid given.  Assumes slave_name points to >= 12 bytes of space.
  */
 int
-open_ppp_loopback(void)
+get_pty(master_fdp, slave_fdp, slave_name, uid)
+    int *master_fdp;
+    int *slave_fdp;
+    char *slave_name;
+    int uid;
 {
-    int flags, i;
+    int i, mfd, sfd;
+    char pty_name[12];
     struct termios tios;
 
-    master_fd = -1;
+    sfd = -1;
     for (i = 0; i < 64; ++i) {
-       slprintf(loop_name, sizeof(loop_name), "/dev/pty%c%x",
+       slprintf(pty_name, sizeof(pty_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;
+       mfd = open(pty_name, O_RDWR, 0);
+       if (mfd >= 0) {
+           pty_name[5] = 't';
+           sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
+           if (sfd >= 0)
+               break;
+           close(mfd);
+       }
     }
-    if (master_fd < 0)
-       fatal("No free pty for loopback");
-    SYSDEBUG(("using %s for loopback", loop_name));
-    loop_name[5] = 't';
-    slave_fd = open(loop_name, O_RDWR | O_NOCTTY, 0);
-    if (slave_fd < 0)
-       fatal("Couldn't open %s for loopback: %m", loop_name);
-
-    set_ppp_fd(slave_fd);
+    if (sfd < 0)
+       return 0;
 
-    if (tcgetattr(ppp_fd, &tios) == 0) {
+    strlcpy(slave_name, pty_name, 12);
+    *master_fdp = mfd;
+    *slave_fdp = sfd;
+    fchown(sfd, uid, -1);
+    fchmod(sfd, S_IRUSR | S_IWUSR);
+    if (tcgetattr(sfd, &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)
-           warn("couldn't set attributes on loopback: %m(%d)", errno);
-    }
+       if (tcsetattr(sfd, TCSAFLUSH, &tios) < 0)
+           warn("couldn't set attributes on pty: %m");
+    } else
+       warn("couldn't get attributes on pty: %m");
+
+    return 1;
+}
+
+/********************************************************************
+ *
+ * open_loopback - open the device we use for getting packets
+ * in demand mode.  Under Linux, we use a pty master/slave pair.
+ */
+int
+open_ppp_loopback(void)
+{
+    int flags;
+
+    if (!get_pty(&master_fd, &slave_fd, loop_name, 0))
+       fatal("No free pty for loopback");
+    SYSDEBUG(("using %s for loopback", loop_name));
+
+    set_ppp_fd(slave_fd);
 
     flags = fcntl(master_fd, F_GETFL);
     if (flags == -1 ||
index c25e33921afdc3eb4b1139d11748c02b9e837304..94b3dd2576d41902d54aad8c17cfec28dc4cb640 100644 (file)
@@ -26,7 +26,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: sys-osf.c,v 1.22 1999/03/19 04:23:49 paulus Exp $";
+static char rcsid[] = "$Id: sys-osf.c,v 1.23 1999/03/22 05:55:38 paulus Exp $";
 #endif
 
 #include <stdio.h>
@@ -1017,12 +1017,16 @@ get_idle_time(u, ip)
 int
 get_ppp_stats(u, stats)
     int u;
-    struct ppp_stats *stats;
+    struct pppd_stats *stats;
 {
-    if (strioctl(pppfd, PPPIO_GETSTAT, stats, 0, sizeof(*stats)) < 0) {
+    struct ppp_stats s;
+
+    if (strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof(s)) < 0) {
        error("Couldn't get link statistics: %m");
        return 0;
     }
+    stats->bytes_in = s.p.ppp_ibytes;
+    stats->bytes_out = s.p.ppp_obytes;
     return 1;
 }
 
index 8a1847faed8d67048b4798faa49a06c4d1ee5350..d0b1ac00d4e2780cbe358e2b549efa50661dbaf3 100644 (file)
@@ -26,7 +26,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: sys-sunos4.c,v 1.17 1999/03/19 04:23:50 paulus Exp $";
+static char rcsid[] = "$Id: sys-sunos4.c,v 1.18 1999/03/22 05:55:39 paulus Exp $";
 #endif
 
 #include <stdio.h>
@@ -865,12 +865,16 @@ get_idle_time(u, ip)
 int
 get_ppp_stats(u, stats)
     int u;
-    struct ppp_stats *stats;
+    struct pppd_stats *stats;
 {
-    if (strioctl(pppfd, PPPIO_GETSTAT, stats, 0, sizeof(*stats)) < 0) {
+    struct ppp_stats s;
+
+    if (strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof(s)) < 0) {
        error("Couldn't get link statistics: %m");
        return 0;
     }
+    stats->bytes_in = s.p.ppp_ibytes;
+    stats->bytes_out = s.p.ppp_obytes;
     return 1;
 }
 
index 461e53640979373dbe328928a5c591fec4da4784..a8d80b91ba5f5e6a8339e2c76cc81802d0377171 100644 (file)
@@ -26,7 +26,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: sys-svr4.c,v 1.28 1999/03/19 04:23:52 paulus Exp $";
+static char rcsid[] = "$Id: sys-svr4.c,v 1.29 1999/03/22 05:55:39 paulus Exp $";
 #endif
 
 #include <limits.h>
@@ -92,6 +92,7 @@ static int    link_mtu, link_mru;
 #define NMODULES       32
 static int     tty_nmodules;
 static char    tty_modules[NMODULES][FMNAMESZ+1];
+static int     tty_npushed;
 
 static int     if_is_up;       /* Interface has been marked up */
 static u_int32_t remote_addr;          /* IP address of peer */
@@ -128,7 +129,7 @@ sys_init()
     if (ipfd < 0)
        fatal("Couldn't open IP device: %m");
 
-    if (default_device)
+    if (default_device && !notty)
        tty_sid = getsid((pid_t)0);
 
     pppfd = open("/dev/ppp", O_RDWR | O_NONBLOCK, 0);
@@ -269,27 +270,36 @@ establish_ppp(fd)
     /* Pop any existing modules off the tty stream. */
     for (i = 0;; ++i)
        if (ioctl(fd, I_LOOK, tty_modules[i]) < 0
+           || strcmp(tty_modules[i], "ptem") == 0
            || ioctl(fd, I_POP, 0) < 0)
            break;
     tty_nmodules = i;
 
     /* Push the async hdlc module and the compressor module. */
-    if (ioctl(fd, I_PUSH, "ppp_ahdl") < 0)
-       fatal("Couldn't push PPP Async HDLC module: %m");
+    tty_npushed = 0;
+    if (ioctl(fd, I_PUSH, "ppp_ahdl") < 0) {
+       error("Couldn't push PPP Async HDLC module: %m");
+       return -1;
+    }
+    ++tty_npushed;
     if (kdebugflag & 4) {
        i = PPPDBG_LOG + PPPDBG_AHDLC;
        strioctl(pppfd, PPPIO_DEBUG, &i, sizeof(int), 0);
     }
     if (ioctl(fd, I_PUSH, "ppp_comp") < 0)
        error("Couldn't push PPP compression module: %m");
+    else
+       ++tty_npushed;
     if (kdebugflag & 2) {
        i = PPPDBG_LOG + PPPDBG_COMP;
        strioctl(pppfd, PPPIO_DEBUG, &i, sizeof(int), 0);
     }
 
     /* Link the serial port under the PPP multiplexor. */
-    if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0)
-       fatal("Can't link tty to PPP mux: %m");
+    if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0) {
+       error("Can't link tty to PPP mux: %m");
+       return -1;
+    }
 
     return pppfd;
 }
@@ -322,8 +332,8 @@ disestablish_ppp(fd)
        fdmuxid = -1;
 
        if (!hungup) {
-           while (ioctl(fd, I_POP, 0) >= 0)
-               ;
+           while (tty_npushed > 0 && ioctl(fd, I_POP, 0) >= 0)
+               --tty_npushed;
            for (i = tty_nmodules - 1; i >= 0; --i)
                if (ioctl(fd, I_PUSH, tty_modules[i]) < 0)
                    error("Couldn't restore tty module %s: %m",
@@ -938,12 +948,16 @@ get_idle_time(u, ip)
 int
 get_ppp_stats(u, stats)
     int u;
-    struct ppp_stats *stats;
+    struct pppd_stats *stats;
 {
-    if (strioctl(pppfd, PPPIO_GETSTAT, stats, 0, sizeof(*stats)) < 0) {
+    struct ppp_stats s;
+
+    if (strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof(s)) < 0) {
        error("Couldn't get link statistics: %m");
        return 0;
     }
+    stats->bytes_in = s.p.ppp_ibytes;
+    stats->bytes_out = s.p.ppp_obytes;
     return 1;
 }
 
@@ -1852,3 +1866,54 @@ have_route_to(addr)
     close(fd);
     return 0;
 }
+
+/*
+ * get_pty - get a pty master/slave pair and chown the slave side to
+ * the uid given.  Assumes slave_name points to MAXPATHLEN bytes of space.
+ */
+int
+get_pty(master_fdp, slave_fdp, slave_name, uid)
+    int *master_fdp;
+    int *slave_fdp;
+    char *slave_name;
+    int uid;
+{
+    int mfd, sfd;
+    char *pty_name;
+    struct termios tios;
+
+    mfd = open("/dev/ptmx", O_RDWR);
+    if (mfd < 0) {
+       error("Couldn't open pty master: %m");
+       return 0;
+    }
+
+    pty_name = ptsname(mfd);
+    if (pty_name == NULL) {
+       error("Couldn't get name of pty slave");
+       close(mfd);
+       return 0;
+    }
+    if (chown(pty_name, uid, -1) < 0)
+       warn("Couldn't change owner of pty slave: %m");
+    if (chmod(pty_name, S_IRUSR | S_IWUSR) < 0)
+       warn("Couldn't change permissions on pty slave: %m");
+    if (unlockpt(mfd) < 0)
+       warn("Couldn't unlock pty slave: %m");
+
+    sfd = open(pty_name, O_RDWR);
+    if (sfd < 0) {
+       error("Couldn't open pty slave %s: %m", pty_name);
+       close(mfd);
+       return 0;
+    }
+    if (ioctl(sfd, I_PUSH, "ptem") < 0)
+       warn("Couldn't push ptem module on pty slave: %m");
+
+    dbglog("Using %s", pty_name);
+    strlcpy(slave_name, pty_name, MAXPATHLEN);
+    *master_fdp = mfd;
+    *slave_fdp = sfd;
+
+    return 1;
+}
index 82783be2095474dc89337f33e078bcd093d183dc..f004ba62b556fc5e3ad7aba77ec2e4d0abd31109 100644 (file)
@@ -21,7 +21,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: sys-ultrix.c,v 1.29 1999/03/19 04:23:54 paulus Exp $";
+static char rcsid[] = "$Id: sys-ultrix.c,v 1.30 1999/03/22 05:55:40 paulus Exp $";
 #endif
 
 /*
@@ -801,7 +801,7 @@ get_idle_time(u, ip)
 int
 get_ppp_stats(u, stats)
     int u;
-    struct ppp_stats *stats;
+    struct pppd_stats *stats;
 {
     struct ifpppstatsreq req;
 
@@ -811,7 +811,8 @@ get_ppp_stats(u, stats)
        error("Couldn't get PPP statistics: %m");
        return 0;
     }
-    *stats = req.stats;
+    stats->bytes_in = req.stats.p.ppp_ibytes;
+    stats->bytes_out = req.stats.p.ppp_obytes;
     return 1;
 }