* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#define RCSID "$Id: main.c,v 1.86 1999/09/11 12:08:57 paulus Exp $"
+#define RCSID "$Id: main.c,v 1.94 2000/04/15 01:27:13 masputra Exp $"
#include <stdio.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#include "pppd.h"
#include "magic.h"
#include "ccp.h"
#include "pathnames.h"
#include "patchlevel.h"
+#include "tdb.h"
#ifdef CBCP_SUPPORT
#include "cbcp.h"
static int conn_running; /* we have a [dis]connector running */
int ttyfd; /* Serial port file descriptor */
-mode_t tty_mode = -1; /* Original access permissions to tty */
+mode_t tty_mode = (mode_t)-1; /* Original access permissions to tty */
int baud_rate; /* Actual bits/second for serial device */
int hungup; /* terminal has been hung up */
int privileged; /* we're running as real uid root */
int devnam_fixed; /* set while in options.ttyxx file */
volatile int status; /* exit status for pppd */
int unsuccess; /* # unsuccessful connection attempts */
+int do_callback; /* != 0 if we should do callback next */
+int doing_callback; /* != 0 if we are doing callback */
+char *callback_script; /* script for doing callback */
+TDB_CONTEXT *pppdb; /* database for storing status etc. */
+char db_key[32];
+
int (*holdoff_hook) __P((void)) = NULL;
int (*new_phase_hook) __P((int)) = NULL;
/* Prototypes for procedures local to this file. */
+static void setup_signals __P((void));
static void create_pidfile __P((void));
static void create_linkpidfile __P((void));
static void cleanup __P((void));
static int device_script __P((char *, int, int, int));
static int reap_kids __P((int waitfor));
static void record_child __P((int, char *, void (*) (void *), void *));
+static void update_db_entry __P((void));
+static void add_db_key __P((const char *));
+static void delete_db_key __P((const char *));
+static void cleanup_db __P((void));
+static int open_socket __P((char *));
static int start_charshunt __P((int, int));
static void charshunt_done __P((void *));
static void charshunt __P((int, int, char *));
char *argv[];
{
int i, fdflags, t;
- struct sigaction sa;
- char *p;
+ char *p, *connector;
struct passwd *pw;
struct timeval timo;
sigset_t mask;
}
hostname[MAXNAMELEN-1] = 0;
+ /* make sure we don't create world or group writable files. */
+ umask(umask(0777) | 022);
+
uid = getuid();
privileged = uid == 0;
slprintf(numbuf, sizeof(numbuf), "%d", uid);
- script_setenv("ORIG_UID", numbuf);
+ script_setenv("ORIG_UID", numbuf, 0);
ngroups = getgroups(NGROUPS_MAX, groups);
/*
* Work out the device name, if it hasn't already been specified.
*/
- using_pty = notty || ptycommand != NULL;
+ using_pty = notty || ptycommand != NULL || pty_socket != NULL;
if (!using_pty && default_device) {
char *p;
if (!isatty(0) || (p = ttyname(0)) == NULL) {
/*
* Parse the tty options file and the command line.
* The per-tty options file should not change
- * ptycommand, notty or devnam.
+ * ptycommand, pty_socket, notty or devnam.
*/
devnam_fixed = 1;
if (!using_pty) {
if (!sys_check_options())
exit(EXIT_OPTION_ERROR);
auth_check_options();
+#ifdef HAVE_MULTILINK
+ mp_check_options();
+#endif
for (i = 0; (protp = protocols[i]) != NULL; ++i)
if (protp->check_options != NULL)
(*protp->check_options)();
- if (demand && connector == 0) {
+ 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 (connector == 0 && !holdoff_specified)
+ if (connect_script == 0 && !holdoff_specified)
holdoff = 0;
if (using_pty) {
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;
&& S_ISCHR(statbuf.st_mode) && statbuf.st_rdev == devstat.st_rdev)
log_to_fd = -1;
- script_setenv("DEVICE", devnam);
-
/*
* Initialize system-dependent stuff.
*/
if (debug)
setlogmask(LOG_UPTO(LOG_DEBUG));
+ pppdb = tdb_open(_PATH_PPPDB, 0, 0, O_RDWR|O_CREAT, 0644);
+ if (pppdb != NULL) {
+ slprintf(db_key, sizeof(db_key), "pppd%d", getpid());
+ update_db_entry();
+ } else {
+ warn("Warning: couldn't open ppp database %s", _PATH_PPPDB);
+ if (multilink) {
+ warn("Warning: disabling multilink");
+ multilink = 0;
+ }
+ }
+
/*
* Detach ourselves from the terminal, if required,
* and identify who is running us.
}
syslog(LOG_NOTICE, "pppd %s.%d%s started by %s, uid %d",
VERSION, PATCHLEVEL, IMPLEMENTATION, p, uid);
- script_setenv("PPPLOGNAME", p);
+ script_setenv("PPPLOGNAME", p, 0);
- /*
- * Compute mask of all interesting signals and install signal handlers
- * for each. Only one signal handler may be active at a time. Therefore,
- * all other signals should be masked when any handler is executing.
- */
- sigemptyset(&mask);
- sigaddset(&mask, SIGHUP);
- sigaddset(&mask, SIGINT);
- sigaddset(&mask, SIGTERM);
- sigaddset(&mask, SIGCHLD);
- sigaddset(&mask, SIGUSR2);
-
-#define SIGNAL(s, handler) do { \
- sa.sa_handler = handler; \
- if (sigaction(s, &sa, NULL) < 0) \
- fatal("Couldn't establish signal handler (%d): %m", s); \
- } while (0)
-
- sa.sa_mask = mask;
- sa.sa_flags = 0;
- SIGNAL(SIGHUP, hup); /* Hangup */
- SIGNAL(SIGINT, term); /* Interrupt */
- SIGNAL(SIGTERM, term); /* Terminate */
- SIGNAL(SIGCHLD, chld);
-
- SIGNAL(SIGUSR1, toggle_debug); /* Toggle debug flag */
- SIGNAL(SIGUSR2, open_ccp); /* Reopen CCP */
-
- /*
- * Install a handler for other signals which would otherwise
- * cause pppd to exit without cleaning up.
- */
- SIGNAL(SIGABRT, bad_signal);
- SIGNAL(SIGALRM, bad_signal);
- SIGNAL(SIGFPE, bad_signal);
- SIGNAL(SIGILL, bad_signal);
- SIGNAL(SIGPIPE, bad_signal);
- SIGNAL(SIGQUIT, bad_signal);
- SIGNAL(SIGSEGV, bad_signal);
-#ifdef SIGBUS
- SIGNAL(SIGBUS, bad_signal);
-#endif
-#ifdef SIGEMT
- SIGNAL(SIGEMT, bad_signal);
-#endif
-#ifdef SIGPOLL
- SIGNAL(SIGPOLL, bad_signal);
-#endif
-#ifdef SIGPROF
- SIGNAL(SIGPROF, bad_signal);
-#endif
-#ifdef SIGSYS
- SIGNAL(SIGSYS, bad_signal);
-#endif
-#ifdef SIGTRAP
- SIGNAL(SIGTRAP, bad_signal);
-#endif
-#ifdef SIGVTALRM
- SIGNAL(SIGVTALRM, bad_signal);
-#endif
-#ifdef SIGXCPU
- SIGNAL(SIGXCPU, bad_signal);
-#endif
-#ifdef SIGXFSZ
- SIGNAL(SIGXFSZ, bad_signal);
-#endif
+ if (devnam[0])
+ script_setenv("DEVICE", devnam, 1);
+ slprintf(numbuf, sizeof(numbuf), "%d", getpid());
+ script_setenv("PPPD_PID", numbuf, 1);
- /*
- * Apparently we can get a SIGPIPE when we call syslog, if
- * syslogd has died and been restarted. Ignoring it seems
- * be sufficient.
- */
- signal(SIGPIPE, SIG_IGN);
+ setup_signals();
waiting = 0;
/*
* Open the loopback channel and set it up to be the ppp interface.
*/
+ tdb_writelock(pppdb);
fd_loop = open_ppp_loopback();
-
- syslog(LOG_INFO, "Using interface ppp%d", ifunit);
- slprintf(ifname, sizeof(ifname), "ppp%d", ifunit);
- script_setenv("IFNAME", ifname);
-
- create_pidfile(); /* write pid to file */
+ set_ifunit(1);
+ tdb_writeunlock(pppdb);
/*
* Configure the interface and mark it up, etc.
demand_conf();
}
+ do_callback = 0;
for (;;) {
need_holdoff = 1;
real_ttyfd = -1;
status = EXIT_OK;
++unsuccess;
+ doing_callback = do_callback;
+ do_callback = 0;
- if (demand) {
+ if (demand && !doing_callback) {
/*
* Don't do anything until we see some activity.
*/
new_phase(PHASE_SERIALCONN);
/*
- * Get a pty master/slave pair if the pty, notty, or record
- * options were specified.
+ * Get a pty master/slave pair if the pty, notty, socket,
+ * 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 (using_pty || record_file != NULL) {
if (!get_pty(&pty_master, &pty_slave, ppp_devnam, uid)) {
error("Couldn't allocate pseudo-tty");
status = EXIT_FATAL_ERROR;
*/
hungup = 0;
kill_link = 0;
+ connector = doing_callback? callback_script: connect_script;
if (devnam[0] != 0) {
for (;;) {
/* If the user specified the device name, become the
}
/*
- * If the notty and/or record option was specified,
+ * If the pty, socket, notty and/or record option was specified,
* start up the character shunt now.
*/
status = EXIT_PTYCMD_FAILED;
close(pty_master);
pty_master = -1;
}
+ } else if (pty_socket != NULL) {
+ int fd = open_socket(pty_socket);
+ if (fd < 0)
+ goto fail;
+ if (!start_charshunt(fd, fd))
+ goto fail;
} else if (notty) {
if (!start_charshunt(0, 1))
goto fail;
/* run connection script */
if ((connector && connector[0]) || initializer) {
if (real_ttyfd != -1) {
+ /* XXX do this if doing_callback == CALLBACK_DIALIN? */
if (!default_device && modem) {
setdtr(real_ttyfd, 0); /* in case modem is off hook */
sleep(1);
clear CLOCAL if modem option */
if (real_ttyfd != -1)
set_up_tty(real_ttyfd, 0);
+
+ if (doing_callback == CALLBACK_DIALIN)
+ connector = NULL;
}
/* reopen tty if necessary to wait for carrier */
}
slprintf(numbuf, sizeof(numbuf), "%d", baud_rate);
- script_setenv("SPEED", numbuf);
+ script_setenv("SPEED", numbuf, 0);
/* run welcome script, if any */
if (welcomer && welcomer[0]) {
}
/* set up the serial device as a ppp interface */
+ tdb_writelock(pppdb);
fd_ppp = establish_ppp(ttyfd);
if (fd_ppp < 0) {
+ tdb_writeunlock(pppdb);
status = EXIT_FATAL_ERROR;
goto disconnect;
}
- if (!demand) {
-
- info("Using interface ppp%d", ifunit);
- slprintf(ifname, sizeof(ifname), "ppp%d", ifunit);
- script_setenv("IFNAME", ifname);
-
- create_pidfile(); /* write pid to file */
- }
+ if (!demand && ifunit >= 0)
+ set_ifunit(1);
+ tdb_writeunlock(pppdb);
/*
* Start opening the connection and wait for
* 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) {
+ add_fd(fd_ppp);
+ if (connect_delay != 0 && (connector != NULL || ptycommand != NULL)) {
struct timeval t;
- t.tv_sec = 1;
- t.tv_usec = 0;
+ t.tv_sec = connect_delay / 1000;
+ t.tv_usec = connect_delay % 1000;
wait_input(&t);
}
lcp_open(0); /* Start protocol */
open_ccp_flag = 0;
- add_fd(fd_ppp);
status = EXIT_NEGOTIATION_FAILED;
new_phase(PHASE_ESTABLISH);
while (phase != PHASE_DEAD) {
fd_ppp = -1;
if (!hungup)
lcp_lowerdown(0);
+ if (!demand)
+ script_unsetenv("IFNAME");
/*
* Run disconnector script, if requested.
* XXX we may not be able to do this if the line has hung up!
*/
disconnect:
- if (disconnector && !hungup) {
+ if (disconnect_script && !hungup) {
new_phase(PHASE_DISCONNECT);
if (real_ttyfd >= 0)
set_up_tty(real_ttyfd, 1);
- if (device_script(disconnector, ttyfd, ttyfd, 0) < 0) {
+ if (device_script(disconnect_script, ttyfd, ttyfd, 0) < 0) {
warn("disconnect script failed");
} else {
info("Serial link disconnected.");
return 0;
}
+/*
+ * setup_signals - initialize signal handling.
+ */
+static void
+setup_signals()
+{
+ struct sigaction sa;
+ sigset_t mask;
+
+ /*
+ * Compute mask of all interesting signals and install signal handlers
+ * for each. Only one signal handler may be active at a time. Therefore,
+ * all other signals should be masked when any handler is executing.
+ */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGHUP);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+ sigaddset(&mask, SIGCHLD);
+ sigaddset(&mask, SIGUSR2);
+
+#define SIGNAL(s, handler) do { \
+ sa.sa_handler = handler; \
+ if (sigaction(s, &sa, NULL) < 0) \
+ fatal("Couldn't establish signal handler (%d): %m", s); \
+ } while (0)
+
+ sa.sa_mask = mask;
+ sa.sa_flags = 0;
+ SIGNAL(SIGHUP, hup); /* Hangup */
+ SIGNAL(SIGINT, term); /* Interrupt */
+ SIGNAL(SIGTERM, term); /* Terminate */
+ SIGNAL(SIGCHLD, chld);
+
+ SIGNAL(SIGUSR1, toggle_debug); /* Toggle debug flag */
+ SIGNAL(SIGUSR2, open_ccp); /* Reopen CCP */
+
+ /*
+ * Install a handler for other signals which would otherwise
+ * cause pppd to exit without cleaning up.
+ */
+ SIGNAL(SIGABRT, bad_signal);
+ SIGNAL(SIGALRM, bad_signal);
+ SIGNAL(SIGFPE, bad_signal);
+ SIGNAL(SIGILL, bad_signal);
+ SIGNAL(SIGPIPE, bad_signal);
+ SIGNAL(SIGQUIT, bad_signal);
+ SIGNAL(SIGSEGV, bad_signal);
+#ifdef SIGBUS
+ SIGNAL(SIGBUS, bad_signal);
+#endif
+#ifdef SIGEMT
+ SIGNAL(SIGEMT, bad_signal);
+#endif
+#ifdef SIGPOLL
+ SIGNAL(SIGPOLL, bad_signal);
+#endif
+#ifdef SIGPROF
+ SIGNAL(SIGPROF, bad_signal);
+#endif
+#ifdef SIGSYS
+ SIGNAL(SIGSYS, bad_signal);
+#endif
+#ifdef SIGTRAP
+ SIGNAL(SIGTRAP, bad_signal);
+#endif
+#ifdef SIGVTALRM
+ SIGNAL(SIGVTALRM, bad_signal);
+#endif
+#ifdef SIGXCPU
+ SIGNAL(SIGXCPU, bad_signal);
+#endif
+#ifdef SIGXFSZ
+ SIGNAL(SIGXFSZ, bad_signal);
+#endif
+
+ /*
+ * Apparently we can get a SIGPIPE when we call syslog, if
+ * syslogd has died and been restarted. Ignoring it seems
+ * be sufficient.
+ */
+ signal(SIGPIPE, SIG_IGN);
+}
+
+/*
+ * set_ifunit - do things we need to do once we know which ppp
+ * unit we are using.
+ */
+void
+set_ifunit(iskey)
+ int iskey;
+{
+ info("Using interface ppp%d", ifunit);
+ slprintf(ifname, sizeof(ifname), "ppp%d", ifunit);
+ script_setenv("IFNAME", ifname, iskey);
+ create_pidfile(); /* write pid to file */
+ create_linkpidfile();
+}
+
/*
* detach - detach us from the controlling terminal.
*/
detach()
{
int pid;
+ char numbuf[16];
if (detached)
return;
close(1);
close(2);
detached = 1;
- log_to_fd = -1;
+ if (!log_to_file && !log_to_specific_fd)
+ log_to_fd = -1;
/* update pid files if they have been written already */
if (pidfilename[0])
create_pidfile();
if (linkpidfile[0])
create_linkpidfile();
+ slprintf(numbuf, sizeof(numbuf), "%d", getpid());
+ script_setenv("PPPD_PID", numbuf, 1);
}
/*
create_pidfile()
{
FILE *pidfile;
- char numbuf[16];
slprintf(pidfilename, sizeof(pidfilename), "%s%s.pid",
_PATH_VARRUN, ifname);
error("Failed to create pid file %s: %m", pidfilename);
pidfilename[0] = 0;
}
- slprintf(numbuf, sizeof(numbuf), "%d", getpid());
- script_setenv("PPPD_PID", numbuf);
- if (linkpidfile[0])
- create_linkpidfile();
}
static void
if (linkname[0] == 0)
return;
+ script_setenv("LINKNAME", linkname, 1);
slprintf(linkpidfile, sizeof(linkpidfile), "%sppp-%s.pid",
_PATH_VARRUN, linkname);
if ((pidfile = fopen(linkpidfile, "w")) != NULL) {
fprintf(pidfile, "%d\n", getpid());
- if (pidfilename[0])
+ if (ifname[0])
fprintf(pidfile, "%s\n", ifname);
(void) fclose(pidfile);
} else {
error("Failed to create pid file %s: %m", linkpidfile);
linkpidfile[0] = 0;
}
- script_setenv("LINKNAME", linkname);
}
/*
new_phase(PHASE_DORMANT);
}
+/* List of protocol names, to make our messages a little more informative. */
+struct protocol_list {
+ u_short proto;
+ const char *name;
+} protocol_list[] = {
+ { 0x21, "IP" },
+ { 0x23, "OSI Network Layer" },
+ { 0x25, "Xerox NS IDP" },
+ { 0x27, "DECnet Phase IV" },
+ { 0x29, "Appletalk" },
+ { 0x2b, "Novell IPX" },
+ { 0x2d, "VJ compressed TCP/IP" },
+ { 0x2f, "VJ uncompressed TCP/IP" },
+ { 0x31, "Bridging PDU" },
+ { 0x33, "Stream Protocol ST-II" },
+ { 0x35, "Banyan Vines" },
+ { 0x39, "AppleTalk EDDP" },
+ { 0x3b, "AppleTalk SmartBuffered" },
+ { 0x3d, "Multi-Link" },
+ { 0x3f, "NETBIOS Framing" },
+ { 0x41, "Cisco Systems" },
+ { 0x43, "Ascom Timeplex" },
+ { 0x45, "Fujitsu Link Backup and Load Balancing (LBLB)" },
+ { 0x47, "DCA Remote Lan" },
+ { 0x49, "Serial Data Transport Protocol (PPP-SDTP)" },
+ { 0x4b, "SNA over 802.2" },
+ { 0x4d, "SNA" },
+ { 0x4f, "IP6 Header Compression" },
+ { 0x6f, "Stampede Bridging" },
+ { 0xfb, "single-link compression" },
+ { 0xfd, "1st choice compression" },
+ { 0x0201, "802.1d Hello Packets" },
+ { 0x0203, "IBM Source Routing BPDU" },
+ { 0x0205, "DEC LANBridge100 Spanning Tree" },
+ { 0x0231, "Luxcom" },
+ { 0x0233, "Sigma Network Systems" },
+ { 0x8021, "Internet Protocol Control Protocol" },
+ { 0x8023, "OSI Network Layer Control Protocol" },
+ { 0x8025, "Xerox NS IDP Control Protocol" },
+ { 0x8027, "DECnet Phase IV Control Protocol" },
+ { 0x8029, "Appletalk Control Protocol" },
+ { 0x802b, "Novell IPX Control Protocol" },
+ { 0x8031, "Bridging NCP" },
+ { 0x8033, "Stream Protocol Control Protocol" },
+ { 0x8035, "Banyan Vines Control Protocol" },
+ { 0x803d, "Multi-Link Control Protocol" },
+ { 0x803f, "NETBIOS Framing Control Protocol" },
+ { 0x8041, "Cisco Systems Control Protocol" },
+ { 0x8043, "Ascom Timeplex" },
+ { 0x8045, "Fujitsu LBLB Control Protocol" },
+ { 0x8047, "DCA Remote Lan Network Control Protocol (RLNCP)" },
+ { 0x8049, "Serial Data Control Protocol (PPP-SDCP)" },
+ { 0x804b, "SNA over 802.2 Control Protocol" },
+ { 0x804d, "SNA Control Protocol" },
+ { 0x804f, "IP6 Header Compression Control Protocol" },
+ { 0x006f, "Stampede Bridging Control Protocol" },
+ { 0x80fb, "Single Link Compression Control Protocol" },
+ { 0x80fd, "Compression Control Protocol" },
+ { 0xc021, "Link Control Protocol" },
+ { 0xc023, "Password Authentication Protocol" },
+ { 0xc025, "Link Quality Report" },
+ { 0xc027, "Shiva Password Authentication Protocol" },
+ { 0xc029, "CallBack Control Protocol (CBCP)" },
+ { 0xc081, "Container Control Protocol" },
+ { 0xc223, "Challenge Handshake Authentication Protocol" },
+ { 0xc281, "Proprietary Authentication Protocol" },
+ { 0, NULL },
+};
+
+/*
+ * protocol_name - find a name for a PPP protocol.
+ */
+const char *
+protocol_name(proto)
+ int proto;
+{
+ struct protocol_list *lp;
+
+ for (lp = protocol_list; lp->proto != 0; ++lp)
+ if (proto == lp->proto)
+ return lp->name;
+ return NULL;
+}
+
/*
* get_input - called when incoming data is available.
*/
}
}
- if (debug)
- warn("Unsupported protocol (0x%x) received", protocol);
+ if (debug) {
+ const char *pname = protocol_name(protocol);
+ if (pname != NULL)
+ warn("Unsupported protocol '%s' (0x%x) received", pname, protocol);
+ else
+ warn("Unsupported protocol 0x%x received", protocol);
+ }
lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN);
}
if (locked)
unlock();
+
+ if (pppdb != NULL)
+ cleanup_db();
}
/*
link_stats_valid = 1;
slprintf(numbuf, sizeof(numbuf), "%d", link_connect_time);
- script_setenv("CONNECT_TIME", numbuf);
+ script_setenv("CONNECT_TIME", numbuf, 0);
slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_out);
- script_setenv("BYTES_SENT", numbuf);
+ script_setenv("BYTES_SENT", numbuf, 0);
slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_in);
- script_setenv("BYTES_RCVD", numbuf);
+ script_setenv("BYTES_RCVD", numbuf, 0);
}
return 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) {
+ --n_children;
*prevp = chp->next;
break;
}
* for scripts that we run (e.g. ip-up, auth-up, etc.)
*/
void
-script_setenv(var, value)
+script_setenv(var, value, iskey)
char *var, *value;
+ int iskey;
{
- size_t vl = strlen(var) + strlen(value) + 2;
+ size_t varl = strlen(var);
+ size_t vl = varl + strlen(value) + 2;
int i;
char *p, *newstring;
- newstring = (char *) malloc(vl);
+ newstring = (char *) malloc(vl+1);
if (newstring == 0)
return;
+ *newstring++ = iskey;
slprintf(newstring, vl, "%s=%s", var, value);
/* check if this variable is already set */
if (script_env != 0) {
for (i = 0; (p = script_env[i]) != 0; ++i) {
- if (strncmp(p, var, vl) == 0 && p[vl] == '=') {
- free(p);
+ if (strncmp(p, var, varl) == 0 && p[varl] == '=') {
+ if (p[-1] && pppdb != NULL)
+ delete_db_key(p);
+ free(p-1);
script_env[i] = newstring;
+ if (iskey && pppdb != NULL)
+ add_db_key(newstring);
+ update_db_entry();
return;
}
}
script_env[i] = newstring;
script_env[i+1] = 0;
+
+ if (pppdb != NULL) {
+ if (iskey)
+ add_db_key(newstring);
+ update_db_entry();
+ }
}
/*
return;
for (i = 0; (p = script_env[i]) != 0; ++i) {
if (strncmp(p, var, vl) == 0 && p[vl] == '=') {
- free(p);
+ if (p[-1] && pppdb != NULL)
+ delete_db_key(p);
+ free(p-1);
while ((script_env[i] = script_env[i+1]) != 0)
++i;
break;
}
}
+ if (pppdb != NULL)
+ update_db_entry();
+}
+
+/*
+ * update_db_entry - update our entry in the database.
+ */
+static void
+update_db_entry()
+{
+ TDB_DATA key, dbuf;
+ int vlen, i;
+ char *p, *q, *vbuf;
+
+ if (script_env == NULL)
+ return;
+ vlen = 0;
+ for (i = 0; (p = script_env[i]) != 0; ++i)
+ vlen += strlen(p) + 1;
+ vbuf = malloc(vlen);
+ if (vbuf == 0)
+ novm("database entry");
+ q = vbuf;
+ for (i = 0; (p = script_env[i]) != 0; ++i)
+ q += slprintf(q, vbuf + vlen - q, "%s;", p);
+
+ key.dptr = db_key;
+ key.dsize = strlen(db_key);
+ dbuf.dptr = vbuf;
+ dbuf.dsize = vlen;
+ if (tdb_store(pppdb, key, dbuf, TDB_REPLACE))
+ error("tdb_store failed: %s", tdb_error(pppdb));
+
+}
+
+/*
+ * add_db_key - add a key that we can use to look up our database entry.
+ */
+static void
+add_db_key(str)
+ const char *str;
+{
+ TDB_DATA key, dbuf;
+
+ key.dptr = (char *) str;
+ key.dsize = strlen(str);
+ dbuf.dptr = db_key;
+ dbuf.dsize = strlen(db_key);
+ if (tdb_store(pppdb, key, dbuf, TDB_REPLACE))
+ error("tdb_store key failed: %s", tdb_error(pppdb));
+}
+
+/*
+ * delete_db_key - delete a key for looking up our database entry.
+ */
+static void
+delete_db_key(str)
+ const char *str;
+{
+ TDB_DATA key;
+
+ key.dptr = (char *) str;
+ key.dsize = strlen(str);
+ tdb_delete(pppdb, key);
+}
+
+/*
+ * cleanup_db - delete all the entries we put in the database.
+ */
+static void
+cleanup_db()
+{
+ TDB_DATA key;
+ int i;
+ char *p;
+
+ key.dptr = db_key;
+ key.dsize = strlen(db_key);
+ tdb_delete(pppdb, key);
+ for (i = 0; (p = script_env[i]) != 0; ++i)
+ if (p[-1])
+ delete_db_key(p);
+}
+
+/*
+ * open_socket - establish a stream socket connection to the nominated
+ * host and port.
+ */
+static int
+open_socket(dest)
+ char *dest;
+{
+ char *sep, *endp = NULL;
+ int sock, port = -1;
+ u_int32_t host;
+ struct hostent *hent;
+ struct sockaddr_in sad;
+
+ /* parse host:port and resolve host to an IP address */
+ sep = strchr(dest, ':');
+ if (sep != NULL)
+ port = strtol(sep+1, &endp, 10);
+ if (port < 0 || endp == sep+1 || sep == dest) {
+ error("Can't parse host:port for socket destination");
+ return -1;
+ }
+ *sep = 0;
+ host = inet_addr(dest);
+ if (host == (u_int32_t) -1) {
+ hent = gethostbyname(dest);
+ if (hent == NULL) {
+ error("%s: unknown host in socket option", dest);
+ *sep = ':';
+ return -1;
+ }
+ host = *(u_int32_t *)(hent->h_addr_list[0]);
+ }
+ *sep = ':';
+
+ /* get a socket and connect it to the other end */
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ error("Can't create socket: %m");
+ return -1;
+ }
+ memset(&sad, 0, sizeof(sad));
+ sad.sin_family = AF_INET;
+ sad.sin_port = htons(port);
+ sad.sin_addr.s_addr = host;
+ if (connect(sock, (struct sockaddr *)&sad, sizeof(sad)) < 0) {
+ error("Can't connect to %s: %m", dest);
+ close(sock);
+ return -1;
+ }
+
+ return sock;
}
/*
int pty_readable, stdin_readable;
struct timeval lasttime;
FILE *recordf = NULL;
+ int ilevel, olevel, max_level;
+ struct timeval levelt, tout, *top;
/*
* Reset signal handlers.
nibuf = nobuf = 0;
ibufp = obufp = NULL;
pty_readable = stdin_readable = 1;
+
+ ilevel = olevel = 0;
+ gettimeofday(&levelt, NULL);
+ if (max_data_rate) {
+ max_level = max_data_rate / 10;
+ if (max_level < 100)
+ max_level = 100;
+ } else
+ max_level = sizeof(inpacket_buf) + 1;
+
nfds = (ofd > pty_master? ofd: pty_master) + 1;
if (recordf != NULL) {
gettimeofday(&lasttime, NULL);
}
while (nibuf != 0 || nobuf != 0 || pty_readable || stdin_readable) {
+ top = 0;
+ tout.tv_sec = 0;
+ tout.tv_usec = 10000;
FD_ZERO(&ready);
FD_ZERO(&writey);
- if (nibuf != 0)
- FD_SET(pty_master, &writey);
- else if (stdin_readable)
+ if (nibuf != 0) {
+ if (ilevel >= max_level)
+ top = &tout;
+ else
+ FD_SET(pty_master, &writey);
+ } else if (stdin_readable)
FD_SET(ifd, &ready);
- if (nobuf != 0)
- FD_SET(ofd, &writey);
- else if (pty_readable)
+ if (nobuf != 0) {
+ if (olevel >= max_level)
+ top = &tout;
+ else
+ FD_SET(ofd, &writey);
+ } else if (pty_readable)
FD_SET(pty_master, &ready);
- if (select(nfds, &ready, &writey, NULL, NULL) < 0) {
+ if (select(nfds, &ready, &writey, NULL, top) < 0) {
if (errno != EINTR)
fatal("select");
continue;
}
+ if (max_data_rate) {
+ double dt;
+ int nbt;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+ dt = (now.tv_sec - levelt.tv_sec
+ + (now.tv_usec - levelt.tv_usec) / 1e6);
+ nbt = (int)(dt * max_data_rate);
+ ilevel = (nbt < 0 || nbt > ilevel)? 0: ilevel - nbt;
+ olevel = (nbt < 0 || nbt > olevel)? 0: olevel - nbt;
+ levelt = now;
+ } else
+ ilevel = olevel = 0;
if (FD_ISSET(ifd, &ready)) {
ibufp = inpacket_buf;
nibuf = read(ifd, ibufp, sizeof(inpacket_buf));
}
}
if (FD_ISSET(ofd, &writey)) {
- n = write(ofd, obufp, nobuf);
+ n = nobuf;
+ if (olevel + n > max_level)
+ n = max_level - olevel;
+ n = write(ofd, obufp, n);
if (n < 0) {
if (errno != EIO) {
error("Error writing standard output: %m");
} else {
obufp += n;
nobuf -= n;
+ olevel += n;
}
}
if (FD_ISSET(pty_master, &writey)) {
- n = write(pty_master, ibufp, nibuf);
+ n = nibuf;
+ if (ilevel + n > max_level)
+ n = max_level - ilevel;
+ n = write(pty_master, ibufp, n);
if (n < 0) {
if (errno != EIO) {
error("Error writing pseudo-tty master: %m");
} else {
ibufp += n;
nibuf -= n;
+ ilevel += n;
}
}
}