1 /*
2 ** Copyright 2001-2006 Double Precision, Inc.  See COPYING for
3 ** distribution information.
4 */
5 
6 static const char rcsid[]="$Id: fork.c,v 1.3 2006/05/28 15:29:52 mrsam Exp $";
7 
8 #include	"config.h"
9 #include	<stdio.h>
10 #include	<stdlib.h>
11 #include	<string.h>
12 #include	<unistd.h>
13 #include	<signal.h>
14 #include	<errno.h>
15 #include	<sys/types.h>
16 #include	<sys/stat.h>
17 #include	<sys/time.h>
18 #if HAVE_SYS_WAIT_H
19 #include	<sys/wait.h>
20 #endif
21 #ifndef WEXITSTATUS
22 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
23 #endif
24 #ifndef WIFEXITED
25 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
26 #endif
27 
28 #include	"gpg.h"
29 #include	"gpglib.h"
30 
31 extern int libmail_gpg_stdin, libmail_gpg_stdout, libmail_gpg_stderr;
32 extern pid_t libmail_gpg_pid;
33 
34 
35 /*
36 ** Helper function: for and run pgp, with the given file descriptors and
37 ** options.
38 */
39 
libmail_gpg_fork(int * libmail_gpg_stdin,int * libmail_gpg_stdout,int * libmail_gpg_stderr,const char * gpgdir,char ** argvec)40 pid_t libmail_gpg_fork(int *libmail_gpg_stdin, int *libmail_gpg_stdout,
41 		       int *libmail_gpg_stderr,
42 		       const char *gpgdir,
43 		       char **argvec)
44 {
45 	int pipein[2], pipeout[2], pipeerr[2];
46 	pid_t p;
47 	char *s;
48 
49 	if (libmail_gpg_stdin && pipe(pipein) < 0)
50 		return (-1);
51 
52 	if (libmail_gpg_stdout && pipe(pipeout) < 0)
53 	{
54 		if (libmail_gpg_stdin)
55 		{
56 			close(pipein[0]);
57 			close(pipein[1]);
58 		}
59 		return (-1);
60 	}
61 
62 	if (libmail_gpg_stderr && pipe(pipeerr) < 0)
63 	{
64 		if (libmail_gpg_stdout)
65 		{
66 			close(pipeout[0]);
67 			close(pipeout[1]);
68 		}
69 
70 		if (libmail_gpg_stdin)
71 		{
72 			close(pipein[0]);
73 			close(pipein[1]);
74 		}
75 		return (-1);
76 	}
77 
78 	signal(SIGCHLD, SIG_DFL);
79 	p=libmail_gpg_pid=fork();
80 	if (p < 0)
81 	{
82 		if (libmail_gpg_stderr)
83 		{
84 			close(pipeerr[0]);
85 			close(pipeerr[1]);
86 		}
87 
88 		if (libmail_gpg_stdout)
89 		{
90 			close(pipeout[0]);
91 			close(pipeout[1]);
92 		}
93 		if (libmail_gpg_stdin)
94 		{
95 			close(pipein[0]);
96 			close(pipein[1]);
97 		}
98 
99 		return (-1);
100 	}
101 
102 	if (p)
103 	{
104 		signal(SIGPIPE, SIG_IGN);
105 
106 		if (libmail_gpg_stderr)
107 		{
108 			close(pipeerr[1]);
109 			*libmail_gpg_stderr=pipeerr[0];
110 		}
111 
112 		if (libmail_gpg_stdout)
113 		{
114 			close(pipeout[1]);
115 			*libmail_gpg_stdout=pipeout[0];
116 		}
117 
118 		if (libmail_gpg_stdin)
119 		{
120 			close(pipein[0]);
121 			*libmail_gpg_stdin=pipein[1];
122 		}
123 		return (0);
124 	}
125 
126 	if (libmail_gpg_stderr)
127 	{
128 		dup2(pipeerr[1], 2);
129 		close(pipeerr[0]);
130 		close(pipeerr[1]);
131 	}
132 	else if (libmail_gpg_stdout)
133 	{
134 		dup2(pipeout[1], 2);
135 	}
136 
137 	if (libmail_gpg_stdout)
138 	{
139 		dup2(pipeout[1], 1);
140 		close(pipeout[0]);
141 		close(pipeout[1]);
142 	}
143 
144 	if (libmail_gpg_stdin)
145 	{
146 		dup2(pipein[0], 0);
147 		close(pipein[0]);
148 		close(pipein[1]);
149 	}
150 
151 	if (gpgdir)
152 	{
153 		s=malloc(sizeof("GNUPGHOME=")+strlen(gpgdir));
154 		if (!s)
155 		{
156 			perror("malloc");
157 			exit(1);
158 		}
159 		strcat(strcpy(s, "GNUPGHOME="), gpgdir);
160 		if (putenv(s) < 0)
161 		{
162 			perror("putenv");
163 			exit(1);
164 		}
165 	}
166 
167 	{
168 		const char *gpg=getenv("GPG");
169 		if (!gpg || !*gpg)
170 			gpg=GPG;
171 
172 		execv(gpg, argvec);
173 		perror(gpg);
174 	}
175 	_exit(1);
176 	return (0);
177 }
178 
libmail_gpg_write(const char * p,size_t cnt,int (* stdout_func)(const char *,size_t,void *),int (* stderr_func)(const char *,size_t,void *),int (* timeout_func)(void *),unsigned timeout,void * voidarg)179 int libmail_gpg_write(const char *p, size_t cnt,
180 		      int (*stdout_func)(const char *, size_t, void *),
181 		      int (*stderr_func)(const char *, size_t, void *),
182 		      int (*timeout_func)(void *),
183 		      unsigned timeout,
184 		      void *voidarg)
185 {
186 	char buf[BUFSIZ];
187 
188 	fd_set fdr, fdw;
189 	struct timeval tv;
190 
191 	if (!timeout_func)
192 		timeout=0;
193 	while (cnt)
194 	{
195 		int maxfd=0;
196 		int n;
197 
198 		FD_ZERO(&fdr);
199 		FD_ZERO(&fdw);
200 
201 		FD_SET(libmail_gpg_stdin, &fdw);
202 
203 		if (libmail_gpg_stdout >= 0)
204 		{
205 			FD_SET(libmail_gpg_stdout, &fdr);
206 			if (libmail_gpg_stdout > maxfd)
207 				maxfd=libmail_gpg_stdout;
208 		}
209 
210 		if (libmail_gpg_stderr >= 0)
211 		{
212 			FD_SET(libmail_gpg_stderr, &fdr);
213 			if (libmail_gpg_stderr > maxfd)
214 				maxfd=libmail_gpg_stderr;
215 		}
216 
217 		tv.tv_usec=0;
218 		tv.tv_sec=timeout;
219 		n=select(maxfd+1, &fdr, &fdw, NULL, timeout ? &tv:NULL);
220 		if (n == 0)
221 		{
222 			n=(*timeout_func)(voidarg);
223 			if (n)
224 				return(n);
225 			continue;
226 		}
227 		if (n < 0)
228 			continue;
229 
230 		if (FD_ISSET(libmail_gpg_stdin, &fdw))
231 		{
232 			int n=write(libmail_gpg_stdin, p, cnt);
233 
234 			if (n <= 0)
235 				return (-1);
236 
237 			p += n;
238 			cnt -= n;
239 		}
240 
241 		if (libmail_gpg_stdout >= 0 &&
242 		    FD_ISSET(libmail_gpg_stdout, &fdr))
243 		{
244 			int n=read(libmail_gpg_stdout, buf, sizeof(buf));
245 
246 			if (n <= 0)
247 			{
248 				close(libmail_gpg_stdout);
249 				libmail_gpg_stdout= -1;
250 			}
251 			else if (stdout_func &&
252 				 (n=(*stdout_func)(buf, n, voidarg)) != 0)
253 				return (n);
254 		}
255 
256 		if (libmail_gpg_stderr >= 0 &&
257 		    FD_ISSET(libmail_gpg_stderr, &fdr))
258 		{
259 			int n=read(libmail_gpg_stderr, buf, sizeof(buf));
260 
261 			if (n <= 0)
262 			{
263 				close(libmail_gpg_stderr);
264 				libmail_gpg_stderr= -1;
265 			}
266 			else if (stderr_func &&
267 				 (n=(*stderr_func)(buf, n, voidarg)) != 0)
268 				return (n);
269 		}
270 	}
271 	return (0);
272 }
273 
libmail_gpg_read(int (* stdout_func)(const char *,size_t,void *),int (* stderr_func)(const char *,size_t,void *),int (* timeout_func)(void *),unsigned timeout,void * voidarg)274 int libmail_gpg_read(int (*stdout_func)(const char *, size_t, void *),
275 		     int (*stderr_func)(const char *, size_t, void *),
276 		     int (*timeout_func)(void *),
277 		     unsigned timeout,
278 		     void *voidarg)
279 {
280 	char buf[BUFSIZ];
281 
282 	fd_set fdr;
283 	struct timeval tv;
284 
285 	if (libmail_gpg_stdin >= 0)
286 	{
287 		close(libmail_gpg_stdin);
288 		libmail_gpg_stdin= -1;
289 	}
290 
291 	if (!timeout_func)
292 		timeout=0;
293 
294 	while ( libmail_gpg_stdout >= 0 || libmail_gpg_stderr >= 0)
295 	{
296 		int maxfd=0;
297 		int n;
298 
299 		FD_ZERO(&fdr);
300 
301 		if (libmail_gpg_stdout >= 0)
302 		{
303 			FD_SET(libmail_gpg_stdout, &fdr);
304 			if (libmail_gpg_stdout > maxfd)
305 				maxfd=libmail_gpg_stdout;
306 		}
307 
308 		if (libmail_gpg_stderr >= 0)
309 		{
310 			FD_SET(libmail_gpg_stderr, &fdr);
311 			if (libmail_gpg_stderr > maxfd)
312 				maxfd=libmail_gpg_stderr;
313 		}
314 
315 		tv.tv_usec=0;
316 		tv.tv_sec=timeout;
317 		n=select(maxfd+1, &fdr, NULL, NULL, timeout ? &tv:NULL);
318 
319 		if (n == 0)
320 		{
321 			n=(*timeout_func)(voidarg);
322 			if (n)
323 				return(n);
324 			continue;
325 		}
326 		if (n < 0)
327 			continue;
328 
329 		if (libmail_gpg_stdout >= 0 &&
330 		    FD_ISSET(libmail_gpg_stdout, &fdr))
331 		{
332 			int n=read(libmail_gpg_stdout, buf, sizeof(buf));
333 
334 			if (n <= 0)
335 			{
336 				close(libmail_gpg_stdout);
337 				libmail_gpg_stdout= -1;
338 			}
339 			else if (stdout_func &&
340 				 (n=(*stdout_func)(buf, n, voidarg)) != 0)
341 				return (n);
342 		}
343 
344 		if (libmail_gpg_stderr >= 0 &&
345 		    FD_ISSET(libmail_gpg_stderr, &fdr))
346 		{
347 			int n=read(libmail_gpg_stderr, buf, sizeof(buf));
348 
349 			if (n <= 0)
350 			{
351 				close(libmail_gpg_stderr);
352 				libmail_gpg_stderr= -1;
353 			}
354 			else if (stderr_func &&
355 				 (n=(*stderr_func)(buf, n, voidarg)) != 0)
356 				return (n);
357 		}
358 	}
359 	return (0);
360 }
361