9e4e90cc1915643d0797e38b10ae3eb81fc70fa2
[debian/amanda] / common-src / pipespawn.c
1 #include "amanda.h"
2 #include "pipespawn.h"
3 #include "arglist.h"
4 #include "clock.h"
5 #include "util.h"
6
7 char skip_argument[1];
8
9 pid_t pipespawnv_passwd(char *prog, int pipedef, int need_root,
10                   int *stdinfd, int *stdoutfd, int *stderrfd,
11                   char **my_argv);
12
13
14 /*
15  * this used to be a function in it's own write but became a wrapper around
16  * pipespawnv to eliminate redundancy...
17  */
18 pid_t
19 pipespawn(
20     char *      prog,
21     int         pipedef,
22     int         need_root,
23     int *       stdinfd,
24     int *       stdoutfd,
25     int *       stderrfd,
26     ...)
27 {
28     va_list ap;
29     int argc = 0, i;
30     pid_t pid;
31     char **argv;
32
33     /* count args */
34     arglist_start(ap, stderrfd);
35     while(arglist_val(ap, char *) != NULL) {
36         argc++;
37     }
38     arglist_end(ap);
39
40     /*
41      * Create the argument vector.
42      */
43     arglist_start(ap, stderrfd);
44     argv = (char **)alloc((argc + 1) * SIZEOF(*argv));
45     i = 0;
46     while((argv[i] = arglist_val(ap, char *)) != NULL) {
47         if (argv[i] != skip_argument) {
48             i++;
49         }
50     }
51     arglist_end(ap);
52
53     pid = pipespawnv_passwd(prog, pipedef, need_root,
54                             stdinfd, stdoutfd, stderrfd, argv);
55     amfree(argv);
56     return pid;
57 }
58
59 pid_t
60 pipespawnv(
61     char *      prog,
62     int         pipedef,
63     int         need_root,
64     int *       stdinfd,
65     int *       stdoutfd,
66     int *       stderrfd,
67     char **     my_argv)
68 {
69     return pipespawnv_passwd(prog, pipedef, need_root,
70                              stdinfd, stdoutfd, stderrfd,
71         my_argv);
72 }
73
74 pid_t
75 pipespawnv_passwd(
76     char *      prog,
77     int         pipedef,
78     int         need_root,
79     int *       stdinfd,
80     int *       stdoutfd,
81     int *       stderrfd,
82     char **     my_argv)
83 {
84     int argc;
85     pid_t pid;
86     int i, inpipe[2], outpipe[2], errpipe[2], passwdpipe[2];
87     char number[NUM_STR_SIZE];
88     char **arg;
89     char *e;
90     char **env;
91     char *cmdline;
92     char *quoted;
93     char **newenv;
94     char *passwdvar = NULL;
95     int  *passwdfd = NULL;
96
97     /*
98      * Log the command line and count the args.
99      */
100     if ((pipedef & PASSWD_PIPE) != 0) {
101         passwdvar = *my_argv++;
102         passwdfd  = (int *)*my_argv++;
103     }
104     memset(inpipe, -1, SIZEOF(inpipe));
105     memset(outpipe, -1, SIZEOF(outpipe));
106     memset(errpipe, -1, SIZEOF(errpipe));
107     memset(passwdpipe, -1, SIZEOF(passwdpipe));
108     argc = 0;
109
110     cmdline = stralloc(prog);
111     for(arg = my_argv; *arg != NULL; arg++) {
112         if (*arg != skip_argument) {
113             argc++;
114             quoted = quote_string(*arg);
115             cmdline = vstrextend(&cmdline, " ", quoted, NULL);
116             amfree(quoted);
117         }
118     }
119     dbprintf(_("Spawning \"%s\" in pipeline\n"), cmdline);
120
121     /*
122      * Create the pipes
123      */
124     if ((pipedef & STDIN_PIPE) != 0) {
125         if(pipe(inpipe) == -1) {
126             error(_("error [open pipe to %s: %s]"), prog, strerror(errno));
127             /*NOTREACHED*/
128         }
129     }
130     if ((pipedef & STDOUT_PIPE) != 0) {
131         if(pipe(outpipe) == -1) {
132             error(_("error [open pipe to %s: %s]"), prog, strerror(errno));
133             /*NOTREACHED*/
134         }
135     }
136     if ((pipedef & STDERR_PIPE) != 0) {
137         if(pipe(errpipe) == -1) {
138             error(_("error [open pipe to %s: %s]"), prog, strerror(errno));
139             /*NOTREACHED*/
140         }
141     }
142     if ((pipedef & PASSWD_PIPE) != 0) {
143         if(pipe(passwdpipe) == -1) {
144             error(_("error [open pipe to %s: %s]"), prog, strerror(errno));
145             /*NOTREACHED*/
146         }
147     }
148
149     /*
150      * Fork and set up the return or run the program.
151      */
152     switch(pid = fork()) {
153     case -1:
154         e = strerror(errno);
155         error(_("error [fork %s: %s]"), prog, e);
156         /*NOTREACHED*/
157
158     default:    /* parent process */
159         if ((pipedef & STDIN_PIPE) != 0) {
160             aclose(inpipe[0]);          /* close input side of pipe */
161             *stdinfd = inpipe[1];
162         }
163         if ((pipedef & STDOUT_PIPE) != 0) {
164             aclose(outpipe[1]);         /* close output side of pipe */
165             *stdoutfd = outpipe[0];
166         }
167         if ((pipedef & STDERR_PIPE) != 0) {
168             aclose(errpipe[1]);         /* close output side of pipe */
169             *stderrfd = errpipe[0];
170         }
171         if ((pipedef & PASSWD_PIPE) != 0) {
172             aclose(passwdpipe[0]);      /* close input side of pipe */
173             *passwdfd = passwdpipe[1];
174         }
175         break;
176     case 0:             /* child process */
177         debug_dup_stderr_to_debug();
178         if ((pipedef & STDIN_PIPE) != 0) {
179             aclose(inpipe[1]);          /* close output side of pipe */
180         } else {
181             inpipe[0] = *stdinfd;
182         }
183         if ((pipedef & STDOUT_PIPE) != 0) {
184             aclose(outpipe[0]);         /* close input side of pipe */
185         } else {
186             outpipe[1] = *stdoutfd;
187         }
188         if ((pipedef & STDERR_PIPE) != 0) {
189             aclose(errpipe[0]);         /* close input side of pipe */
190         } else {
191             errpipe[1] = *stderrfd;
192         }
193         if ((pipedef & PASSWD_PIPE) != 0) { 
194             aclose(passwdpipe[1]);      /* close output side of pipe */
195         }
196
197         /*
198          * Shift the pipes to the standard file descriptors as requested.
199          */
200         if(dup2(inpipe[0], 0) == -1) {
201             g_fprintf(stderr, "error [spawn %s: dup2 in: %s]", prog, strerror(errno));
202             exit(1);
203             /*NOTREACHED*/
204         }
205         if(dup2(outpipe[1], 1) == -1) {
206             g_fprintf(stderr, "error [spawn %s: dup2 out: %s]", prog, strerror(errno));
207             exit(1);
208             /*NOTREACHED*/
209         }
210         if(dup2(errpipe[1], 2) == -1) {
211             g_fprintf(stderr, "error [spawn %s: dup2 err: %s]", prog, strerror(errno));
212             exit(1);
213             /*NOTREACHED*/
214         }
215
216         /*
217          * Get the "safe" environment.  If we are sending a password to
218          * the child via a pipe, add the environment variable for that.
219          */
220         env = safe_env();
221         if ((pipedef & PASSWD_PIPE) != 0) {
222             for (i = 0; env[i] != NULL; i++)
223                 (void)i; /* make lint happy and do nothing */   
224             newenv = (char **)alloc((i + 1 + 1) * SIZEOF(*newenv));
225             g_snprintf(number, SIZEOF(number), "%d", passwdpipe[0]);
226             newenv[0] = vstralloc(passwdvar, "=", number, NULL);
227             for(i = 0; env[i] != NULL; i++)
228                 newenv[i + 1] = env[i];
229             newenv[i + 1] = NULL;
230             amfree(env);
231             env = newenv;
232             safe_fd(passwdpipe[0], 1);
233         } else {
234             safe_fd(-1, 0);
235         }
236
237         if (need_root) {
238             become_root();
239         } else {
240             /* if our real userid is zero, the child shouldn't inherit
241              * that, so drop privs permanently */
242             if (getuid() == 0 && !set_root_privs(-1)) {
243                 error(_("could not drop root privileges"));
244             }
245         }
246
247         execve(prog, my_argv, env);
248         e = strerror(errno);
249         error(_("error [exec %s: %s]"), prog, e);
250         /*NOTREACHED*/
251     }
252     amfree(cmdline);
253     return pid;
254 }