📄 main.c
字号:
/* * device_script - run a program to talk to the specified fds * (e.g. to run the connector or disconnector script). * stderr gets connected to the log fd or to the _PATH_CONNERRS file. */intdevice_script(program, in, out, dont_wait) char *program; int in, out; int dont_wait;{ int pid; int status = -1; int errfd; if (log_to_fd >= 0) errfd = log_to_fd; else errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0600); ++conn_running; pid = safe_fork(in, out, errfd); if (pid != 0 && log_to_fd < 0) close(errfd); if (pid < 0) { --conn_running; error("Failed to create child process: %m"); return -1; } if (pid != 0) { if (dont_wait) { record_child(pid, program, NULL, NULL); status = 0; } else { while (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) continue; fatal("error waiting for (dis)connection process: %m"); } --conn_running; } return (status == 0 ? 0 : -1); } /* here we are executing in the child */ setgid(getgid()); setuid(uid); if (getuid() != uid) { fprintf(stderr, "pppd: setuid failed\n"); exit(1); } execl("/bin/sh", "sh", "-c", program, (char *)0); perror("pppd: could not exec /bin/sh"); exit(99); /* NOTREACHED */}/* * 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 * or isn't an executable plain file, or the process ID of the child. * If done != NULL, (*done)(arg) will be called later (within * reap_kids) iff the return value is > 0. */pid_trun_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, status; struct stat sbuf; /* * First check if the file exists and is executable. * We don't use access() because that would use the * real user-id, which might not be root, and the script * might be accessible only to root. */ errno = EINVAL; if (stat(prog, &sbuf) < 0 || !S_ISREG(sbuf.st_mode) || (sbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) { if (must_exist || errno != ENOENT) warn("Can't execute %s: %m", prog); return 0; } pid = safe_fork(fd_devnull, fd_devnull, fd_devnull); if (pid == -1) { error("Failed to create child process for %s: %m", prog); return -1; } if (pid != 0) { if (debug) dbglog("Script %s started (pid %d)", prog, pid); record_child(pid, prog, done, arg); 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; } /* Leave the current location */ (void) setsid(); /* No controlling tty. */ (void) umask (S_IRWXG|S_IRWXO); (void) chdir ("/"); /* no current directory. */ setuid(0); /* set real UID = root */ setgid(getegid());#ifdef BSD /* Force the priority back to zero if pppd is running higher. */ if (setpriority (PRIO_PROCESS, 0, 0) < 0) warn("can't reset priority to 0: %m");#endif /* run the program */ execve(prog, args, script_env); if (must_exist || errno != ENOENT) { /* have to reopen the log, there's nowhere else for the message to go. */ reopen_log(); syslog(LOG_ERR, "Can't execute %s: %m", prog); closelog(); } _exit(-1);}/* * record_child - add a child process to the list for reap_kids * to use. */voidrecord_child(pid, prog, done, arg) int pid; char *prog; void (*done) __P((void *)); void *arg;{ struct subprocess *chp; ++n_children; chp = (struct subprocess *) malloc(sizeof(struct subprocess)); if (chp == NULL) { warn("losing track of %s process", prog); } else { chp->pid = pid; chp->prog = prog; chp->done = done; chp->arg = arg; chp->next = children; children = chp; }}/* * childwait_end - we got fed up waiting for the child processes to * exit, send them all a SIGTERM. */static voidchildwait_end(arg) void *arg;{ struct subprocess *chp; for (chp = children; chp != NULL; chp = chp->next) { if (debug) dbglog("sending SIGTERM to process %d", chp->pid); kill(chp->pid, SIGTERM); } childwait_done = 1;}/* * forget_child - clean up after a dead child */static voidforget_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. */static intreap_kids(){ int pid, status; if (n_children == 0) return 0; while ((pid = waitpid(-1, &status, WNOHANG)) != -1 && pid != 0) { forget_child(pid, status); } if (pid == -1) { if (errno == ECHILD) return -1; if (errno != EINTR) error("Error waiting for child process: %m"); } return 0;}/* * add_notifier - add a new function to be called when something happens. */voidadd_notifier(notif, func, arg) struct notifier **notif; notify_func func; void *arg;{ struct notifier *np; np = malloc(sizeof(struct notifier)); if (np == 0) novm("notifier struct"); np->next = *notif; np->func = func; np->arg = arg; *notif = np;}/* * remove_notifier - remove a function from the list of things to * be called when something happens. */voidremove_notifier(notif, func, arg) struct notifier **notif; notify_func func; void *arg;{ struct notifier *np; for (; (np = *notif) != 0; notif = &np->next) { if (np->func == func && np->arg == arg) { *notif = np->next; free(np); break; } }}/* * notify - call a set of functions registered with add_notifier. */voidnotify(notif, val) struct notifier *notif; int val;{ struct notifier *np; while ((np = notif) != 0) { notif = np->next; (*np->func)(np->arg, val); }}/* * novm - log an error message saying we ran out of memory, and die. */voidnovm(msg) char *msg;{ fatal("Virtual memory exhausted allocating %s\n", msg);}/* * script_setenv - set an environment variable value to be used * for scripts that we run (e.g. ip-up, auth-up, etc.) */voidscript_setenv(var, value, iskey) char *var, *value; int iskey;{ size_t varl = strlen(var); size_t vl = varl + strlen(value) + 2; int i; char *p, *newstring; 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, varl) == 0 && p[varl] == '=') {#ifdef USE_TDB if (p[-1] && pppdb != NULL) delete_db_key(p);#endif free(p-1); script_env[i] = newstring;#ifdef USE_TDB if (iskey && pppdb != NULL) add_db_key(newstring); update_db_entry();#endif return; } } } else { /* no space allocated for script env. ptrs. yet */ i = 0; script_env = (char **) malloc(16 * sizeof(char *)); if (script_env == 0) 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;#ifdef USE_TDB if (pppdb != NULL) { if (iskey) add_db_key(newstring); update_db_entry(); }#endif}/* * script_unsetenv - remove a variable from the environment * for scripts. */voidscript_unsetenv(var) char *var;{ int vl = strlen(var); int i; char *p; if (script_env == 0) return; for (i = 0; (p = script_env[i]) != 0; ++i) { if (strncmp(p, var, vl) == 0 && p[vl] == '=') {#ifdef USE_TDB if (p[-1] && pppdb != NULL) delete_db_key(p);#endif free(p-1); while ((script_env[i] = script_env[i+1]) != 0) ++i; break; } }#ifdef USE_TDB if (pppdb != NULL) update_db_entry();#endif}/* * Any arbitrary string used as a key for locking the database. * It doesn't matter what it is as long as all pppds use the same string. */#define PPPD_LOCK_KEY "pppd lock"/* * lock_db - get an exclusive lock on the TDB database. * Used to ensure atomicity of various lookup/modify operations. */void lock_db(){#ifdef USE_TDB TDB_DATA key; key.dptr = PPPD_LOCK_KEY; key.dsize = strlen(key.dptr); tdb_chainlock(pppdb, key);#endif}/* * unlock_db - remove the exclusive lock obtained by lock_db. */void unlock_db(){#ifdef USE_TDB TDB_DATA key; key.dptr = PPPD_LOCK_KEY; key.dsize = strlen(key.dptr); tdb_chainunlock(pppdb, key);#endif}#ifdef USE_TDB/* * update_db_entry - update our entry in the database. */static voidupdate_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 + 1); 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)); if (vbuf) free(vbuf);}/* * add_db_key - add a key that we can use to look up our database entry. */static voidadd_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 voiddelete_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 voidcleanup_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);}#endif /* USE_TDB */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -