X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fmain.c;h=e09b6ffcce32bd06389d91da6276f24c1e009007;hb=5c765a67fd25f9d84e71ed61ace37c8c97f6be15;hp=be212daa171f36cfa3c0922fc5f92b430b014a62;hpb=bc3775fa3f711516fbd0890035a8ddc145ad2ff0;p=ppp.git diff --git a/pppd/main.c b/pppd/main.c index be212da..e09b6ff 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.151 2005/07/12 01:07:59 paulus Exp $" +#define RCSID "$Id: main.c,v 1.156 2008/06/23 11:47:18 paulus Exp $" #include #include @@ -124,7 +124,7 @@ 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; @@ -220,6 +220,7 @@ struct subprocess { char *prog; void (*done) __P((void *)); void *arg; + int killable; struct subprocess *next; }; @@ -242,6 +243,7 @@ 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 void forget_child __P((int pid, int status)); static int reap_kids __P((void)); static void childwait_end __P((void *)); @@ -255,7 +257,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 *[])); @@ -296,13 +297,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; @@ -735,8 +729,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 */ @@ -962,7 +959,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" }, @@ -1382,7 +1379,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; @@ -1566,6 +1577,8 @@ safe_fork(int infd, int outfd, int errfd) if (errfd == 0 || errfd == 1) errfd = dup(errfd); + closelog(); + /* dup the in, out, err fds to 0, 1, 2 */ if (infd != 0) dup2(infd, 0); @@ -1574,7 +1587,6 @@ safe_fork(int infd, int outfd, int errfd) if (errfd != 2) dup2(errfd, 2); - closelog(); if (log_to_fd > 2) close(log_to_fd); if (the_channel->close) @@ -1598,6 +1610,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). @@ -1631,15 +1689,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); @@ -1653,16 +1711,55 @@ 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, - * but don't wait for it. + * 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. * Returns -1 if it couldn't fork, 0 if the file doesn't exist @@ -1671,14 +1768,15 @@ device_script(program, in, out, dont_wait) * reap_kids) iff the return value is > 0. */ pid_t -run_program(prog, args, must_exist, done, arg) +run_program(prog, args, must_exist, done, arg, wait) char *prog; char **args; int must_exist; void (*done) __P((void *)); void *arg; + int wait; { - int pid; + int pid, status; struct stat sbuf; /* @@ -1703,7 +1801,15 @@ run_program(prog, args, must_exist, done, arg) 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) + continue; + fatal("error waiting for script %s: %m", prog); + } + forget_child(pid, status); + } return pid; } @@ -1721,6 +1827,7 @@ run_program(prog, args, must_exist, done, arg) #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 @@ -1729,7 +1836,7 @@ run_program(prog, args, must_exist, done, arg) syslog(LOG_ERR, "Can't execute %s: %m", prog); closelog(); } - _exit(-1); + _exit(99); } @@ -1738,11 +1845,12 @@ run_program(prog, args, must_exist, done, arg) * 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; @@ -1757,6 +1865,7 @@ record_child(pid, prog, done, arg) chp->done = done; chp->arg = arg; chp->next = children; + chp->killable = killable; children = chp; } } @@ -1779,6 +1888,35 @@ childwait_end(arg) childwait_done = 1; } +/* + * forget_child - clean up after a dead child + */ +static void +forget_child(pid, status) + int pid, status; +{ + struct subprocess *chp, **prevp; + + for (prevp = &children; (chp = *prevp) != NULL; prevp = &chp->next) { + if (chp->pid == pid) { + --n_children; + *prevp = chp->next; + break; + } + } + if (WIFSIGNALED(status)) { + warn("Child process %s (pid %d) terminated with signal %d", + (chp? chp->prog: "??"), pid, WTERMSIG(status)); + } else if (debug) + dbglog("Script %s finished (pid %d), status = 0x%x", + (chp? chp->prog: "??"), pid, + WIFEXITED(status) ? WEXITSTATUS(status) : status); + if (chp && chp->done) + (*chp->done)(chp->arg); + if (chp) + free(chp); +} + /* * reap_kids - get status from any dead child processes, * and log a message for abnormal terminations. @@ -1787,29 +1925,11 @@ static int reap_kids() { int pid, status; - struct subprocess *chp, **prevp; if (n_children == 0) return 0; while ((pid = waitpid(-1, &status, WNOHANG)) != -1 && pid != 0) { - for (prevp = &children; (chp = *prevp) != NULL; prevp = &chp->next) { - if (chp->pid == pid) { - --n_children; - *prevp = chp->next; - break; - } - } - if (WIFSIGNALED(status)) { - warn("Child process %s (pid %d) terminated with signal %d", - (chp? chp->prog: "??"), pid, WTERMSIG(status)); - } else if (debug) - dbglog("Script %s finished (pid %d), status = 0x%x", - (chp? chp->prog: "??"), pid, - WIFEXITED(status) ? WEXITSTATUS(status) : status); - if (chp && chp->done) - (*chp->done)(chp->arg); - if (chp) - free(chp); + forget_child(pid, status); } if (pid == -1) { if (errno == ECHILD) @@ -1918,9 +2038,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; } @@ -1928,25 +2050,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) { @@ -1977,9 +2090,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; } } @@ -2052,7 +2163,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); @@ -2073,7 +2184,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)); } /*