X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fmain.c;h=1b3f1e54bdd3250cb41fb986b89b3aaff355128e;hp=7924b5df7dbb583ba4a1385f8ca4f9d436333bc9;hb=d00f8a0e184cc73b1ca33a9b22c1b1f87292a72f;hpb=cd8692c099106d7acad6fd0215a899dae866792a;ds=sidebyside diff --git a/pppd/main.c b/pppd/main.c index 7924b5d..1b3f1e5 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -66,7 +66,7 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define RCSID "$Id: main.c,v 1.154 2006/12/19 07:48:19 paulus Exp $" +#define RCSID "$Id: main.c,v 1.156 2008/06/23 11:47:18 paulus Exp $" #include #include @@ -80,7 +80,6 @@ #include #include #include -#include #include #include #include @@ -121,10 +120,9 @@ #include "atcp.h" #endif -static const char rcsid[] = RCSID; /* interface vars */ -char ifname[32]; /* Interface name */ +char ifname[MAXIFNAMELEN]; /* Interface name */ int ifunit; /* Interface unit number */ struct channel *the_channel; @@ -181,7 +179,7 @@ int got_sighup; static sigset_t signals_handled; static int waiting; -static sigjmp_buf sigjmp; +static int sigpipe[2]; char **script_env; /* Env. variable values for scripts */ int s_env_nalloc; /* # words avail at script_env */ @@ -220,6 +218,7 @@ struct subprocess { char *prog; void (*done) __P((void *)); void *arg; + int killable; struct subprocess *next; }; @@ -256,7 +255,6 @@ static void cleanup_db __P((void)); static void handle_events __P((void)); void print_link_stats __P((void)); -extern char *ttyname __P((int)); extern char *getlogin __P((void)); int main __P((int, char *[])); @@ -297,13 +295,6 @@ struct protent *protocols[] = { NULL }; -/* - * If PPP_DRV_NAME is not defined, use the default "ppp" as the device name. - */ -#if !defined(PPP_DRV_NAME) -#define PPP_DRV_NAME "ppp" -#endif /* !defined(PPP_DRV_NAME) */ - int main(argc, argv) int argc; @@ -606,19 +597,21 @@ static void handle_events() { struct timeval timo; + unsigned char buf[16]; kill_link = open_ccp_flag = 0; - if (sigsetjmp(sigjmp, 1) == 0) { - sigprocmask(SIG_BLOCK, &signals_handled, NULL); - if (got_sighup || got_sigterm || got_sigusr2 || got_sigchld) { - sigprocmask(SIG_UNBLOCK, &signals_handled, NULL); - } else { - waiting = 1; - sigprocmask(SIG_UNBLOCK, &signals_handled, NULL); - wait_input(timeleft(&timo)); - } - } + + /* alert via signal pipe */ + waiting = 1; + /* flush signal pipe */ + for (; read(sigpipe[0], buf, sizeof(buf)) > 0; ); + add_fd(sigpipe[0]); + /* wait if necessary */ + if (!(got_sighup || got_sigterm || got_sigusr2 || got_sigchld)) + wait_input(timeleft(&timo)); waiting = 0; + remove_fd(sigpipe[0]); + calltimeout(); if (got_sighup) { info("Hangup (SIGHUP)"); @@ -653,6 +646,14 @@ setup_signals() { struct sigaction sa; + /* create pipe to wake up event handler from signal handler */ + if (pipe(sigpipe) < 0) + fatal("Couldn't create signal pipe: %m"); + fcntl(sigpipe[0], F_SETFD, fcntl(sigpipe[0], F_GETFD) | FD_CLOEXEC); + fcntl(sigpipe[1], F_SETFD, fcntl(sigpipe[1], F_GETFD) | FD_CLOEXEC); + fcntl(sigpipe[0], F_SETFL, fcntl(sigpipe[0], F_GETFL) | O_NONBLOCK); + fcntl(sigpipe[1], F_SETFL, fcntl(sigpipe[1], F_GETFL) | O_NONBLOCK); + /* * Compute mask of all interesting signals and install signal handlers * for each. Only one signal handler may be active at a time. Therefore, @@ -736,8 +737,11 @@ void set_ifunit(iskey) int iskey; { - info("Using interface %s%d", PPP_DRV_NAME, ifunit); - slprintf(ifname, sizeof(ifname), "%s%d", PPP_DRV_NAME, ifunit); + if (req_ifname[0] != '\0') + slprintf(ifname, sizeof(ifname), "%s", req_ifname); + else + slprintf(ifname, sizeof(ifname), "%s%d", PPP_DRV_NAME, ifunit); + info("Using interface %s", ifname); script_setenv("IFNAME", ifname, iskey); if (iskey) { create_pidfile(getpid()); /* write pid to file */ @@ -963,7 +967,7 @@ struct protocol_list { { 0x8051, "KNX Bridging Control Protocol" }, { 0x8053, "Encryption Control Protocol" }, { 0x8055, "Individual Link Encryption Control Protocol" }, - { 0x8057, "IPv6 Control Protovol" }, + { 0x8057, "IPv6 Control Protocol" }, { 0x8059, "PPP Muxing Control Protocol" }, { 0x805b, "Vendor-Specific Network Control Protocol (VSNCP)" }, { 0x806f, "Stampede Bridging Control Protocol" }, @@ -1383,7 +1387,21 @@ kill_my_pg(sig) int sig; { struct sigaction act, oldact; + struct subprocess *chp; + + if (!detached) { + /* + * There might be other things in our process group that we + * didn't start that would get hit if we did a kill(0), so + * just send the signal individually to our children. + */ + for (chp = children; chp != NULL; chp = chp->next) + if (chp->killable) + kill(chp->pid, sig); + return; + } + /* We've done a setsid(), so we can just use a kill(0) */ sigemptyset(&act.sa_mask); /* unnecessary in fact */ act.sa_handler = SIG_IGN; act.sa_flags = 0; @@ -1422,7 +1440,7 @@ hup(sig) kill_my_pg(sig); notify(sigreceived, sig); if (waiting) - siglongjmp(sigjmp, 1); + write(sigpipe[1], &sig, sizeof(sig)); } @@ -1443,7 +1461,7 @@ term(sig) kill_my_pg(sig); notify(sigreceived, sig); if (waiting) - siglongjmp(sigjmp, 1); + write(sigpipe[1], &sig, sizeof(sig)); } @@ -1457,7 +1475,7 @@ chld(sig) { got_sigchld = 1; if (waiting) - siglongjmp(sigjmp, 1); + write(sigpipe[1], &sig, sizeof(sig)); } @@ -1492,7 +1510,7 @@ open_ccp(sig) { got_sigusr2 = 1; if (waiting) - siglongjmp(sigjmp, 1); + write(sigpipe[1], &sig, sizeof(sig)); } @@ -1556,7 +1574,8 @@ safe_fork(int infd, int outfd, int errfd) /* Executing in the child */ sys_close(); #ifdef USE_TDB - tdb_close(pppdb); + if (pppdb != NULL) + tdb_close(pppdb); #endif /* make sure infd, outfd and errfd won't get tromped on below */ @@ -1600,6 +1619,52 @@ safe_fork(int infd, int outfd, int errfd) return 0; } +static bool +add_script_env(pos, newstring) + int pos; + char *newstring; +{ + if (pos + 1 >= s_env_nalloc) { + int new_n = pos + 17; + char **newenv = realloc(script_env, new_n * sizeof(char *)); + if (newenv == NULL) { + free(newstring - 1); + return 0; + } + script_env = newenv; + s_env_nalloc = new_n; + } + script_env[pos] = newstring; + script_env[pos + 1] = NULL; + return 1; +} + +static void +remove_script_env(pos) + int pos; +{ + free(script_env[pos] - 1); + while ((script_env[pos] = script_env[pos + 1]) != NULL) + pos++; +} + +/* + * update_system_environment - process the list of set/unset options + * and update the system environment. + */ +static void +update_system_environment() +{ + struct userenv *uep; + + for (uep = userenv_list; uep != NULL; uep = uep->ue_next) { + if (uep->ue_isset) + setenv(uep->ue_name, uep->ue_value, 1); + else + unsetenv(uep->ue_name); + } +} + /* * device_script - run a program to talk to the specified fds * (e.g. to run the connector or disconnector script). @@ -1633,15 +1698,15 @@ device_script(program, in, out, dont_wait) } if (pid != 0) { - if (dont_wait) { - record_child(pid, program, NULL, NULL); - status = 0; - } else { + record_child(pid, program, NULL, NULL, 1); + status = 0; + if (!dont_wait) { while (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) continue; fatal("error waiting for (dis)connection process: %m"); } + forget_child(pid, status); --conn_running; } return (status == 0 ? 0 : -1); @@ -1655,15 +1720,54 @@ device_script(program, in, out, dont_wait) fprintf(stderr, "pppd: setuid failed\n"); exit(1); } + update_system_environment(); execl("/bin/sh", "sh", "-c", program, (char *)0); perror("pppd: could not exec /bin/sh"); - exit(99); + _exit(99); /* NOTREACHED */ } /* - * run-program - execute a program with given arguments, + * update_script_environment - process the list of set/unset options + * and update the script environment. Note that we intentionally do + * not update the TDB. These changes are layered on top right before + * exec. It is not possible to use script_setenv() or + * script_unsetenv() safely after this routine is run. + */ +static void +update_script_environment() +{ + struct userenv *uep; + + for (uep = userenv_list; uep != NULL; uep = uep->ue_next) { + int i; + char *p, *newstring; + int nlen = strlen(uep->ue_name); + + for (i = 0; (p = script_env[i]) != NULL; i++) { + if (strncmp(p, uep->ue_name, nlen) == 0 && p[nlen] == '=') + break; + } + if (uep->ue_isset) { + nlen += strlen(uep->ue_value) + 2; + newstring = malloc(nlen + 1); + if (newstring == NULL) + continue; + *newstring++ = 0; + slprintf(newstring, nlen, "%s=%s", uep->ue_name, uep->ue_value); + if (p != NULL) + script_env[i] = newstring; + else + add_script_env(i, newstring); + } else if (p != NULL) { + remove_script_env(i); + } + } +} + +/* + * run_program - execute a program with given arguments, * but don't wait for it unless wait is non-zero. * If the program can't be executed, logs an error unless * must_exist is 0 and the program file doesn't exist. @@ -1706,7 +1810,7 @@ run_program(prog, args, must_exist, done, arg, wait) if (pid != 0) { if (debug) dbglog("Script %s started (pid %d)", prog, pid); - record_child(pid, prog, done, arg); + record_child(pid, prog, done, arg, 0); if (wait) { while (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) @@ -1732,6 +1836,7 @@ run_program(prog, args, must_exist, done, arg, wait) #endif /* run the program */ + update_script_environment(); execve(prog, args, script_env); if (must_exist || errno != ENOENT) { /* have to reopen the log, there's nowhere else @@ -1740,7 +1845,7 @@ run_program(prog, args, must_exist, done, arg, wait) syslog(LOG_ERR, "Can't execute %s: %m", prog); closelog(); } - _exit(-1); + _exit(99); } @@ -1749,11 +1854,12 @@ run_program(prog, args, must_exist, done, arg, wait) * to use. */ void -record_child(pid, prog, done, arg) +record_child(pid, prog, done, arg, killable) int pid; char *prog; void (*done) __P((void *)); void *arg; + int killable; { struct subprocess *chp; @@ -1768,6 +1874,7 @@ record_child(pid, prog, done, arg) chp->done = done; chp->arg = arg; chp->next = children; + chp->killable = killable; children = chp; } } @@ -1940,9 +2047,11 @@ script_setenv(var, value, iskey) free(p-1); script_env[i] = newstring; #ifdef USE_TDB - if (iskey && pppdb != NULL) - add_db_key(newstring); - update_db_entry(); + if (pppdb != NULL) { + if (iskey) + add_db_key(newstring); + update_db_entry(); + } #endif return; } @@ -1950,25 +2059,16 @@ script_setenv(var, value, iskey) } else { /* no space allocated for script env. ptrs. yet */ i = 0; - script_env = (char **) malloc(16 * sizeof(char *)); - if (script_env == 0) + script_env = malloc(16 * sizeof(char *)); + if (script_env == 0) { + free(newstring - 1); return; + } s_env_nalloc = 16; } - /* reallocate script_env with more space if needed */ - if (i + 1 >= s_env_nalloc) { - int new_n = i + 17; - char **newenv = (char **) realloc((void *)script_env, - new_n * sizeof(char *)); - if (newenv == 0) - return; - script_env = newenv; - s_env_nalloc = new_n; - } - - script_env[i] = newstring; - script_env[i+1] = 0; + if (!add_script_env(i, newstring)) + return; #ifdef USE_TDB if (pppdb != NULL) { @@ -1999,9 +2099,7 @@ script_unsetenv(var) if (p[-1] && pppdb != NULL) delete_db_key(p); #endif - free(p-1); - while ((script_env[i] = script_env[i+1]) != 0) - ++i; + remove_script_env(i); break; } } @@ -2074,7 +2172,7 @@ update_db_entry() dbuf.dptr = vbuf; dbuf.dsize = vlen; if (tdb_store(pppdb, key, dbuf, TDB_REPLACE)) - error("tdb_store failed: %s", tdb_error(pppdb)); + error("tdb_store failed: %s", tdb_errorstr(pppdb)); if (vbuf) free(vbuf); @@ -2095,7 +2193,7 @@ add_db_key(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)); + error("tdb_store key failed: %s", tdb_errorstr(pppdb)); } /*