/*
* tty.c - code for handling serial ports in pppd.
*
- * Copyright (C) 2000 Paul Mackerras.
- * All rights reserved.
+ * Copyright (C) 2000-2004 Paul Mackerras. All rights reserved.
*
- * Portions Copyright (c) 1989 Carnegie Mellon University.
- * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
*
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Carnegie Mellon University. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. The name(s) of the authors of this software must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 3. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Paul Mackerras
+ * <paulus@samba.org>".
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Portions derived from main.c, which is:
+ *
+ * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any legal
+ * details, please contact
+ * Office of Technology Transfer
+ * Carnegie Mellon University
+ * 5000 Forbes Avenue
+ * Pittsburgh, PA 15213-3890
+ * (412) 268-4387, fax: (412) 268-7395
+ * tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define RCSID "$Id: tty.c,v 1.2 2000/07/06 11:17:03 paulus Exp $"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <netdb.h>
#include <utmp.h>
#include <pwd.h>
-#include <setjmp.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include "pppd.h"
+#include "pppd-private.h"
+#include "options.h"
#include "fsm.h"
#include "lcp.h"
-static int setxonxoff __P((char **));
-static void finish_tty __P((void));
-static int start_charshunt __P((int, int));
-static void stop_charshunt __P((void *, int));
-static void charshunt_done __P((void *));
-static void charshunt __P((int, int, char *));
-static int record_write __P((FILE *, int code, u_char *buf, int nb,
- struct timeval *));
-static int open_socket __P((char *));
-static void maybe_relock __P((void *, int));
+void tty_process_extra_options(void);
+void tty_check_options(void);
+int connect_tty(void);
+void disconnect_tty(void);
+void tty_close_fds(void);
+void cleanup_tty(void);
+void tty_do_send_config(int, u_int32_t, int, int);
+
+static int setdevname(char *, char **, int);
+static int setspeed(char *, char **, int);
+static int setxonxoff(char **);
+static int setescape(char **);
+static void printescape(struct option *, void (*)(void *, char *,...),void *);
+static void finish_tty(void);
+static int start_charshunt(int, int);
+static void stop_charshunt(void *, int);
+static void charshunt_done(void *);
+static void charshunt(int, int, char *);
+static int record_write(FILE *, int code, u_char *buf, int nb,
+ struct timeval *);
+static int open_socket(char *);
+static void maybe_relock(void *, int);
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) */
static int ttyfd; /* Serial port file descriptor */
+static char speed_str[16]; /* Serial port speed as string */
mode_t tty_mode = (mode_t)-1; /* Original access permissions to tty */
int baud_rate; /* Actual bits/second for serial device */
struct stat devstat; /* result of stat() on devnam */
/* option variables */
+char devnam[MAXPATHLEN]; /* Device name */
+char ppp_devname[MAXPATHLEN];/* name of PPP tty (maybe ttypx) */
int crtscts = 0; /* Use hardware flow control */
+int stop_bits = 1; /* Number of serial port stop bits */
bool modem = 1; /* Use modem control lines */
int inspeed = 0; /* Input/Output speed requested */
bool lockflag = 0; /* Create lock file to lock the serial dev */
extern uid_t uid;
extern int kill_link;
+extern int asked_to_quit;
+extern int got_sigterm;
/* XXX */
extern int privopen; /* don't lock, open device as root */
+u_int32_t xmit_accm[8]; /* extended transmit ACCM */
+
/* option descriptors */
-option_t tty_options[] = {
+static struct option 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 | OPT_A2STRVAL | OPT_STATIC,
+ devnam},
+
+ { "tty speed", o_wild, (void *) &setspeed,
+ "Baud rate for serial port",
+ OPT_PRIO | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC, speed_str },
+
{ "lock", o_bool, &lockflag,
- "Lock serial device with UUCP-style lock file", 1 },
+ "Lock serial device with UUCP-style lock file", OPT_PRIO | 1 },
{ "nolock", o_bool, &lockflag,
- "Don't lock serial device", OPT_PRIV },
+ "Don't lock serial device", OPT_PRIOSUB | 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_PRIO | 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_PRIO | 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_PRIO | OPT_PRIVFIX },
+
{ "welcome", o_string, &welcomer,
- "Script to welcome client",
- OPT_A2INFO | OPT_PRIVFIX, &welcomer_info },
+ "Script to welcome client", OPT_PRIO | OPT_PRIVFIX },
+
{ "pty", o_string, &ptycommand,
"Script to run on pseudo-tty master side",
- OPT_A2INFO | OPT_PRIVFIX | OPT_DEVNAM, &ptycommand_info },
+ OPT_PRIO | OPT_PRIVFIX | OPT_DEVNAM },
+
{ "notty", o_bool, ¬ty,
"Input/output is not a tty", OPT_DEVNAM | 1 },
+
{ "socket", o_string, &pty_socket,
- "Send and receive over socket, arg is host:port", OPT_DEVNAM },
+ "Send and receive over socket, arg is host:port",
+ OPT_PRIO | OPT_DEVNAM },
+
{ "record", o_string, &record_file,
- "Record characters sent/received to file" },
+ "Record characters sent/received to file", OPT_PRIO },
+
{ "crtscts", o_int, &crtscts,
- "Set hardware (RTS/CTS) flow control", OPT_NOARG|OPT_VAL(1) },
+ "Set hardware (RTS/CTS) flow control",
+ OPT_PRIO | OPT_NOARG | OPT_VAL(1) },
+ { "cdtrcts", o_int, &crtscts,
+ "Set alternate hardware (DTR/CTS) flow control",
+ OPT_PRIOSUB | OPT_NOARG | OPT_VAL(2) },
{ "nocrtscts", o_int, &crtscts,
- "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
+ "Disable hardware flow control",
+ OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) },
{ "-crtscts", o_int, &crtscts,
- "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
- { "cdtrcts", o_int, &crtscts,
- "Set alternate hardware (DTR/CTS) flow control", OPT_NOARG|OPT_VAL(2) },
+ "Disable hardware flow control",
+ OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
{ "nocdtrcts", o_int, &crtscts,
- "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
+ "Disable hardware flow control",
+ OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
{ "xonxoff", o_special_noarg, (void *)setxonxoff,
- "Set software (XON/XOFF) flow control" },
+ "Set software (XON/XOFF) flow control", OPT_PRIOSUB },
+ { "stop-bits", o_int, &stop_bits,
+ "Number of stop bits in serial port",
+ OPT_PRIO | OPT_PRIVFIX | OPT_LIMITS, NULL, 2, 1 },
+
{ "modem", o_bool, &modem,
- "Use modem control lines", 1 },
+ "Use modem control lines", OPT_PRIO | 1 },
{ "local", o_bool, &modem,
- "Don't use modem control lines" },
+ "Don't use modem control lines", OPT_PRIOSUB | 0 },
+
{ "sync", o_bool, &sync_serial,
"Use synchronous HDLC serial encoding", 1 },
+
{ "datarate", o_int, &max_data_rate,
- "Maximum data rate in bytes/sec (with pty, notty or record option)" },
+ "Maximum data rate in bytes/sec (with pty, notty or record option)",
+ OPT_PRIO },
+
+ { "escape", o_special, (void *)setescape,
+ "List of character codes to escape on transmission",
+ OPT_A2PRINTER, (void *)printescape },
+
{ NULL }
};
+
+struct channel tty_channel = {
+ tty_options,
+ &tty_process_extra_options,
+ &tty_check_options,
+ &connect_tty,
+ &disconnect_tty,
+ &tty_establish_ppp,
+ &tty_disestablish_ppp,
+ &tty_do_send_config,
+ &tty_recv_config,
+ &cleanup_tty,
+ &tty_close_fds
+};
+
+bool
+ppp_sync_serial()
+{
+ return sync_serial;
+}
+
+bool
+ppp_get_modem()
+{
+ return modem;
+}
+
+void
+ppp_set_modem(bool on)
+{
+ modem = on;
+}
+
+bool
+ppp_using_pty()
+{
+ return using_pty;
+}
+
+int
+ppp_set_pppdevnam(const char *name)
+{
+ if (name) {
+ return strlcpy(ppp_devname, name, sizeof(ppp_devname));
+ }
+ return -1;
+}
+
+const char *
+ppp_pppdevnam()
+{
+ return ppp_devname;
+}
+
+const char *
+ppp_devnam()
+{
+ return devnam;
+}
+
+int
+ppp_set_devnam(const char *name)
+{
+ if (name) {
+ return strlcpy(devnam, name, sizeof(devnam));
+ }
+ return -1;
+}
+
+
+/*
+ * 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(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;
+ slprintf(speed_str, sizeof(speed_str), "%d", 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(char *cp, char **argv, int doit)
+{
+ struct stat statbuf;
+ char dev[MAXPATHLEN];
+
+ if (*cp == 0)
+ return 0;
+
+ if (*cp != '/') {
+ 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;
+ ppp_option_error("Couldn't stat %s: %m", cp);
+ return 0;
+ }
+ if (!S_ISCHR(statbuf.st_mode)) {
+ if (doit)
+ ppp_option_error("%s is not a character device", cp);
+ return 0;
+ }
+
+ if (doit) {
+ strlcpy(devnam, cp, MAXPATHLEN);
+ devstat = statbuf;
+ default_device = 0;
+ }
+
+ return 1;
+}
+
static int
-setxonxoff(argv)
- char **argv;
+setxonxoff(char **argv)
{
lcp_wantoptions[0].asyncmap |= 0x000A0000; /* escape ^S and ^Q */
lcp_wantoptions[0].neg_asyncmap = 1;
return 1;
}
+/*
+ * setescape - add chars to the set we escape on transmission.
+ */
+static int
+setescape(char **argv)
+{
+ int n, ret;
+ char *p, *endp;
+
+ p = *argv;
+ ret = 1;
+ while (*p) {
+ n = strtol(p, &endp, 16);
+ if (p == endp) {
+ ppp_option_error("escape parameter contains invalid hex number '%s'",
+ p);
+ return 0;
+ }
+ p = endp;
+ if (n < 0 || n == 0x5E || n > 0xFF) {
+ ppp_option_error("can't escape character 0x%x", n);
+ ret = 0;
+ } else
+ xmit_accm[n >> 5] |= 1U << (n & 0x1F);
+ while (*p == ',' || *p == ' ')
+ ++p;
+ }
+ lcp_allowoptions[0].asyncmap = xmit_accm[0];
+ return ret;
+}
+
+static void
+printescape(struct option *opt, void (*printer)(void *, char *, ...), void *arg)
+{
+ int n;
+ int first = 1;
+
+ for (n = 0; n < 256; ++n) {
+ if (n == 0x7d)
+ n += 2; /* skip 7d, 7e */
+ if (xmit_accm[n >> 5] & (1U << (n & 0x1f))) {
+ if (!first)
+ printer(arg, ",");
+ else
+ first = 0;
+ printer(arg, "%x", n);
+ }
+ }
+ if (first)
+ printer(arg, "oops # nothing escaped");
+}
+
/*
* tty_init - do various tty-related initializations.
*/
-void tty_init()
+void tty_init(void)
{
- add_notifier(&pidchange, maybe_relock, 0);
- add_options(tty_options);
+ ppp_add_notify(NF_PID_CHANGE, maybe_relock, 0);
+ the_channel = &tty_channel;
+ xmit_accm[3] = 0x60000000U;
}
/*
- * tty_device_check - work out which tty device we are using
+ * tty_process_extra_options - work out which tty device we are using
* and read its options file.
*/
-void tty_device_check()
+void tty_process_extra_options(void)
{
using_pty = notty || ptycommand != NULL || pty_socket != NULL;
if (using_pty)
if (default_device) {
char *p;
if (!isatty(0) || (p = ttyname(0)) == NULL) {
- option_error("no device specified and stdin is not a tty");
+ ppp_option_error("no device specified and stdin is not a tty");
exit(EXIT_OPTION_ERROR);
}
- strlcpy(devnam, p, sizeof(devnam));
+ strlcpy(devnam, p, MAXPATHLEN);
if (stat(devnam, &devstat) < 0)
fatal("Couldn't stat default device %s: %m", devnam);
}
* tty_check_options - do consistency checks on the options we were given.
*/
void
-tty_check_options()
+tty_check_options(void)
{
struct stat statbuf;
int fdflags;
- if (demand && connect_script == 0) {
- option_error("connect script is required for demand-dialling\n");
+ if (demand && notty) {
+ ppp_option_error("demand-dialling is incompatible with notty");
+ exit(EXIT_OPTION_ERROR);
+ }
+ if (demand && connect_script == 0 && ptycommand == NULL
+ && pty_socket == NULL) {
+ ppp_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 (using_pty) {
if (!default_device) {
- option_error("%s option precludes specifying device name",
- notty? "notty": "pty");
+ ppp_option_error("%s option precludes specifying device name",
+ pty_socket? "socket": notty? "notty": "pty");
exit(EXIT_OPTION_ERROR);
}
if (ptycommand != NULL && notty) {
- option_error("pty option is incompatible with notty option");
+ ppp_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");
+ ppp_option_error("socket option is incompatible with pty and notty");
exit(EXIT_OPTION_ERROR);
}
default_device = notty;
* That is, open the serial port, set its speed and mode, and run
* the connector and/or welcomer.
*/
-int connect_tty()
+int connect_tty(void)
{
char *connector;
int fdflags;
+#ifndef __linux__
struct stat statbuf;
+#endif
char numbuf[16];
/*
* Get a pty master/slave pair if the pty, notty, socket,
* or record options were specified.
*/
- strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
+ strlcpy(ppp_devname, devnam, MAXPATHLEN);
pty_master = -1;
pty_slave = -1;
real_ttyfd = -1;
if (using_pty || record_file != NULL) {
- if (!get_pty(&pty_master, &pty_slave, ppp_devnam, uid)) {
+ if (!get_pty(&pty_master, &pty_slave, ppp_devname, uid)) {
error("Couldn't allocate pseudo-tty");
- status = EXIT_FATAL_ERROR;
+ ppp_set_status(EXIT_FATAL_ERROR);
return -1;
}
set_up_tty(pty_slave, 1);
/*
* Lock the device if we've been asked to.
*/
- status = EXIT_LOCK_FAILED;
+ ppp_set_status(EXIT_LOCK_FAILED);
if (lockflag && !privopen) {
if (lock(devnam) < 0)
- return -1;
+ goto errret;
locked = 1;
}
* out and we want to use the modem lines, we reopen it later
* in order to wait for the carrier detect signal from the modem.
*/
- hungup = 0;
- kill_link = 0;
+ got_sigterm = 0;
connector = doing_callback? callback_script: connect_script;
if (devnam[0] != 0) {
for (;;) {
/* If the user specified the device name, become the
user before opening it. */
- int err;
- if (!devnam_info.priv && !privopen)
- seteuid(uid);
- ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
+ int err, prio;
+
+ prio = privopen? OPRIO_ROOT: tty_options[0].priority;
+ if (prio < OPRIO_ROOT && seteuid(uid) == -1) {
+ error("Unable to drop privileges before opening %s: %m\n",
+ devnam);
+ ppp_set_status(EXIT_OPEN_FAILED);
+ goto errret;
+ }
+ real_ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
err = errno;
- if (!devnam_info.priv && !privopen)
- seteuid(0);
- if (ttyfd >= 0)
+ if (prio < OPRIO_ROOT && seteuid(0) == -1)
+ fatal("Unable to regain privileges");
+ if (real_ttyfd >= 0)
break;
errno = err;
if (err != EINTR) {
error("Failed to open %s: %m", devnam);
- status = EXIT_OPEN_FAILED;
+ ppp_set_status(EXIT_OPEN_FAILED);
}
if (!persist || err != EINTR)
- return -1;
+ goto errret;
}
+ ttyfd = real_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");
+#ifndef __linux__
+ /*
+ * Linux 2.4 and above blocks normal writes to the tty
+ * when it is in PPP line discipline, so this isn't needed.
+ */
/*
* Do the equivalent of `mesg n' to stop broadcast messages.
*/
warn("Couldn't restrict write permissions to %s: %m", devnam);
} else
tty_mode = statbuf.st_mode;
+#endif /* __linux__ */
/*
* Set line speed, flow control, etc.
*/
set_up_tty(ttyfd, ((connector != NULL && connector[0] != 0)
|| initializer != NULL));
- real_ttyfd = ttyfd;
}
/*
* If the pty, socket, notty and/or record option was specified,
* start up the character shunt now.
*/
- status = EXIT_PTYCMD_FAILED;
+ ppp_set_status(EXIT_PTYCMD_FAILED);
if (ptycommand != NULL) {
if (record_file != NULL) {
int ipipe[2], opipe[2], ok;
if (pipe(ipipe) < 0 || pipe(opipe) < 0)
fatal("Couldn't create pipes for record option: %m");
+
+ /* don't leak these to the ptycommand */
+ (void) fcntl(ipipe[0], F_SETFD, FD_CLOEXEC);
+ (void) fcntl(opipe[1], F_SETFD, FD_CLOEXEC);
+
ok = device_script(ptycommand, opipe[0], ipipe[1], 1) == 0
&& start_charshunt(ipipe[0], opipe[1]);
close(ipipe[0]);
close(opipe[0]);
close(opipe[1]);
if (!ok)
- return -1;
+ goto errret;
} else {
if (device_script(ptycommand, pty_master, pty_master, 1) < 0)
- return -1;
- ttyfd = pty_slave;
- close(pty_master);
- pty_master = -1;
+ goto errret;
}
} else if (pty_socket != NULL) {
int fd = open_socket(pty_socket);
if (fd < 0)
- return -1;
+ goto errret;
if (!start_charshunt(fd, fd))
- return -1;
+ goto errret;
+ close(fd);
} else if (notty) {
if (!start_charshunt(0, 1))
- return -1;
+ goto errret;
+ dup2(fd_devnull, 0);
+ dup2(fd_devnull, 1);
+ if (log_to_fd == 1)
+ log_to_fd = -1;
+ if (log_to_fd != 2)
+ dup2(fd_devnull, 2);
} else if (record_file != NULL) {
- if (!start_charshunt(ttyfd, ttyfd))
- return -1;
+ int fd = dup(ttyfd);
+ if (!start_charshunt(fd, fd))
+ goto errret;
+ }
+
+ if (using_pty || record_file != NULL) {
+ ttyfd = pty_slave;
+ close(pty_master);
+ pty_master = -1;
}
/* run connection script */
if (initializer && initializer[0]) {
if (device_script(initializer, ttyfd, ttyfd, 0) < 0) {
error("Initializer script failed");
- status = EXIT_INIT_FAILED;
- return -1;
+ ppp_set_status(EXIT_INIT_FAILED);
+ goto errretf;
}
- if (kill_link) {
+ if (got_sigterm) {
disconnect_tty();
- return -1;
+ goto errretf;
}
info("Serial port initialized.");
}
if (connector && connector[0]) {
if (device_script(connector, ttyfd, ttyfd, 0) < 0) {
error("Connect script failed");
- status = EXIT_CONNECT_FAILED;
- return -1;
+ ppp_set_status(EXIT_CONNECT_FAILED);
+ goto errretf;
}
- if (kill_link) {
+ if (got_sigterm) {
disconnect_tty();
- return -1;
+ goto errretf;
}
info("Serial connection established.");
}
break;
if (errno != EINTR) {
error("Failed to reopen %s: %m", devnam);
- status = EXIT_OPEN_FAILED;
+ ppp_set_status(EXIT_OPEN_FAILED);
}
- if (!persist || errno != EINTR || hungup || kill_link)
- return -1;
+ if (!persist || errno != EINTR || hungup || got_sigterm)
+ goto errret;
}
close(i);
}
slprintf(numbuf, sizeof(numbuf), "%d", baud_rate);
- script_setenv("SPEED", numbuf, 0);
+ ppp_script_setenv("SPEED", numbuf, 0);
/* run welcome script, if any */
if (welcomer && welcomer[0]) {
warn("Welcome script failed");
}
- if (connector != NULL || ptycommand != NULL)
+ /*
+ * 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 || pty_socket != NULL)
listen_time = connect_delay;
return ttyfd;
+
+ errretf:
+ if (real_ttyfd >= 0)
+ tcflush(real_ttyfd, TCIOFLUSH);
+ errret:
+ if (pty_master >= 0) {
+ close(pty_master);
+ pty_master = -1;
+ }
+ ttyfd = -1;
+ if (got_sigterm)
+ asked_to_quit = 1;
+ return -1;
}
-void disconnect_tty()
+void disconnect_tty(void)
{
if (disconnect_script == NULL || hungup)
return;
} else {
info("Serial link disconnected.");
}
+ stop_charshunt(NULL, 0);
}
-void tty_close_fds()
+void tty_close_fds(void)
{
- if (pty_master >= 0)
- close(pty_master);
if (pty_slave >= 0)
close(pty_slave);
if (real_ttyfd >= 0) {
/* N.B. ttyfd will == either pty_slave or real_ttyfd */
}
-void cleanup_tty()
+void cleanup_tty(void)
{
if (real_ttyfd >= 0)
finish_tty();
}
}
+/*
+ * tty_do_send_config - set transmit-side PPP configuration.
+ * We set the extended transmit ACCM here as well.
+ */
+void
+tty_do_send_config(int mtu, u_int32_t accm, int pcomp, int accomp)
+{
+ tty_set_xaccm(xmit_accm);
+ tty_send_config(mtu, accm, pcomp, accomp);
+}
+
/*
* finish_tty - restore the terminal device to its original settings
*/
static void
-finish_tty()
+finish_tty(void)
{
/* drop dtr to hang up */
if (!default_device && modem) {
restore_tty(real_ttyfd);
+#ifndef __linux__
if (tty_mode != (mode_t) -1) {
- if (fchmod(real_ttyfd, tty_mode) != 0) {
- /* XXX if devnam is a symlink, this will change the link */
- chmod(devnam, tty_mode);
- }
+ if (fchmod(real_ttyfd, tty_mode) != 0)
+ error("Couldn't restore tty permissions");
}
+#endif /* __linux__ */
close(real_ttyfd);
real_ttyfd = -1;
* maybe_relock - our PID has changed, maybe update the lock file.
*/
static void
-maybe_relock(arg, pid)
- void *arg;
- int pid;
+maybe_relock(void *arg, int pid)
{
if (locked)
relock(pid);
* host and port.
*/
static int
-open_socket(dest)
- char *dest;
+open_socket(char *dest)
{
char *sep, *endp = NULL;
int sock, port = -1;
* start_charshunt - create a child process to run the character shunt.
*/
static int
-start_charshunt(ifd, ofd)
- int ifd, ofd;
+start_charshunt(int ifd, int ofd)
{
- int cpid;
+ int cpid, ret;
- cpid = fork();
+ cpid = ppp_safe_fork(ifd, ofd, (log_to_fd >= 0? log_to_fd: 2));
if (cpid == -1) {
error("Can't fork process for character shunt: %m");
return 0;
}
if (cpid == 0) {
/* child */
- close(pty_slave);
- setuid(uid);
- if (getuid() != uid)
- fatal("setuid failed");
- setgid(getgid());
+ reopen_log();
if (!nodetach)
log_to_fd = -1;
- charshunt(ifd, ofd, record_file);
+ else if (log_to_fd >= 0)
+ log_to_fd = 2;
+ ret = setgid(getgid());
+ if (ret != 0) {
+ fatal("setgid failed, %m");
+ }
+ ret = setuid(uid);
+ if (ret != 0 || getuid() != uid) {
+ fatal("setuid failed, %m");
+ }
+ charshunt(0, 1, record_file);
exit(0);
}
charshunt_pid = cpid;
- add_notifier(&sigreceived, stop_charshunt, 0);
- close(pty_master);
- pty_master = -1;
- ttyfd = pty_slave;
- record_child(cpid, "pppd (charshunt)", charshunt_done, NULL);
+ record_child(cpid, "pppd (charshunt)", charshunt_done, NULL, 1);
return 1;
}
static void
-charshunt_done(arg)
- void *arg;
+charshunt_done(void *arg)
{
charshunt_pid = 0;
}
static void
-stop_charshunt(arg, sig)
- void *arg;
- int sig;
+stop_charshunt(void *arg, int sig)
{
if (charshunt_pid)
kill(charshunt_pid, (sig == SIGINT? sig: SIGTERM));
* (We assume ofd >= ifd which is true the way this gets called. :-).
*/
static void
-charshunt(ifd, ofd, record_file)
- int ifd, ofd;
- char *record_file;
+charshunt(int ifd, int ofd, char *record_file)
{
int n, nfds;
fd_set ready, writey;
signal(SIGXFSZ, SIG_DFL);
#endif
+ /*
+ * Check that the fds won't overrun the fd_sets
+ */
+ if (ifd >= FD_SETSIZE || ofd >= FD_SETSIZE || pty_master >= FD_SETSIZE)
+ fatal("internal error: file descriptor too large (%d, %d, %d)",
+ ifd, ofd, pty_master);
+
/*
* Open the record file if required.
*/
pty_readable = stdin_readable = 1;
ilevel = olevel = 0;
- gettimeofday(&levelt, NULL);
+ ppp_get_time(&levelt);
if (max_data_rate) {
max_level = max_data_rate / 10;
if (max_level < 100)
int nbt;
struct timeval now;
- gettimeofday(&now, NULL);
+ ppp_get_time(&now);
dt = (now.tv_sec - levelt.tv_sec
+ (now.tv_usec - levelt.tv_usec) / 1e6);
nbt = (int)(dt * max_data_rate);
} 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;
if (!record_write(recordf, 1, obufp, nobuf, &lasttime))
recordf = NULL;
}
- }
+ } else if (!stdin_readable)
+ pty_readable = 0;
if (FD_ISSET(ofd, &writey)) {
n = nobuf;
if (olevel + n > max_level)
}
static int
-record_write(f, code, buf, nb, tp)
- FILE *f;
- int code;
- u_char *buf;
- int nb;
- struct timeval *tp;
+record_write(FILE *f, int code, u_char *buf, int nb, struct timeval *tp)
{
struct timeval now;
int diff;