pid_t pipespawnv_passwd( char * prog, int pipedef, int need_root, int * stdinfd, int * stdoutfd, int * stderrfd, char ** my_argv) { pid_t pid; int i, inpipe[2], outpipe[2], errpipe[2], passwdpipe[2]; char number[NUM_STR_SIZE]; char **arg; char *e; char **env; char *cmdline; char **newenv; char *passwdvar = NULL; int *passwdfd = NULL; GPtrArray *array = g_ptr_array_new(); gchar **strings; /* * Log the command line and count the args. */ if ((pipedef & PASSWD_PIPE) != 0) { passwdvar = *my_argv++; passwdfd = (int *)*my_argv++; } memset(inpipe, -1, sizeof(inpipe)); memset(outpipe, -1, sizeof(outpipe)); memset(errpipe, -1, sizeof(errpipe)); memset(passwdpipe, -1, sizeof(passwdpipe)); g_ptr_array_add(array, g_strdup(prog)); for(arg = my_argv; *arg != NULL; arg++) { if (*arg == skip_argument) continue; g_ptr_array_add(array, quote_string(*arg)); } g_ptr_array_add(array, NULL); strings = (gchar **)g_ptr_array_free(array, FALSE); cmdline = g_strjoinv(" ", strings); g_strfreev(strings); dbprintf(_("Spawning \"%s\" in pipeline\n"), cmdline); /* * Create the pipes */ if ((pipedef & STDIN_PIPE) != 0) { if(pipe(inpipe) == -1) { error(_("error [open pipe to %s: %s]"), prog, strerror(errno)); /*NOTREACHED*/ } } if ((pipedef & STDOUT_PIPE) != 0) { if(pipe(outpipe) == -1) { error(_("error [open pipe to %s: %s]"), prog, strerror(errno)); /*NOTREACHED*/ } } if ((pipedef & STDERR_PIPE) != 0) { if(pipe(errpipe) == -1) { error(_("error [open pipe to %s: %s]"), prog, strerror(errno)); /*NOTREACHED*/ } } if ((pipedef & PASSWD_PIPE) != 0) { if(pipe(passwdpipe) == -1) { error(_("error [open pipe to %s: %s]"), prog, strerror(errno)); /*NOTREACHED*/ } } /* * Fork and set up the return or run the program. */ switch(pid = fork()) { case -1: e = strerror(errno); error(_("error [fork %s: %s]"), prog, e); /*NOTREACHED*/ default: /* parent process */ if ((pipedef & STDIN_PIPE) != 0) { aclose(inpipe[0]); /* close input side of pipe */ *stdinfd = inpipe[1]; } if ((pipedef & STDOUT_PIPE) != 0) { aclose(outpipe[1]); /* close output side of pipe */ *stdoutfd = outpipe[0]; } if ((pipedef & STDERR_PIPE) != 0) { aclose(errpipe[1]); /* close output side of pipe */ *stderrfd = errpipe[0]; } if ((pipedef & PASSWD_PIPE) != 0) { aclose(passwdpipe[0]); /* close input side of pipe */ *passwdfd = passwdpipe[1]; } break; case 0: /* child process */ debug_dup_stderr_to_debug(); if ((pipedef & STDIN_PIPE) != 0) { aclose(inpipe[1]); /* close output side of pipe */ } else { inpipe[0] = *stdinfd; } if ((pipedef & STDOUT_PIPE) != 0) { aclose(outpipe[0]); /* close input side of pipe */ } else { outpipe[1] = *stdoutfd; } if ((pipedef & STDERR_PIPE) != 0) { aclose(errpipe[0]); /* close input side of pipe */ } else { errpipe[1] = *stderrfd; } if ((pipedef & PASSWD_PIPE) != 0) { aclose(passwdpipe[1]); /* close output side of pipe */ } /* * Shift the pipes to the standard file descriptors as requested. */ if(dup2(inpipe[0], 0) == -1) { g_fprintf(stderr, "error [spawn %s: dup2 in: %s]", prog, strerror(errno)); exit(1); /*NOTREACHED*/ } if(dup2(outpipe[1], 1) == -1) { g_fprintf(stderr, "error [spawn %s: dup2 out: %s]", prog, strerror(errno)); exit(1); /*NOTREACHED*/ } if(dup2(errpipe[1], 2) == -1) { g_fprintf(stderr, "error [spawn %s: dup2 err: %s]", prog, strerror(errno)); exit(1); /*NOTREACHED*/ } /* * Get the "safe" environment. If we are sending a password to * the child via a pipe, add the environment variable for that. */ env = safe_env(); if ((pipedef & PASSWD_PIPE) != 0) { for (i = 0; env[i] != NULL; i++) (void)i; /* make lint happy and do nothing */ newenv = (char **)g_malloc((i + 1 + 1) * sizeof(*newenv)); g_snprintf(number, sizeof(number), "%d", passwdpipe[0]); newenv[0] = g_strjoin(NULL, passwdvar, "=", number, NULL); for(i = 0; env[i] != NULL; i++) newenv[i + 1] = env[i]; newenv[i + 1] = NULL; amfree(env); env = newenv; safe_fd(passwdpipe[0], 1); } else { safe_fd(-1, 0); } if (need_root) { become_root(); } else { /* if our real userid is zero, the child shouldn't inherit * that, so drop privs permanently */ if (getuid() == 0 && !set_root_privs(-1)) { error(_("could not drop root privileges")); } } execve(prog, my_argv, env); e = strerror(errno); error(_("error [exec %s: %s]"), prog, e); /*NOTREACHED*/ } amfree(cmdline); return pid; }
static int start_chg_glue(void) { int stdin_pipe[2] = { -1, -1 }; int stdout_pipe[2] = { -1, -1 }; char *chg_glue = NULL; char **config_options = NULL; char *cmdline = NULL; /* is it already running? */ if (tpchanger_pid != -1) return 1; if (pipe(stdin_pipe) == -1 || pipe(stdout_pipe) == -1) { changer_resultstr = vstrallocf( _("<error> could not make pipe: %s"), strerror(errno)); goto error; } config_options = get_config_options(2); config_options[0] = g_strdup("chg-glue"); config_options[1] = g_strdup(get_config_name()); chg_glue = g_strdup_printf("%s/chg-glue", amlibexecdir); cmdline = g_strjoinv(" ", config_options); g_debug("invoking %s: %s", chg_glue, cmdline); amfree(cmdline); switch(tpchanger_pid = fork()) { case -1: changer_resultstr = vstrallocf( _("<error> could not fork: %s"), strerror(errno)); goto error; case 0: debug_dup_stderr_to_debug(); if(dup2(stdin_pipe[0], 0) == -1) { changer_resultstr = vstrallocf( _("<error> could not dup2: %s\n"), strerror(errno)); goto child_err; } if(dup2(stdout_pipe[1], 1) == -1) { changer_resultstr = vstrallocf( _("<error> could not dup2: %s\n"), strerror(errno)); goto child_err; } safe_fd(-1, 0); execv(chg_glue, config_options); changer_resultstr = vstrallocf( _("<error> could not exec \"%s\": %s\n"), chg_glue, strerror(errno)); child_err: (void)full_write(stdout_pipe[1], changer_resultstr, strlen(changer_resultstr)); exit(1); default: aclose(stdin_pipe[0]); aclose(stdout_pipe[1]); g_strfreev(config_options); amfree(chg_glue); amfree(cmdline); tpchanger_stdout = stdout_pipe[0]; tpchanger_stdin = stdin_pipe[1]; return 1; } error: amfree(chg_glue); amfree(cmdline); aclose(stdin_pipe[0]); aclose(stdin_pipe[1]); aclose(stdout_pipe[0]); aclose(stdout_pipe[1]); return 0; }