X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Ftty.c;h=b7e61650d48357f692d3353a77ea2db71ef7fcee;hb=f7ee87797ae1851c7bfb57752185b66f127326e8;hp=3e02e27dd16ab2147b9d3a405a5902625d49b27c;hpb=52a17b6d41d64d0502a73e5b4224546360581b49;p=ppp.git diff --git a/pppd/tty.c b/pppd/tty.c index 3e02e27..b7e6165 100644 --- a/pppd/tty.c +++ b/pppd/tty.c @@ -20,7 +20,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#define RCSID "$Id: tty.c,v 1.1 2000/06/30 04:54:23 paulus Exp $" +#define RCSID "$Id: tty.c,v 1.4 2001/02/22 03:15:21 paulus Exp $" #include #include @@ -49,6 +49,8 @@ #include "fsm.h" #include "lcp.h" +static int setdevname __P((char *, char **, int)); +static int setspeed __P((char *, char **, int)); static int setxonxoff __P((char **)); static void finish_tty __P((void)); static int start_charshunt __P((int, int)); @@ -70,6 +72,7 @@ int baud_rate; /* Actual bits/second for serial device */ char *callback_script; /* script for doing callback */ int charshunt_pid; /* Process ID for charshunt */ int locked; /* lock() has succeeded */ +struct stat devstat; /* result of stat() on devnam */ /* option variables */ int crtscts = 0; /* Use hardware flow control */ @@ -86,7 +89,7 @@ char *record_file = NULL; /* File to record chars sent/received */ int max_data_rate; /* max bytes/sec through charshunt */ bool sync_serial = 0; /* Device is synchronous serial device */ char *pty_socket = NULL; /* Socket to connect to pty */ -int using_pty = 0; +int using_pty = 0; /* we're allocating a pty as the device */ extern uid_t uid; extern int kill_link; @@ -96,25 +99,25 @@ extern int privopen; /* don't lock, open device as root */ /* option descriptors */ option_t tty_options[] = { + /* device name must be first, or change connect_tty() below! */ + { "device name", o_wild, (void *) &setdevname, + "Serial port device name", OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG }, + { "tty speed", o_wild, (void *) &setspeed, + "Baud rate for serial port", OPT_NOARG }, { "lock", o_bool, &lockflag, "Lock serial device with UUCP-style lock file", 1 }, { "nolock", o_bool, &lockflag, "Don't lock serial device", OPT_PRIV }, { "init", o_string, &initializer, - "A program to initialize the device", - OPT_A2INFO | OPT_PRIVFIX, &initializer_info }, + "A program to initialize the device", OPT_PRIVFIX }, { "connect", o_string, &connect_script, - "A program to set up a connection", - OPT_A2INFO | OPT_PRIVFIX, &connect_script_info }, + "A program to set up a connection", OPT_PRIVFIX }, { "disconnect", o_string, &disconnect_script, - "Program to disconnect serial device", - OPT_A2INFO | OPT_PRIVFIX, &disconnect_script_info }, + "Program to disconnect serial device", OPT_PRIVFIX }, { "welcome", o_string, &welcomer, - "Script to welcome client", - OPT_A2INFO | OPT_PRIVFIX, &welcomer_info }, + "Script to welcome client", OPT_PRIVFIX }, { "pty", o_string, &ptycommand, - "Script to run on pseudo-tty master side", - OPT_A2INFO | OPT_PRIVFIX | OPT_DEVNAM, &ptycommand_info }, + "Script to run on pseudo-tty master side", OPT_PRIVFIX | OPT_DEVNAM }, { "notty", o_bool, ¬ty, "Input/output is not a tty", OPT_DEVNAM | 1 }, { "socket", o_string, &pty_socket, @@ -144,6 +147,77 @@ option_t tty_options[] = { { NULL } }; + +/* + * setspeed - Set the serial port baud rate. + * If doit is 0, the call is to check whether this option is + * potentially a speed value. + */ +static int +setspeed(arg, argv, doit) + char *arg; + char **argv; + int doit; +{ + char *ptr; + int spd; + + spd = strtol(arg, &ptr, 0); + if (ptr == arg || *ptr != 0 || spd == 0) + return 0; + if (doit) + inspeed = spd; + return 1; +} + + +/* + * setdevname - Set the device name. + * If doit is 0, the call is to check whether this option is + * potentially a device name. + */ +static int +setdevname(cp, argv, doit) + char *cp; + char **argv; + int doit; +{ + struct stat statbuf; + char dev[MAXPATHLEN]; + + if (*cp == 0) + return 0; + + if (strncmp("/dev/", cp, 5) != 0) { + strlcpy(dev, "/dev/", sizeof(dev)); + strlcat(dev, cp, sizeof(dev)); + cp = dev; + } + + /* + * Check if there is a character device by this name. + */ + if (stat(cp, &statbuf) < 0) { + if (!doit) + return errno != ENOENT; + option_error("Couldn't stat %s: %m", cp); + return 0; + } + if (!S_ISCHR(statbuf.st_mode)) { + if (doit) + option_error("%s is not a character device", cp); + return 0; + } + + if (doit) { + strlcpy(devnam, cp, sizeof(devnam)); + devstat = statbuf; + default_device = 0; + } + + return 1; +} + static int setxonxoff(argv) char **argv; @@ -164,6 +238,102 @@ void tty_init() add_options(tty_options); } +/* + * tty_device_check - work out which tty device we are using + * and read its options file. + */ +void tty_device_check() +{ + using_pty = notty || ptycommand != NULL || pty_socket != NULL; + if (using_pty) + return; + if (default_device) { + char *p; + if (!isatty(0) || (p = ttyname(0)) == NULL) { + option_error("no device specified and stdin is not a tty"); + exit(EXIT_OPTION_ERROR); + } + strlcpy(devnam, p, sizeof(devnam)); + if (stat(devnam, &devstat) < 0) + fatal("Couldn't stat default device %s: %m", devnam); + } + + + /* + * Parse the tty options file. + * The per-tty options file should not change + * ptycommand, pty_socket, notty or devnam. + * options_for_tty doesn't override options set on the command line, + * except for some privileged options. + */ + if (!options_for_tty()) + exit(EXIT_OPTION_ERROR); +} + +/* + * tty_check_options - do consistency checks on the options we were given. + */ +void +tty_check_options() +{ + struct stat statbuf; + int fdflags; + + if (demand && connect_script == 0) { + option_error("connect script is required for demand-dialling\n"); + exit(EXIT_OPTION_ERROR); + } + /* default holdoff to 0 if no connect script has been given */ + if (connect_script == 0 && !holdoff_specified) + holdoff = 0; + + if (using_pty) { + if (!default_device) { + option_error("%s option precludes specifying device name", + notty? "notty": "pty"); + exit(EXIT_OPTION_ERROR); + } + if (ptycommand != NULL && notty) { + option_error("pty option is incompatible with notty option"); + exit(EXIT_OPTION_ERROR); + } + if (pty_socket != NULL && (ptycommand != NULL || notty)) { + option_error("socket option is incompatible with pty and notty"); + exit(EXIT_OPTION_ERROR); + } + default_device = notty; + lockflag = 0; + modem = 0; + if (notty && log_to_fd <= 1) + log_to_fd = -1; + } else { + /* + * If the user has specified a device which is the same as + * the one on stdin, pretend they didn't specify any. + * If the device is already open read/write on stdin, + * we assume we don't need to lock it, and we can open it + * as root. + */ + if (fstat(0, &statbuf) >= 0 && S_ISCHR(statbuf.st_mode) + && statbuf.st_rdev == devstat.st_rdev) { + default_device = 1; + fdflags = fcntl(0, F_GETFL); + if (fdflags != -1 && (fdflags & O_ACCMODE) == O_RDWR) + privopen = 1; + } + } + if (default_device) + nodetach = 1; + + /* + * Don't send log messages to the serial port, it tends to + * confuse the peer. :-) + */ + if (log_to_fd >= 0 && fstat(log_to_fd, &statbuf) >= 0 + && S_ISCHR(statbuf.st_mode) && statbuf.st_rdev == devstat.st_rdev) + log_to_fd = -1; +} + /* * connect_tty - get the serial port ready to start doing PPP. * That is, open the serial port, set its speed and mode, and run @@ -217,12 +387,14 @@ int connect_tty() for (;;) { /* If the user specified the device name, become the user before opening it. */ - int err; - if (!devnam_info.priv && !privopen) + int err, prio; + + prio = privopen? OPRIO_ROOT: tty_options[0].priority; + if (prio < OPRIO_ROOT) seteuid(uid); ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0); err = errno; - if (!devnam_info.priv && !privopen) + if (prio < OPRIO_ROOT) seteuid(0); if (ttyfd >= 0) break; @@ -234,6 +406,7 @@ int connect_tty() if (!persist || err != EINTR) return -1; } + real_ttyfd = ttyfd; 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"); @@ -259,7 +432,6 @@ int connect_tty() */ set_up_tty(ttyfd, ((connector != NULL && connector[0] != 0) || initializer != NULL)); - real_ttyfd = ttyfd; } /* @@ -373,6 +545,14 @@ int connect_tty() warn("Welcome script failed"); } + /* + * 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) + listen_time = connect_delay; + return ttyfd; }